【opencv】图像基本操作
一.计算机眼中的图像
1.1 图像读取
cv2.IMREAD_COLOR:彩色图像
cv2.IMREAD_GRAYSCCALE:灰色图像
①导包
import cv2 # opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
②读取图像
img = cv2.imread("we.jpg")
可以指定读彩色图还是灰度图
③显示图像
语法:cv2.imshow(window_name, image)
-
window_name
:这是一个字符串,用来标识显示图像的窗口名称。你可以用不同的名字创建多个窗口。 -
image
:这是你想要显示的图像。通常这是一个读取到的图像文件(使用cv2.imread
),也可以是经过处理后的图像。
当你调用 cv2.imshow
来显示图像时,通常需要紧接着调用 cv2.waitKey([delay])
函数来等待按键事件。参数 delay
是以毫秒为单位的等待时间。如果 delay
参数被设置为0,则表示无限期地等待键盘输入。
# 图像的显示,也可以创建多个窗口
cv2.imshow("we",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
③保存图像
cv2.imwrite("gray_we.jpg",img)
第一个参数是图像保存的名字
第二个参数是图像
保存成功会返回True
1.2 视频读取
cv2.VideoCapture可以捕获摄像头,用数字来控制不同的设备,如0,1
如果是视频文件,直接指定好路径即可
①读取视频
vc = cv2.VideoCapture("test.mp4")
②判断视频是否正常打开
# 检查是否打开正确
if vc.isOpened():open,frame = vc.read()
else:open = False
③读取视频
while open:ret, frame = vc.read()if frame is None:breakif ret == True:gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)cv2.imshow("result",gray)if cv2.waitKey(10) & 0xFF == 27:break
vc.release()
cv2.destroyAllWindows()
这段代码展示了一个基本的视频处理循环,它从视频捕获对象(`vc`)中逐帧读取数据,并将每一帧转换为灰度图像显示在窗口中,直到用户按下ESC键(其ASCII码为27)或视频结束。下面是对这段代码的详细解释:
1. `while open:`
- 这个循环会持续执行,只要 `open` 变量为 `True`。`open` 代表视频流是否成功打开并准备好。
2. `ret, frame = vc.read()`
- 使用 `vc.read()` 方法从视频流中读取下一帧。
- `ret` 是一个布尔值,表示是否成功读取了帧。如果读取成功,`ret` 为 `True`;否则为 `False`。
- `frame` 是读取到的当前帧图像,通常是一个三维数组(对于彩色图像),包含该帧的像素数据。
3. `if frame is None: break`
- 检查 `frame` 是否为 `None`。如果是,这意味着没有更多帧可供读取(例如到达视频文件末尾),此时跳出循环。
4. `if ret == True:`
- 如果帧成功读取,则继续处理。这个条件检查是为了确保只有当有有效的帧被读取时才进行处理。
5. `gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)`
- 将读取到的彩色帧转换为灰度图像。这一步骤通过减少颜色信息来简化图像,有利于某些类型的图像处理和分析任务。
6. `cv2.imshow("result", gray)`
- 在名为 "result" 的窗口中显示灰度图像。如果你之前没有创建过名为 "result" 的窗口,`cv2.imshow` 会自动创建一个。
7. `if cv2.waitKey(10) & 0xFF == 27: break`
- 等待按键事件。`cv2.waitKey(10)` 函数会暂停程序10毫秒等待按键输入。如果在这段时间内按下了ESC键(其ASCII码为27),则跳出循环终止程序。
8. `vc.release()` 和 `cv2.destroyAllWindows()`
- `vc.release()`:释放视频捕获对象所占用的资源。
- `cv2.destroyAllWindows()`:关闭所有由 OpenCV 创建的窗口。
这段代码是实时视频处理的一个简单示例,展示了如何从摄像头或者视频文件中读取视频流、对每一帧进行处理,并在窗口中显示结果。此外,还演示了如何通过键盘输入退出循环,停止视频处理。
1.3 ROI区域
①截取部分图像数据
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyAllWindows()
img = cv2.imread("we.jpg")
we = img[400:1000,400:750]
cv_show("we",we)
②颜色通道提取
b,g,r = cv2.split(we)
通道合并
we = cv2.merge((b,g,r))
③只保留某通道
只保留R通道,按照B/G/R,将前两个通道置零即可
cur_img = we.copy()
cur_img[:,:,0] = 0
cur_img[:,:,1] = 0
cv_show("R",cur_img)
只保留B通道:
cur_img = we.copy()
cur_img[:,:,1] = 0
cur_img[:,:,2] = 0
cv_show("B",cur_img)
只保留G通道:
cur_img = we.copy()
cur_img[:,:,0] = 0
cur_img[:,:,2] = 0
cv_show("G",cur_img)
1.4 边界填充
函数原型copyMakeBorder:
cv2.copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]]) -> dst
-
src
: 输入图像。 -
top
,bottom
,left
,right
: 分别表示在原图的顶部、底部、左侧、右侧添加的边框宽度(像素数)。 -
borderType
: 定义了边框类型。OpenCV 提供了几种不同的边框类型:-
cv2.BORDER_CONSTANT
: 添加固定值颜色的边框,需要同时提供value
参数指定边框的颜色。 -
cv2.BORDER_REFLECT
: 边框元素是边框对应的镜像,比如:fedcba|abcdefgh|hgfedcb。 -
cv2.BORDER_REFLECT_101
或cv2.BORDER_DEFAULT
: 和上面类似,但不复制最后一个像素,例如:gfedcb|abcdefgh|gfedcba。 -
cv2.BORDER_REPLICATE
: 最后一个像素进行复制扩展,例如:aaaaaa|abcdefgh|hhhhhhh。 -
cv2.BORDER_WRAP
: 另一种镜像方式,不过与BORDER_REFLECT
不同,它更像是将图像首尾相连。
-
-
dst
: 输出图像,可选参数。 -
value
: 当borderType
为cv2.BORDER_CONSTANT
时使用的边框颜色,对于多通道图像,每个通道都需要指定一个值。
top_size,bottom_size,left_size,right_size = (50,50,50,50)replicate = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_CONSTANT,value=0)
import matplotlib.pyplot as plt
plt.subplot(231),plt.imshow(img),plt.title("Original")
plt.subplot(232),plt.imshow(replicate),plt.title("Replicate")
plt.subplot(233),plt.imshow(reflect),plt.title("Reflect")
plt.subplot(234),plt.imshow(reflect101),plt.title("Reflect101")
plt.subplot(235),plt.imshow(wrap),plt.title("Wrap")
plt.subplot(236),plt.imshow(constant),plt.title("Constant")
1.5 数值计算
①加法:
②图像融合
当两张图片大小不同时,不能直接融合
可以resize:
也可以用倍数resize:
fx和fy就是倍数
③使用cv2.addWeighted进行融合
基本语法:
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
参数解释:
-
src1
: 第一个原数组(在这里是li
)。 -
alpha
: 第一个数组的权重。 -
src2
: 第二个原数组(在这里是xia
)。 -
beta
: 第二个数组的权重。 -
gamma
: 图像叠加时添加的标量值,通常设为0。 -
dst
: 可选参数,输出数组,与src1
形状和类型相同。 -
dtype
: 输出数组的可选深度,若未指定,则使用输入数组的深度。
li = cv2.resize(li,(1080,1920))
res = cv2.addWeighted(li,0.4,xia,0.6,0)
plt.imshow(res)
二、阈值与平滑操作
2.1 图像阈值
函数原型:
ret, thresh = cv2.threshold(src, thresh, maxval, type)
参数解释:
-
src
: 输入图像,应为灰度图。 -
thresh
: 设定的阈值,用于与图像中的每一个像素值进行比较。 -
maxval
: 当某像素值超过(或小于,取决于所使用的阈值类型)阈值时,该像素被赋予的新值。 -
type
: 阈值处理的类型,决定了如何应用阈值。OpenCV 提供了几种不同的阈值方法:-
cv2.THRESH_BINARY
: 二进制阈值化。大于阈值的像素值设置为maxval
,其余设置为 0。 -
cv2.THRESH_BINARY_INV
: 反二进制阈值化。大于阈值的像素值设置为 0,其余设置为maxval
。 -
cv2.THRESH_TRUNC
: 截断。大于阈值的像素值设置为阈值本身,其余不变。 -
cv2.THRESH_TOZERO
: 将小于阈值的像素值设置为 0,其余不变。 -
cv2.THRESH_TOZERO_INV
: 反向为零。大于阈值的像素值设置为 0,其余不变。 -
cv2.THRESH_OTSU
: 使用 Otsu's 方法自动计算最佳阈值。此模式下,thresh
参数会被忽略,且函数返回的最佳阈值会作为第一个返回值。
-
-
ret
: 返回的最佳阈值(仅当使用了如cv2.THRESH_OTSU
或cv2.THRESH_TRIANGLE
等自动确定阈值的方法时有意义)。 -
thresh
: 输出图像,其数据类型与输入图像相同。
ret, thresh1 = cv2.threshold(li,127,255,cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(li,127,255,cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(li,127,255,cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(li,127,255,cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(li,127,255,cv2.THRESH_TOZERO_INV)titles = ["Original","binary","binary_inv","trunc","tozero","tozero_inv"]
images = [li,thresh1,thresh2,thresh3,thresh4,thresh5]for i in range(6):plt.subplot(2,3,i+1)plt.imshow(images[i],"gray")plt.title(titles[i])plt.xticks([])plt.yticks([])
plt.show()
2.2 图像平滑处理
①读取图像
li = cv2.imread("li.jpg")
li = li[400:1000,300:1300,:]cv2.imshow("li",li)
cv2.waitKey(0)
cv2.destroyAllWindows()
②均值滤波
均值滤波(Mean Filtering)是一种简单的线性滤波技术,常用于图像处理中以减少噪声。它通过将每个像素点的值替换为其某个邻域内所有像素值的平均值来平滑图像。这种方法对于去除高斯噪声或均匀分布的随机噪声特别有效,但同时也会模糊图像中的边缘和其他锐利特征。
均值滤波的工作原理
-
定义一个卷积核(Kernel):通常是一个正方形矩阵,如3x3、5x5等。这个卷积核决定了要对当前像素及其周围哪些像素进行平均操作。卷积核的大小直接影响到滤波的效果和计算复杂度。
-
遍历图像的每一个像素:对于图像中的每一个像素,计算其与卷积核覆盖的所有像素值的平均值。这个过程涉及到将卷积核中心放置在目标像素上,并考虑卷积核下的所有像素值。
-
计算平均值并更新像素值:将这些像素值相加后除以卷积核内的像素总数,得到的结果即为该位置的新像素值。这样做的结果是,原始图像中的每个像素都被其邻域内像素的平均值所替代,从而实现图像的平滑效果。
-
边界处理:当卷积核的一部分超出了图像边界时,需要决定如何处理这种情况。常见的方法包括填充边界(例如使用最近的像素值、固定值如0,或者镜像复制)、忽略超出部分仅考虑位于图像内的像素,等等。
# 均值滤波
blur = cv2.blur(li,(3,3))cv2.imshow("blur",blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
③方框滤波
函数原型:
dst = cv2.boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]])
参数解释:
-
src
: 输入图像;即需要进行滤波处理的原始图像。该图像通常是一个单通道或多通道的灰度或彩色图像。对于多通道图像,每个通道独立处理。 -
ddepth
: 输出图像的深度。使用-1
表示输出图像与输入图像具有相同的深度。你可以根据需要指定其他深度类型,如cv2.CV_8U
,cv2.CV_16U
,cv2.CV_32F
等。 -
ksize
: 滤波器(卷积核)的大小,以元组(width, height)
形式给出。例如,(5, 5)
表示一个 5x5 的滤波器。较大的滤波器尺寸会导致更强的模糊效果。 -
dst
(可选): 输出图像。如果提供,则其大小和类型必须正确。如果不提供,则函数内部会创建一个符合要求的输出图像。 -
anchor
(可选): 锚点的位置,默认值为(-1, -1)
,表示锚点位于卷积核的中心。这个参数允许你指定卷积核相对于目标像素位置的偏移量。 -
normalize
(可选): 一个布尔值,默认为True
。如果设置为True
,则结果会被归一化(即除以卷积核内的元素数量)。如果设置为False
,则不对结果进行归一化处理,这意味着直接对覆盖区域的像素值求和。 -
borderType
(可选): 边界填充类型,决定了如何处理图像边界。常用的选项包括:cv2.BORDER_CONSTANT
: 使用固定值填充边界。cv2.BORDER_REPLICATE
: 复制边缘像素填充边界。cv2.BORDER_REFLECT
: 反射法填充边界。cv2.BORDER_WRAP
: 包裹法填充边界。
默认情况下,OpenCV 使用的是
cv2.BORDER_DEFAULT
,这通常是cv2.BORDER_REFLECT_101
,即反射法但不复制最后一个像素。
# 方框滤波
box = cv2.boxFilter(li,-1,(3,3),normalize=True)cv2.imshow("box",box)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 方框滤波
box = cv2.boxFilter(li,-1,(3,3),normalize=False)cv2.imshow("box",box)
cv2.waitKey(0)
cv2.destroyAllWindows()
注1:设置normalize=False
这样做的结果是直接对覆盖区域的像素值求和,而不进行平均处理,可能会导致输出图像的像素值超出原始范围。因此,在大多数情况下,默认的归一化行为更常用。
注2:
cv2.blur()
和 cv2.boxFilter()
都是 OpenCV 中用于实现均值滤波(即方框滤波,Box Filtering)的方法。它们的主要目的是通过对图像中的每个像素及其邻域内的像素值求平均来平滑图像,从而减少噪声。这两个函数的目标相同,仅在某些细节和使用方式上存在差异。
④高斯滤波
高斯滤波(Gaussian Filtering)是一种常用的图像处理技术,主要用于平滑图像、减少噪声。与均值滤波不同,高斯滤波在计算像素的新值时,并不是简单地取邻域内所有像素的平均值,而是根据每个邻域像素到中心像素的距离赋予不同的权重。距离中心越近的像素具有越高的权重,这种权重分布遵循高斯分布(正态分布)。因此,高斯滤波能够更自然地平滑图像,同时较好地保持边缘信息。
函数原型:
dst = cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])
参数解释:
-
src
: 输入图像;即需要进行高斯模糊处理的原始图像。支持单通道或多通道图像。每个通道独立处理。 -
ksize
: 高斯核大小,格式为(width, height)
,宽度和高度都应该是正奇数(例如(5, 5)
)。较大的核尺寸会导致更强的模糊效果。如果两个维度值相同,则只需指定一个值,如(5, 5)
可以简写为5
。如果设置为(0, 0)
,则根据sigmaX
自动计算核大小。 -
sigmaX
: X方向上的高斯核标准差。控制高斯分布的宽度。较高的值会产生更广泛的模糊。如果设为0,将根据ksize
自动计算合适的值。
# 高斯滤波
gaussian = cv2.GaussianBlur(li,(5,5),1)cv2.imshow("gaussian",gaussian)
cv2.waitKey(0)
cv2.destroyAllWindows()
⑤中值滤波
中值滤波(Median Filtering)是一种非线性的图像处理技术,主要用于减少噪声,特别是所谓的“椒盐噪声”(Salt-and-pepper noise),即随机出现在图像中的黑白点。与均值滤波或高斯滤波不同,中值滤波不是基于像素值的加权平均,而是通过计算每个像素邻域内所有像素值的中位数来替换该像素值。这种方法能够有效地去除噪声同时较好地保留边缘信息。
# 中值滤波
median = cv2.medianBlur(li,5)cv2.imshow("median",median)
cv2.waitKey(0)
cv2.destroyAllWindows()
展示所有:
# 展示所有
res = np.vstack((blur,gaussian,median))cv2.imshow("median guassian blur",res)
cv2.waitKey(0)
cv2.destroyAllWindows()
三、图像形态学操作
3.1 腐蚀操作
例一:
img = cv2.imread("yizhou.png")cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
腐蚀是一种形态学操作,通常用于移除图像中的噪声或使对象变得更小。
腐蚀操作:
cv2.erode(img, kernel, iterations=2)
函数对图像 img
应用腐蚀操作。腐蚀操作通过滑动结构元素遍历整个图像,并将当前像素值替换为其邻域内最小的像素值(对于二值图像而言,就是判断邻域内是否全部为前景像素,只有当邻域完全覆盖前景时,中心像素才保持不变)。iterations=2
表示该操作重复执行两次,每次操作都会进一步侵蚀图像中的前景区域。
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(img,kernel,iterations=2)cv2.imshow("erosion",erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
例二:
pie = cv2.imread("pen.png")cv2.imshow("pie",pie)
cv2.waitKey(0)
cv2.destroyAllWindows()
执行腐蚀槽值:
kernel = np.ones((30,30),np.uint8)erosion1 = cv2.erode(pie,kernel,iterations=1)
erosion2 = cv2.erode(pie,kernel,iterations=2)
erosion3 = cv2.erode(pie,kernel,iterations=3)erosion = np.hstack((erosion1,erosion2,erosion3))
cv2.imshow("erosion",erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.2 膨胀操作
例一:
当我们把“以昼”腐蚀掉以后,虽然去除了噪音,但是字变细了。膨胀操作就是一个反操作。
yizhou = cv2.imread("yizhou.png")kernel = np.ones((5,5),np.uint8)yz = cv2.erode(yizhou,kernel,iterations = 2)
yz = cv2.dilate(yz,kernel,iterations = 2)cv2.imshow("yz",yz)
cv2.waitKey(0)
cv2.destroyAllWindows()
例二:
pie = cv2.imread("pie.png")kernel = np.ones((30,30),np.uint8)
dilate1 = cv2.dilate(pie,kernel,iterations=1)
dilate2 = cv2.dilate(pie,kernel,iterations=2)
dilate3 = cv2.dilate(pie,kernel,iterations=3)dilate = np.hstack((dilate1,dilate2,dilate3))
cv2.imshow("dilate",dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.3 开运算与闭运算
开运算:先腐蚀,再膨胀
# 开:先腐蚀,再膨胀
img = cv2.imread("yizhou.png")kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel,iterations=2)cv2.imshow("opening",opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
闭运算:先膨胀,再腐蚀
# 闭:先膨胀,再腐蚀
img = cv2.imread("yizhou.png")kernel = np.ones((5,5),np.uint8)
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel,iterations=2)cv2.imshow("closing",closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.4 梯度运算
梯度运算 = 膨胀图像 - 腐蚀图像
膨胀图像和腐蚀图像如下:
pie = cv2.imread("pie.png")kernel = np.ones((5,5),np.uint8)
# 膨胀图像
dilate = cv2.dilate(pie,kernel,iterations=5)
# 腐蚀图像
erosion = cv2.erode(pie,kernel,iterations=5)res = np.hstack((dilate,erosion))
cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows()
梯度操作如下:
pie = cv2.imread("pie.png")kernel = np.ones((5,5),np.uint8)
gradient = cv2.morphologyEx(pie,cv2.MORPH_GRADIENT,kernel,iterations=5)cv2.imshow("gradient",gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.5 礼帽和黑帽
礼帽 = 原始输入 - 开运算结果
黑帽 = 闭运算结果 - 原始输入
礼帽:留下刺的轮廓
# 礼帽
yizhou = cv2.imread("yizhou.png")kernel = np.ones((5,5),np.uint8)
tophat = cv2.morphologyEx(yizhou,cv2.MORPH_TOPHAT,kernel)cv2.imshow("tophat",tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()
黑帽:留下字的轮廓
# 黑帽
yizhou = cv2.imread("yizhou.png")kernel = np.ones((5,5),np.uint8)
blackhat = cv2.morphologyEx(yizhou,cv2.MORPH_BLACKHAT,kernel)cv2.imshow("blackhat",blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()
四、图像梯度运算
4.1 Sobel算子
Sobel算子计算方法:从右到左、从下到上
Sobel算子是一种常用的边缘检测算法,主要用于图像处理中识别图像中的边界或边缘。它通过计算图像的梯度来近似图像的导数,从而帮助确定图像中亮度发生急剧变化的位置,这些位置通常对应于物体的边界。
参数解释:
-
src
: 输入图像;即需要进行边缘检测的原始图像。通常为灰度图像。 -
ddepth
: 输出图像的深度。常见的选择有cv2.CV_64F
(64位浮点数),这允许表示负数梯度值,因为图像从亮到暗的变化会被视为负梯度。 -
dx
和dy
: 分别表示对X方向和Y方向求导的阶数。例如,为了计算X方向上的导数,设置dx=1
和dy=0
。 -
ksize
: Sobel算子使用的卷积核大小。必须是正奇数(如3、5、7等)。较大的尺寸可能会导致更平滑的结果,但也会丢失一些细节。
利用Sobel算子计算X方向上的导数
pie = cv2.imread("pie.png")sobelx = cv2.Sobel(pie,cv2.CV_64F,1,0,ksize=3)cv2.imshow("sobelx",sobelx)
cv2.waitKey(0)
cv2.destroyAllWindows()
利用Sobel算子计算Y方向上的导数:
pie = cv2.imread("pie.png")sobely = cv2.Sobel(pie,cv2.CV_64F,0,1,ksize=3)cv2.imshow("sobely",sobely)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.2 梯度计算方法
白到黑是正数,而黑到白是负数,负数会被截断,所以要取绝对值
使用cv2.convertScaleAbs()
x方向:
pie = cv2.imread("pie.png")sobelx = cv2.Sobel(pie,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)cv2.imshow("sobelx",sobelx)
cv2.waitKey(0)
cv2.destroyAllWindows()
y方向:
pie = cv2.imread("pie.png")sobely = cv2.Sobel(pie,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)cv2.imshow("sobely",sobely)
cv2.waitKey(0)
cv2.destroyAllWindows()
分别计算x和y(此时已转换为绝对值),再相加
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)cv2.imshow("sobelxy",sobelxy)
cv2.waitKey(0)
cv2.destroyAllWindows()
不建议直接计算,效果不好
sobelxy = cv2.Sobel(pie,cv2.CV_64F,1,1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)cv2.imshow("sobelxy",sobelxy)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.2 scharr算子和laplacian算子
处理前:
0. 使用sobel算子
xyz = cv2.imread("xyz.jpg",cv2.IMREAD_GRAYSCALE)
xyz = xyz[300:1000,:]
# 使用sobel算子
sobelx = cv2.Sobel(xyz,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(xyz,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)cv2.imshow("xyz-sobel",sobelxy)
cv2.waitKey(0)
cv2.destroyAllWindows()
①shcarr算子
Scharr算子是Sobel算子的一种改进版本,专门设计用来更精确地估计图像的梯度,特别是在使用小尺寸(3x3)卷积核时。Scharr算子提供了对图像梯度方向更好的近似,减少了旋转不变性的误差。
提高精度:相比Sobel算子,Scharr算子在计算图像梯度时能提供更高的准确性,尤其是在使用3x3大小的卷积核时。
# 使用scharr算子
scharrx = cv2.Scharr(xyz,cv2.CV_64F,1,0)
scharry = cv2.Scharr(xyz,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)cv2.imshow("xyz-scharr",scharrxy)
cv2.waitKey(0)
cv2.destroyAllWindows()
②laplacian算子
Laplacian算子是一种二阶导数算子,用于检测图像中的亮度急剧变化的位置,即边缘。它通过计算图像的拉普拉斯变换来工作,能够同时考虑X方向和Y方向的变化。
二阶导数:与Sobel和Scharr这些一阶导数算子不同,Laplacian算子基于二阶导数,可以突出显示图像中亮度变化最剧烈的区域。
# 适用laplacian算子
laplacian = cv2.Laplacian(xyz,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)cv2.imshow("xyz-laplacian",laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()
总结:
- Scharr算子:更适合于需要高精度梯度估计的应用场景,尤其是当使用小尺寸卷积核时。它提供了比Sobel算子更好的旋转不变性。
- Laplacian算子:基于二阶导数,适用于检测图像中的亮度急剧变化区域。虽然对噪声敏感,但它能有效地找出图像中的精细边缘。
五、边缘检测
5.1 Canny边缘检测流程
①使用高斯滤波器
②利用Sobel算子计算梯度
5.2 非极大值抑制
③非极大值抑制
非极大值抑制(Non-Maximum Suppression, NMS)是一种在计算机视觉任务中常用的技术,尤其是在目标检测算法中。NMS 的主要目的是消除冗余的边界框,保留最具有代表性的检测结果。这是因为目标检测算法通常会在同一个物体周围生成多个重叠的边界框,而非极大值抑制可以帮助选择出最准确的那个边界框,并去除其余的。
非极大值抑制的基本思想是对于每个检测到的目标类别,在所有预测的边界框中选出得分最高的那个边界框,然后移除与其重叠超过一定阈值的所有其他边界框。这个过程可以重复进行,直到所有的边界框都被处理完毕。
5.3 双阈值检测
-
阈值的选择 (
threshold1
,threshold2
):-
这些阈值的选择对结果有很大影响。一般建议
threshold2
设置为threshold1
的两到三倍。例如,可以选择threshold1=50
和threshold2=150
。较低的阈值会导致更多的边缘被检测出来,但也可能包括更多的噪声;较高的阈值则可能导致遗漏一些真实的边缘。
-
xyz = cv2.imread("xyz.jpg",cv2.IMREAD_GRAYSCALE)
xyz = xyz[300:1000,:]v1 = cv2.Canny(xyz,80,150)
v2 = cv2.Canny(xyz,50,100)cv2.imshow("v1",v1)
cv2.imshow("v2",v2)
cv2.waitKey(0)
cv2.destroyAllWindows()
六、金字塔与轮廓检测
6.1 图像金字塔
①高斯金字塔
6.2 金字塔制作方法
向上采样:
up = cv2.pyrUp(xyz)cv2.imshow("xyz-up",up)
cv2.waitKey(0)
cv2.destroyAllWindows()
向下采样:
down = cv2.pyrDown(xyz)cv2.imshow("xyz-down",down)
cv2.waitKey(0)
cv2.destroyAllWindows()
拉普拉斯金字塔:
down = cv2.pyrDown(xyz)
down_up = cv2.pyrUp(down)
laplacian = xyz - down_upcv2.imshow("xyz-laplacian",laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.3 轮廓检测方法
为了更高的准确率,使用二值图像
xyz = cv2.imread("xyz.jpg",cv2.IMREAD_GRAYSCALE)
xyz = xyz[300:1000,:]ret, thresh = cv2.threshold(xyz,127,255,cv2.THRESH_BINARY)cv2.imshow("thresh",thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
函数原型:
image, contours, hierarchy = cv2.findContours(image, mode, method)
-
image
: 输入图像,必须是二值图像(即黑白图像),非零像素被视为前景(通常是白色),零像素被视为背景(通常是黑色)。为了获得这样的图像,通常需要先对原始图像进行阈值处理或边缘检测。 -
mode
: 轮廓检索模式,决定了如何从图像中提取轮廓:-
cv2.RETR_EXTERNAL
: 只检索最外层的轮廓。 -
cv2.RETR_LIST
: 检索所有轮廓并将它们组织成一个列表,不建立层次关系。 -
cv2.RETR_CCOMP
: 检索所有轮廓并将它们组织成两级层次结构,第一级是外部边界,第二级是孔洞。 -
cv2.RETR_TREE
: 检索所有轮廓并重建完整的层次结构信息。
-
-
method
: 轮廓近似方法,决定了如何近似轮廓形状:-
cv2.CHAIN_APPROX_NONE
: 存储所有的轮廓点。任何两点间如果为水平、垂直或对角方向,则会包含中间点。 -
cv2.CHAIN_APPROX_SIMPLE
: 压缩水平、垂直和对角方向上的点,仅保留端点。例如,一条直线只需要两个点来表示。 -
cv2.CHAIN_APPROX_TC89_L1
,cv2.CHAIN_APPROX_TC89_KCOS
: 使用Teh-Chin链逼近算法的一种变体。
-
-
contours
(可选): 输出参数,保存找到的所有轮廓,每个轮廓是一个 Numpy 数组,包含轮廓点的坐标。 -
hierarchy
(可选): 输出参数,每条轮廓对应的信息向量,包含有关图像拓扑结构的信息(如父轮廓、子轮廓等)。 -
offset
(可选): 可选的偏移量,应用于所有轮廓点。这对于将轮廓移动到图像的不同部分很有用。
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)cv2.imshow("image",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.4 轮廓检测结果
draw_img = xyz.copy()# 参数列表:传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
res = cv2.drawContours(draw_img,contours,-1,(0,255,0),2)cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.5 轮廓特征与近似
①轮廓特征
②轮廓近似
img = cv2.imread("contours.png")gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]draw_img = img.copy()
res = cv2.drawContours(draw_img,[cnt],-1,(0,0,255),5)cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows()
也可以让轮廓不那么贴合:
epsilon = 0.05*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)draw_img = img.copy()
res = cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.6 模版匹配方法
模版匹配和卷积的原理类似,模板在原图像上从原点开始滑动,计算模板与图像被模板覆盖的地方的差别程度,共六种差别程度的计算方法。然后将每次计算的结果放入一个矩阵,作为结果输出。
假如原图是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
# 模板匹配
img = cv2.imread("xyz.jpg",0)
template = cv2.imread("xyz-face.png",0)
在OpenCV中,`cv2.matchTemplate()` 函数用于执行模板匹配,它允许你使用不同的方法来计算模板图像和目标图像之间的相似度。以下是 `cv2.matchTemplate()` 支持的几种匹配方法及其具体介绍:
1. cv2.TM_SQDIFF` (平方差匹配法)
- 这种方法通过计算模板图像与目标图像每个位置子区域之间的平方差之和来进行匹配。
- 匹配结果越小表示匹配度越高,即最小值代表最佳匹配。
2. cv2.TM_SQDIFF_NORMED` (归一化平方差匹配法)
- 该方法是对平方差匹配法的归一化版本,其结果范围通常在0到1之间。
- 归一化后的公式有助于比较不同大小的模板和图像之间的匹配程度。
- 同样,较小的值表示较好的匹配。
3. cv2.TM_CCORR` (相关匹配法)
- 相关匹配法通过计算模板图像与目标图像每个位置子区域之间的乘积之和来进行匹配。
- 值越大表示匹配度越高,但因为没有考虑均值偏移,所以对亮度变化敏感。
4. cv2.TM_CCORR_NORMED(归一化相关匹配法)
- 对相关匹配法的结果进行归一化处理,使得结果更容易解释,并且不受图像大小的影响。
- 结果范围通常在0到1之间,较大的值表示更好的匹配。
5. cv2.TM_CCOEFF` (系数匹配法)
- 系数匹配法首先将模板图像和目标图像每个位置的子区域减去各自的平均值,然后计算它们的乘积之和。
- 这种方法考虑了图像的整体亮度变化,因此对于光照变化具有一定的鲁棒性。
- 较大的值表示较好的匹配。
6. cv2.TM_CCOEFF_NORMED (归一化系数匹配法)**
- 对系数匹配法的结果进行归一化处理,使得结果更加稳定并且易于解释。
- 结果范围通常在-1到1之间,接近1的值表示最好的匹配。
res = cv2.matchTemplate(img,template,cv2.TM_SQDIFF)
6.7 模板匹配方法
①匹配单个对象
methods = {"cv2.TM_SQDIFF","cv2.TM_SQDIFF_NORMED","cv2.TM_CCORR","cv2.TM_CCORR_NORMED","cv2.TM_CCOEFF","cv2.TM_CCOEFF_NORMED"}
h,w = template.shape[:2]for meth in methods:img2 = img.copy()# 匹配方法的真值method = eval(meth)print(method)res = cv2.matchTemplate(img,template,method)min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(res)# 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED 取最小值if method in [cv2.TM_SQDIFF,cv2.TM_SQDIFF_NORMED]:top_left = min_locelse:top_left = max_locbottom_right = (top_left[0]+w,top_left[1]+h)# 画矩形cv2.rectangle(img2,top_left,bottom_right,(0,0,255),5)plt.subplot(121),plt.imshow(res,cmap="gray")plt.xticks([]),plt.yticks([])plt.subplot(122),plt.imshow(img2,cmap="gray")plt.xticks([]),plt.yticks([])plt.suptitle(meth)plt.show()
②匹配多个对象
img = cv2.imread("mario.png")
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
template = cv2.imread("mario-face.png",0)
h,w = template.shape[:2]res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于80%的坐标
loc = np.where(res>=threshold)
for pt in zip(*loc[::-1]):bottom_right = (pt[0]+w,pt[1]+h)cv2.rectangle(img,pt,bottom_right,(0,0,255),2)cv2.imshow("img",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
注:
-
loc[::-1]
首先反转了loc
元组中的元素顺序。因为loc
的格式是(y_positions, x_positions)
,所以loc[::-1]
将其变为(x_positions, y_positions)
,这更符合我们常规的(x, y)坐标表示法。 -
zip(*loc[::-1])
则将分离的x和y坐标的数组重新组合成一系列的(x, y)坐标对。每个坐标对代表了一个在原图中找到模板的位置。
七、直方图与傅里叶变换
7.1 直方图定义
img = cv2.imread("xyz.jpg",0)
hist = cv2.calcHist([img],[0],None,[256],[0,256])
img = cv2.imread("xyz.jpg")
color = ("b","g","r")for i,col in enumerate(color):histr = cv2.calcHist([img],[i],None,[256],[0,256])plt.plot(histr,color=col)plt.xlim([0,256])
7.2 均衡化原理
0.准备工作
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyAllWindows()
①创造掩码
img = cv2.imread("xyz.jpg")# 创建mask
mask = np.zeros(img.shape[:2],np.uint8)
mask[400:1000,500:1000] = 255
cv_show("mask",mask)
②执行与操作
masked_img = cv2.bitwise_and(img,img,mask=mask)
cv_show("masked_img",masked_img)
cv2.bitwise_and(img, img, mask=mask)
是 OpenCV 中用于执行按位与操作的一个函数调用,它结合了一个图像和一个掩码(mask),以提取或修改图像的特定部分。这种方法常用于图像处理任务中,比如在仅对图像的某些区域应用效果或分析时。
函数解释
-
cv2.bitwise_and(src1, src2[, dst[, mask]])
:-
src1
,src2
: 这是要进行按位与操作的两个源数组(在这里都是img
,意味着我们将同一个图像与自身进行按位与操作)。 -
dst
(可选): 输出数组,其大小和类型与输入数组相同。如果未提供,则函数内部会创建一个。 -
mask
(可选): 操作掩码,这是一个8位单通道数组,指定要更改的输出数组元素。只有掩码中非零像素位置的操作才会被计算并保存到目标图像中。
-
参数说明
-
img
: 输入图像,可以是灰度图像或彩色图像。 -
mask
: 掩码图像,必须是一个8位单通道图像(如灰度图像)。掩码中的每个像素值决定了对应位置上的原图像素是否会被包含在最终的结果中:-
如果掩码图像中某个位置的像素值为非零(通常为255,即白色),则该位置对应的原图像素将保留在结果图像中。
-
如果掩码图像中某个位置的像素值为零(即黑色),则该位置对应的原图像素将被设置为零(对于灰度图像)或(0,0,0)(对于彩色图像),即这些像素不会出现在结果图像中。
-
应用场景
这种技术特别适用于当你只想处理或分析图像的特定区域时。例如,如果你有一个圆形的兴趣区域(ROI),你可以创建一个同样大小的圆形掩码,并使用上述方法来“裁剪”出这个圆形区域内的图像部分。
③绘制对比
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])
④绘制图像
plt.subplot(221),plt.imshow(img,"gray")
plt.subplot(222),plt.imshow(mask,"gray")
plt.subplot(223),plt.imshow(masked_img,"gray")
plt.subplot(224),plt.plot(hist_full),plt.plot(hist_mask)
plt.xlim([0,256])
plt.show()
plt.imshow()
-
用途:
plt.imshow()
主要用于显示二维图像数据(如照片、热图等)。它接受一个二维数组(对于灰度图像)或三维数组(对于彩色图像),并根据这些数值绘制图像。
plt.plot()
-
用途:
plt.plot()
用于绘制线性图形,适用于展示数据点之间的关系,如时间序列、函数曲线等。它可以用来绘制一条或多条线,并支持多种样式选项。
图像均衡化是一种用于增强图像对比度的技术,特别适用于那些直方图集中在某些灰度级范围内的图像。通过重新分布图像的像素值,使得整个灰度范围内像素值的分布更加均匀,从而达到增强图像对比度的效果。均衡化最常应用于灰度图像,但也可以扩展到彩色图像的每个通道。
7.3 均衡化效果
img = cv2.imread("xyz.jpg",0)
plt.hist(img.ravel(),256)
plt.show()
均衡化:
equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)
plt.show()
分别展示两张图片:
自适应直方图均衡化:
clahe = cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
是 OpenCV 中用于创建一个 Contrast Limited Adaptive Histogram Equalization (CLAHE) 对象的函数调用。CLAHE 是一种改进的直方图均衡化方法,旨在克服传统直方图均衡化的一些缺点,比如过度放大噪声的问题。
参数解释
-
clipLimit
:对比度限制阈值。这是一个浮点数,表示对比度增强的阈值。如果某个小区域内的对比度超过了这个阈值,则会进行裁剪(即限制该区域内像素值的变化幅度),以防止噪声被过度放大。默认值为40.0
,但在你的例子中设置为2.0
。 -
tileGridSize
:用于划分图像的小块(tiles)大小。它是一个包含两个整数的元组(x, y)
,表示将图像划分为x * y
的网格。每个小块独立地进行直方图均衡化。在你的例子中,设置为(8, 8)
,意味着图像会被分成 8x8 的小块。
res_clahe = clahe.apply(img)
cv_show("res_clahe",res_clahe[300:1000,300:1000])
7.4 傅里叶概述
在图像处理和计算机视觉领域,傅里叶变换是一种非常重要的工具,它可以将图像从空间域转换到频率域。这种转换有助于分析图像的频率成分,并且可以用于多种应用,如图像滤波、压缩、特征提取等。
7.5 频域变化结果
img = cv2.imread("xyz.jpg",0)img_float32 = np.float32(img)dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 得到灰度图能表示的形式
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))plt.subplot(121), plt.imshow(img, cmap="gray")
plt.title("Input Image"), plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap="gray")
plt.title("Magnitude Spectrum"),plt.xticks([]),plt.yticks([])
plt.show()
傅里叶变换要求输入数据类型为浮点型。这里使用 np.float32()
将图像从默认的 uint8
类型转换为 float32
类型,以便后续处理。
使用 cv2.dft()
函数对图像执行离散傅里叶变换 (DFT)。flags=cv2.DFT_COMPLEX_OUTPUT
参数确保输出是一个复数数组,包含两个通道:一个表示实部,另一个表示虚部。
默认情况下,傅里叶变换的结果中,零频率分量位于左上角。使用 np.fft.fftshift()
函数可以将零频率分量移到频谱图的中心位置,这有助于更直观地分析和可视化频率成分。
首先,使用 cv2.magnitude()
函数计算傅里叶变换结果的幅度。该函数接收复数数组的实部和虚部作为输入,返回幅度值。
然后,应用 20*np.log(...)
转换,将幅度值缩放到对数尺度。这样做是为了使幅度谱中的动态范围更适合于显示,因为原始幅度值的范围可能非常大,难以在图像中直观地展示。
7.6 低通与高通滤波
①低通滤波
img = cv2.imread("xyz.jpg",0)img_float32 = np.float32(img)dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)rows,cols = img.shape
crow,ccol = int(rows/2),int(cols/2)#低通滤波
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30,ccol-30:ccol+30] = 1# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])plt.subplot(121),plt.imshow(img,cmap = "gray")
plt.title("Input Image"),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back,cmap="gray")
plt.title("Result"),plt.xticks([]),plt.yticks([])plt.show()
将傅里叶变换后的结果 dft_shift
与低通滤波器掩码 mask
相乘,从而保留低频分量,去除高频分量。
使用 np.fft.ifftshift()
将零频率分量重新移回左上角。
使用 cv2.idft()
执行逆傅里叶变换,恢复到空间域。
使用 cv2.magnitude()
计算复数数组的幅度值,以得到最终的图像。
②高通滤波
img = cv2.imread("xyz.jpg",0)img_float32 = np.float32(img)dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)rows,cols = img.shape
crow,ccol = int(rows/2),int(cols/2)#低通滤波
mask = np.ones((rows,cols,2),np.uint8)
mask[crow-30:crow+30,ccol-30:ccol+30] = 0# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])plt.subplot(121),plt.imshow(img,cmap = "gray")
plt.title("Input Image"),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back,cmap="gray")
plt.title("Result"),plt.xticks([]),plt.yticks([])plt.show()
至此,opencv基本图像操作学习完毕
相关文章:

【opencv】图像基本操作
一.计算机眼中的图像 1.1 图像读取 cv2.IMREAD_COLOR:彩色图像 cv2.IMREAD_GRAYSCCALE:灰色图像 ①导包 import cv2 # opencv读取的格式是BGR import matplotlib.pyplot as plt import numpy as np %matplotlib inline ②读取图像 img cv2.imread(…...

泛微OA编写后端Rest接口
泛微OA编写后端Rest接口 前言 具体实现 运行结果 注意要点 总结 前言 在泛微E9中,可以通过注解的方式来编写对外的接口,之前的版本都是通过编写servlet类,然后在web.xml文件中将这个类和访问路径进行编辑之后才好在浏览器中通过输入对应…...

AI助力下的PPT革命:DeepSeek 与Kimi的高效创作实践
清华大学出品《DeepSeek:从入门到精通》分享 在忙碌的职场中,制作一份高质量的PPT往往需要投入大量时间和精力,尤其是在临近截止日期时。今天,我们将探索如何借助 AI 工具 —— DeepSeek 和 Kimi —— 让 PPT 制作变得既快捷又高…...

002 SpringCloudAlibaba整合 - Feign远程调用、Loadbalancer负载均衡
前文地址: 001 SpringCloudAlibaba整合 - Nacos注册配置中心、Sentinel流控、Zipkin链路追踪、Admin监控 文章目录 8.Feign远程调用、loadbalancer负载均衡整合1.OpenFeign整合1.引入依赖2.启动类添加EnableFeignClients注解3.yml配置4.日志配置5.远程调用测试6.服务…...

计算机视觉之图像处理-----SIFT、SURF、FAST、ORB 特征提取算法深度解析
SIFT、SURF、FAST、ORB 特征提取算法深度解析 前言 在图像处理领域亦或是计算机视觉中,首先我们需要先理解几个名词: 什么是尺度不变? 在实际场景中,同一物体可能出现在不同距离(如远处的山和近处的树)…...

DeepSeek接入Siri(已升级支持苹果手表)完整版硅基流动DeepSeek-R1部署
DeepSeek接入Siri(已升级支持苹果手表)完整版硅基流动DeepSeek-R1部署 **DeepSeek** 是一款专注于深度学习和人工智能的工具或平台,通常与人工智能、机器学习、自动化分析等领域有关。它的主要功能可能包括:深度学习模型搜索&…...

elabradio入门第八讲——帧同步技术
一、帧同步的相关知识 数字通信中, 为了使接收到的码元能够被理解,需要知道其如何分组。一般说来,接收端需要利用帧同步码去划分接收码元序列。将标志码组开始位置的帧同步码插入于一个码组的前面,如图所示。 这里的帧同步码是一…...

站长工具SEO综合查询是什么?怎么利用站长工具SEO综合查询
你的网站是否像一辆没有仪表盘的车?明明在狂奔却不知道油耗、时速、故障灯状态?2025年SimilarWeb数据显示,83%的站长因缺乏数据化诊断工具,导致50%以上的流量白白流失。今天我们用“修车师傅”的视角,拆解SEO综合查询工…...

超简单理解KMP算法(最长公共前后缀next数组、合并主子串、子串偏移法)
KMP算法理解 最长公共前后缀next合并主子串子串偏移 参考b站:子串偏移、合并主子串 最长公共前后缀next 这个概念是一个trick,帮助我们记录遍历了一遍的数组的相似特性,想出来确实很nb,我也不理解逻辑是怎么想出来的。 字符串的…...
【每日论文】TESS 2: A Large-Scale Generalist Diffusion Language Model
下载PDF或阅读论文,请点击:LlamaFactory - huggingface daily paper - 每日论文解读 | LlamaFactory | LlamaFactory 摘要 我们推出了TESS 2,这是一种通用的指令跟随扩散语言模型,其性能优于当代的指令调整扩散模型,有…...
如何在 React 中测试高阶组件?
在 React 中测试高阶组件可以采用多种策略,以下是常见的测试方法: 1. 测试高阶组件返回的组件 高阶组件本身是一个函数,它返回一个新的组件。因此,可以通过测试这个返回的组件来间接测试高阶组件的功能。通常使用 Jest 作为测试…...
设计模式学习笔记
说了一万遍!学习要做笔记! 时间一长,就会忘了,后面再来学,又要从头学起 关键是重难点!!!当初学的时候就是因为攻克难点、寻找重点花费时间 不做笔记每次复习都要浪费时间在重难点上…...

写论文技巧 :Word文档插入图片,实现自动对齐
插入表格,调整大小 取消自动适应 插入图片,去掉边框...

VSCode - VSCode 切换自动换行
VSCode 自动换行 1、基本介绍 在 VSCode 中,启用自动换行可以让长行代码自动折行显示,避免水平滚动条频繁使用,提升代码阅读体验 如果禁用自动换行,长行代码就需要手动结合水平滚动条来阅读 2、演示 启用自动换行 禁用自动换…...

postman传query一个数组类型的参数,并且数组里面只有一个值的时候
1.在所加的检索项目后面加上[0], 例: item[0]2.数组里面多个值的时候,写两个相同的项目名,值不相同 itemvalue1 itemvalue2再看不懂,我也没办法了。...

【智能客服】ChatGPT大模型话术优化落地方案
本文原创作者:姚瑞南 AI-agent 大模型运营专家,先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗;多年人工智能行业智能产品运营及大模型落地经验,拥有AI外呼方向国家专利与PMP项目管理证书。(转载需经授权) 目录 一、项目背景 1.1 行业背景 1.2 业务现…...
vue3 文件类型传Form Data数据格式给后端
在 Vue 3 中,如果你想将文件(例如上传的 Excel 文件)以 FormData 格式发送到后端,可以通过以下步骤实现。这种方式通常用于处理文件上传,因为它可以将文件和其他数据一起发送到服务器。 首先,创建一个 Vue…...
高考或者单招考试需要考物理这科目
问题:帮忙搜索一下以上学校哪些高考或者单招考试需要考物理这科目的 回答: 根据目前获取的资料,明确提及高考或单招考试需考物理的学校为湖南工业职业技术学院,在部分专业单招时要求选考物理;其他学校暂未发现明确提…...
深入剖析 DeepSeek:张量计算范式全解析
一、引言 在 AI 技术迅猛发展的当下,DeepSeek 以其卓越的性能成为研究热点。清华大学的《DeepSeek:从入门到精通》这一珍贵资料,为我们深入挖掘 DeepSeek 核心原理提供了指引,其中张量计算范式更是关键所在,它构建起整…...

VSCode集成deepseek使用介绍(Visual Studio Code)
VSCode集成deepseek使用介绍(Visual Studio Code) 1. 简介 随着AI辅助编程工具的快速发展,VSCode作为一款轻量级、高度可扩展的代码编辑器,已成为开发者首选的工具之一。DeepSeek作为AI模型,结合Roo Code插件&#x…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...

FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...