• [其他] OpenCV(33)---模板匹配人眼
    什么是模板匹配模板匹配是指在当前图像A内寻找与图像B最相似的部分,可以理解找茬,但是这里是找出一样的信息。一般我们将图像A称为输入图像,将图像B称为模板图像。模板匹配的原理就是将模板B图像在图像A上滑动遍历,找出与其匹配的部分。模板匹配函数在OpenCV中,它给我们提供了cv2.matchTemplate()函数来完成模板匹配。其函数的完整定义如下:def matchTemplate(image, templ, method, result=None, mask=None): 复制代码image:原始图像templ:模板图像method:匹配方法。该参数通过TemplateMatchModes实现,如下表所示:参数取值含义cv2.TM_SQDIFF0以方差为依据进行匹配。若完全匹配,则结果为0;若不匹配,则会得到一个很大的差值cv2.TM_SQDIFF_NORMED1标准(归一化)平方差匹配cv2.TM_CCORR2相关匹配,这类方法将模板图像与输入图像相乘,如果乘积越大,则匹配度较高;如果乘积为0,则表示匹配效果最差cv2.TM_CCORR_NORMED3标准(归一化)相关匹配cv2.TM_CCOEFF4相关系统匹配,这类方法将模板图像与其均值的相对值,和输入图像与其均值的相关值进行匹配。1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关匹配(随机序列)cv2.TM_CCOEFF_NORMED5标准(归一化)相关系数匹配result:返回值。它是由每个位置的比较结果组合所构成的一个结果集,类型是单通道32位浮点型。如果输入图像尺寸是WH,模板尺寸是wh,则返回值的大小为(W-w+1)*(H-h+1)。mask:模板图像掩模。它必须与模板图像具有相同类型的大小。通常使用默认值即可。实现模板匹配首先,我们需要两张图片,这里我们还是选取经常用的美女照片以及截取其眼睛部分作为模板图像,如下:import cv2 import matplotlib.pyplot as plt img = cv2.imread("4.jpg", 0) template = cv2.imread("4_1.jpg", 0) th, tw = template.shape[::] rv = cv2.matchTemplate(img, template, cv2.TM_SQDIFF) min, max, minLoc, maxLoc = cv2.minMaxLoc(rv) topLeft = minLoc bottomRight = (topLeft[0] + tw, topLeft[1] + th) cv2.rectangle(img, topLeft, bottomRight, 255, 2) plt.subplot(121) plt.imshow(template, cmap="gray") plt.axis('off') plt.subplot(122) plt.imshow(img, cmap="gray") plt.axis('off') plt.show() 复制代码运行之后,效果如下:作者:极客学编程链接:https://juejin.cn/post/6988360954475970596来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(32)---cv2实现傅里叶变换
    在OpenCV中,我们通过cv2.dft()来实现傅里叶变换,使用cv2.idft()来实现逆傅里叶变换。两个函数的定义如下:cv2.dft(原始图像,转换标识) 复制代码这里的原始图像必须是np.float32格式。所以,我们首先需要使用cv2.float32()函数将图像转换。而转换标识的值通常为cv2.DFT_COMPLEX_OUTPUT,用来输出一个复数阵列。经过cv2.dft()函数的变换后,我们会得到原始图像的频谱信息。此时零分量与Numpy库实现一样都不在中心位置。这里我们还是需要使用numpy.fft.fftshift()函数将其移动到中间位置。需要特别注意的是,函数cv2.dft()返回值是双通道的,第1个通道是结果的实数部分,第2个通道是结果的虚数部分。使用numpy.fft.fftshift()函数处理后,频谱图像还只是一个由实部和虚部构成的值,要显示出来,要使用到另一个函数cv2.magnitude()。该函数的定义如下:cv2.magnitude(参数1,参数2) 复制代码参数1:浮点型x坐标值,也就是实部参数2:浮点型y坐标值,也就是虚部,它必须和参数1具有相同的大小(size)得到频谱图像的幅度之后,还需要将幅度映射到灰度空间[0,255]内,使其以灰度图像显示出来。与前篇博文一样,使用20*np.log(cv2.magnitude())。实现傅里叶变换下面,我们来通过上述OpenCV函数来实现傅里叶变换,并显示其频谱信息。import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread("4.jpg", 0) dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) dftShift = np.fft.fftshift(dft) result = 20 * np.log(cv2.magnitude(dftShift[:, :, 0], dftShift[:, :, 1])) plt.subplot(121) plt.imshow(img, cmap="gray") plt.axis('off') plt.subplot(122) plt.imshow(result, cmap="gray") plt.axis('off') plt.show() 复制代码运行之后,显示效果与前篇博文一样。作者:极客学编程链接:https://juejin.cn/post/6988061494483091463来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(31)---傅里叶变换原理(1)
    高通滤波与低通滤波经过前文的介绍,我们知道在一副图像内,同时存在着高频信号和低频信号。而滤波器你可以把它想象成平时生活中的漏斗,它能够允许一定频率的分量通过或者拒绝其通过。我们通过滤波器的作用方式,将其分为低通滤波器与高通滤波器。(题外话,此高通非彼高通,皮一下)低通滤波器:允许低频信号通过。低通滤波器使高频信号衰减而对低频信号放行,会使图像变得模糊高通滤波器:允许高频信号通过。高通滤波器使低频信号衰减而让高频信号通过,将增强图像中尖锐的细节,但是会导致图像的对比度降低。频域处理就是对图像的高频或低频信号进行处理后,再进行逆傅里叶变换返回空间域。下面,我们来通过傅里叶的正逆操作,实现高通滤波。代码如下:import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread("4.jpg", 0) # 傅里叶变换 f = np.fft.fft2(img) fshift = np.fft.fftshift(f) #屏蔽低频信号 rows, cols = img.shape row_half, col_half = int(rows / 2), int(cols / 2) fshift[row_half-20:row_half+20,col_half-20:col_half+20]=0 #逆傅里叶变换 ishift=np.fft.ifftshift(fshift) iimg=np.fft.ifft2(ishift) iimg=np.abs(iimg) plt.subplot(121) plt.imshow(img, cmap="gray") plt.axis('off') plt.subplot(122) plt.imshow(iimg, cmap="gray") plt.axis('off') plt.show() 复制代码上面的代码中,主要通过3行代码屏蔽低频信号,代码如下:rows, cols = img.shape row_half, col_half = int(rows / 2), int(cols / 2) fshift[row_half-20:row_half+20,col_half-20:col_half+20]=0 复制代码我们通过前文知道,np.fft.fftshift会将零频率分量移动到图像的中心区域,那么从中心区域向外扩散就是从低到高。所以,我们只要将中心周围部分的低频信号屏蔽,就保留的高频信号,也就是实现了高通滤波。这里我们选择从中心向外扩散30半径,将其内部的所有低频信号全部赋值为0即可。运行之后,我们会得到高通滤波的图像,同时该图像的边缘信息得以保留。作者:极客学编程链接:https://juejin.cn/post/6987989165329612807来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(31)---傅里叶变换原理
    前言要理解傅里叶变换,我们首先需要了解图像处理。在图像处理的过程中,一般分为空间域处理和频率域处理。空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰度变换和空间滤波两种形式。灰度变换是对图像内的单个像素进行处理,比如调节对比度和处理阈值等。控制滤波处理涉及图像质量的改变,例如前面的图像平滑处理。空间域处理的优点:计算简单方便,运算速度更快频率域处理时先将图像变换到频率域,然后在频率域对图像进行处理,最后在通过反变换将图像从频率域变换到空间域。傅里叶变换是应用最广泛的一种频率域变换,它能够将图像从空间域变换到频率域,而逆傅里叶变换能够将频率域信息变换到空间域内。傅里叶变化法国数学家傅里叶指出,任何周期函数都可以表示为不同频率的正弦函数和的形式。在图像的处理中,傅里叶变换就是将图像分解为正弦分量和余弦分量两部分,即将图像从空间域转换到频率域。数字图像经过傅里叶变化后,得到的频率域的值是复数。因此显示傅里叶变换的结果需要使用实数图像加虚数图像,或者幅度图像加相位图像的形式。因为幅度图像包含了原图像中我们所需要的大部分信息,所以在图像的处理过程中,通常仅使用幅度图像。当然,如果希望先在频率域内对图像进行处理,再通过傅里叶变换得到修改后的空间域图像,就必须同时保留幅度图像和相位图像。对图像进行傅里叶变换后,我们会得到图像中的低频与高频信息。低频信息对应图像内变化缓慢的灰度分量。高频信息对应图像内变换越来越快的灰度分量,是由灰度的尖锐过度造成的。例如,在一副大草原的图像中有一头狮子,低频信息就对应着广袤的草原,而高频信息对应着狮子的轮廓等各种边界及噪声信息。傅里叶变换的作用,就是为了将图像从空域转换到频域,并在频率域内实现对图像内特定对象的处理,然后再对经过处理的频率域图像进行逆傅里叶变换得到空间域图像。其主要用处包括:图像增强,图像去噪,边缘检测,特征提取,图像压缩,图像加密等。实现傅里叶变化在Numpy包中,它给我们提供了numpy.fft.fft2()函数实现傅里叶变换。其完整定义如下:def fft2(原始图像): 复制代码需要注意的是,原始图像必须是灰度图像,其返回值是ndarray类型。下面,我们来实现傅里叶变换,并观察得到的频谱图像:import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread("4.jpg", 0)#1 f = np.fft.fft2(img)#2 fshift = np.fft.fftshift(f)#3 spectrum = 20 * np.log(np.abs(fshift))#4 #5 plt.subplot(121) plt.imshow(img) plt.axis('off') #6 plt.subplot(122) plt.imshow(spectrum) plt.axis('off') #7 plt.show() 复制代码上面代码以此代表的意思如下:1.使用OpenCV以灰度图像的形式读取2.实现傅里叶变换3.经过2傅里叶变换函数处理之后。此时,图像频谱中的零频率分量位于频谱图像的左上角,为了便于观察,这里通过函数np.fft.fftshift将零频谱成分移动到频域图像的中心位置。4.对图像进行傅里叶变换之后,得到的是一个复数数组。为了显示为图像,需要将它们的值调整到[0,255]的灰度空间内,通过20 * np.log(np.abs(fshift))实现。5.以灰度图像的形式绘制原图6.以灰度图像的形式绘制频域图7.显示2个图运行之后,效果如下:实现逆傅里叶变化既然我们在实现傅里叶变换之时,将零频谱移动到了图像中间。那么,在逆变换的时候,我我们就需要将其移回去,该移回去的逆函数是np.fft.ifftshift()。而移回去之后,才可以进行逆傅里叶变换。逆傅里叶变换函数为np.fft.ifft2()。它返回空域信息是一个复数数组,同样需要我们将信息调整到[0,255]之间。使用公式为:np.abs(逆傅里叶变换结果)。下面,我们实现傅里叶变换以及逆傅里叶变换。代码如下所示:import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread("4.jpg", 0) #傅里叶变换 f = np.fft.fft2(img) fshift = np.fft.fftshift(f) ishift=np.fft.ifftshift(fshift) iimg=np.fft.ifft2(ishift) iimg=np.abs(iimg) print(iimg) print(img) plt.subplot(121) plt.imshow(img,cmap="gray") plt.axis('off') plt.subplot(122) plt.imshow(iimg,cmap="gray") plt.axis('off') plt.show()作者:极客学编程链接:https://juejin.cn/post/6987989165329612807来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(30)---图像的输入输出与显示(1)
    使用matplotlib读取,保存和显示图像在OpenCV中,我们对图像进行直方图处理的时候,会经常辅助用到matplotlib包。所以,我们有必要掌握matplotlib包读取,保存与显示图像。from matplotlib.image import imread import matplotlib.pyplot as plt img = imread("4.jpg")#读取图像 print(img.shape, img.dtype, type(img))#输出图像的参数 plt.figure(figsize=(10, 10)) plt.axis("off")#不显示坐标轴 #显示图像 plt.imshow(img) plt.show() plt.savefig("11111.jpg")#保存图像 复制代码上面注释非常详细,这里就不在赘述。不过,其imshow()方法还有一个插值参数interpolation。plt.imshow(img,interpolation="spline16") 复制代码通过interpolation参数,我们可以使用不同的插值对图像进行处理。使用scikit-image读取,保存和显示图像scikit-image包与PIL一样,可以读取图像后获取图像的详细参数信息。同时,它也可以与OpenCV一样进行色彩空间的转换。from skimage import io,color import matplotlib.pyplot as plt img=io.imread("4.jpg")#读取图像 print(img.shape,img.dtype,type(img))#输出图像参数 plt.axis("off")#去除坐标轴 io.imsave("11111.jpg",img)#保存图像 hsv=color.rgb2hsv(img)#图像转换为hsv色彩空间 #显示图像 plt.imshow(hsv) plt.show() 复制代码scikit-image与matplotlib读取后的格式都是numpy.ndarray。作者:极客学编程链接:https://juejin.cn/post/6987988861108355103来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(30)---图像的输入输出与显示
    前言在讲解后面的采样以及傅里叶变换之前,我们需要掌握python对图像的输入、输出以及显示等操作。本篇涉及都是简单的图像显示保存等操作,但是后面基于此复杂的变换都会或多或少用到这些知识。所以,别看非常简单,应用起来还是非常多的。使用PIL读取,保存和显示图像在PIL包中,使用Image.open()函数读取磁盘图像。获取图像后,我们可以完整的获取图像的宽高,分辨率等信息。from PIL import Image img=Image.open("4.jpg") print("图像宽度:"+str(img.width)) print("图像高度:"+str(img.height)) print("图像分辨率:"+img.format) print("图像模式:"+img.mode) img.show() 复制代码运行之后,图片这些信息都会完整的显示出来:而对于识别图像内容来说,我们一般都是将图像转换为灰度图像。而PIL包转换为恢复图像的方式如下:img=Image.open("4.jpg") imgL=img.convert("L") imgL.show() 复制代码运行之后,灰度图像会通过默认的电脑图片显示程序,显示出来。至于存储图像,我们通过如下代码实现:imgL.save("1111111.jpg")作者:极客学编程链接:https://juejin.cn/post/6987988861108355103来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(29)---轮廓的特征值(6)
    极点有时候,我们希望获取某个对象内的极点,比如最左,最右,最上,最下等。在OpenCV中,它给我们提供了以下方法进行获取:left=tuple(cnt[cnt[:,:,0].argmin()][0]) right=tuple(cnt[cnt[:,:,0].argmax()][0]) top=tuple(cnt[cnt[:,:,1].argmin()][0]) bottom=tuple(cnt[cnt[:,:,1].argmax()][0]) 复制代码下面,我们来通过这些方法获取,代码如下:import cv2 import numpy as np img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) mask = np.zeros(img.shape, np.uint8) cnt = contours[0] left = tuple(cnt[cnt[:, :, 0].argmin()][0]) right = tuple(cnt[cnt[:, :, 0].argmax()][0]) top = tuple(cnt[cnt[:, :, 1].argmin()][0]) bottom = tuple(cnt[cnt[:, :, 1].argmax()][0]) print(left, right, top, bottom) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img, "left", left, font, 1, (0, 255, 0), 2) cv2.putText(img, "right", right, font, 1, (0, 255, 0), 2) cv2.putText(img, "top", top, font, 1, (0, 255, 0), 2) cv2.putText(img, "bottom", bottom, font, 1, (0, 255, 0), 2) cv2.imshow("result",img) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,值与效果如下:作者:极客学编程链接:https://juejin.cn/post/6987744292550754318来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(29)---轮廓的特征值(5)
    平均颜色及平均灰度在OpenCV中,它给我们提供cv2.mean()函数计算一个对象的平均颜色与平均灰度。其完整定义如下:def mean(src, mask=None): 复制代码参数与上面两个小节一样,这里不在赘述。下面,我们来使用这个函数,代码如下:import cv2 import numpy as np img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) mask=np.zeros(gray.shape,np.uint8) cv2.drawContours(mask,[contours[0]],0,255,2) mean=cv2.mean(img,mask) 复制代码运行之后,输出4个值:RGB以及A通道的均值:作者:极客学编程链接:https://juejin.cn/post/6987744292550754318来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(29)---轮廓的特征值(4)
    最大值,最小值以及它们的位置在OpenCV中,它提供cv2.minMaxLoc()函数获取指定对象内最大值,最小值以及位置等信息,其完整定义如下:def minMaxLoc(src, mask=None): 复制代码src:单通道图像mask:掩摸,通过使用掩摸图像,得到掩膜指定区域内的最值信息该函数返回4个值:最小值,最大值,最小值位置,最大值位置。下面,我们来获取这些值,代码如下:import cv2 import numpy as np img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) mask = np.zeros(gray.shape, np.uint8) cv2.drawContours(mask, [contours[0]], 0, 255, 2) min, max, min_loc, max_loc = cv2.minMaxLoc(gray, mask) print(min, max, min_loc, max_loc) 复制代码运行之后,控制台输出4个值:作者:极客学编程链接:https://juejin.cn/post/6987744292550754318来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(29)---轮廓的特征值(3)
    掩摸和像素点有时候,我们还像获取某对象的掩摸图像及其对应的点。在OpenCV中,它还提供了cv2.findNonZero()函数用于获取一个图像内的轮廓点位置,其完整定义如下:def findNonZero(src, idx=None): 复制代码src:要查找非零元素的图像idx:返回值,表示非0元素的索引位置。具体格式为(行号,列号)下面,我们实测该函数,代码如下:import cv2 import numpy as np img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) mask=np.zeros(gray.shape,np.uint8) cv2.drawContours(mask,[contours[0]],0,255,2) pixelpoints=cv2.findNonZero(mask) print(pixelpoints) cv2.imshow("img1", mask) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,我们会得到轮廓点位置:作者:极客学编程链接:https://juejin.cn/post/6987744292550754318来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(29)---轮廓的特征值(2)
    Solidity我们还可以使用轮廓面积与凸包面积之比Solidity来衡量图像,轮廓以及凸包的特征。其数学计算公式为:Slidity=轮廓面积/凸包面积下面,我们来计算Slidity,代码如下:import cv2 img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) x, y, w, h = cv2.boundingRect(contours[0]) cntArea=cv2.contourArea(contours[0])#轮廓面积 hull=cv2.convexHull(contours[0]) hullArea=cv2.contourArea(hull)#凸包面积 solidity=float(cntArea)/hullArea print(solidity) 复制代码运行之后,本例轮廓面积与凸包面积的比值solidity约为1:等效直径在OpenCV中,我们还可以使用等效直径来衡量轮廓的特征值,该值是与轮廓面积相等的圆形的直径。其数学计算公式为:下面,我们来计算与轮廓面积相等的圆形直径,代码如下:import cv2 import numpy as np img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) x, y, w, h = cv2.boundingRect(contours[0]) cntArea=cv2.contourArea(contours[0])#轮廓面积 equiDiameter=np.sqrt(4*cntArea/np.pi) print(equiDiameter) cv2.circle(img,(100,100),int(equiDiameter/2),(0,255,0),3) cv2.imshow("img1",img) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,我们得到其等效直径约为145:方向在OpenCV中,函数cv2.fitEllipse()可以用来构建最优拟合椭圆,还可以在返回值内分别返回椭圆的中心点,轴长,旋转角度信息。使用这种形式,能够直观地获取椭圆的方向等信息。函数cv2.fitEllipse()返回值为:(x,y):椭圆的中心点(MA,ma):椭圆水平方向轴与垂直方向轴的长度angle:椭圆的旋转角度import cv2 img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) ellipsis=cv2.fitEllipse(contours[0]) (x, y), (MA, ma), angle = cv2.fitEllipse(contours[0]) print((x, y), (MA, ma), angle) cv2.ellipse(img, ellipsis, (0, 255, 0), 2) cv2.imshow("img1", img) cv2.waitKey() cv2.destroyAllWindows() 复制代码本来就是椭圆图,下面拟合后正好也是椭圆:作者:极客学编程链接:https://juejin.cn/post/6987744292550754318来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(29)---轮廓的特征值(1)
    前言轮廓自身的一些属性特征及轮廓所包围对象的特征对于描述图像具有重要意义。本篇博文将介绍几个轮廓自身的属性特征及轮廓包围对象的特征。宽高比在轮廓中,我们可以通过宽高比来描述轮廓,例如矩形的轮廓宽高比为:宽高比=宽度/高度下面,我们来计算矩形轮廓的宽高比,代码如下:import cv2 img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) x, y, w, h = cv2.boundingRect(contours[0]) cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 3) cv2.imshow("img1", img) aspectRatio=float(w)/h print(aspectRatio) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,我们可以得到轮廓的宽高比约为3:Extend我们还可以使用轮廓面积与矩形边界面积之比Extend来描述图像及其轮廓特征,数学计算公式图下:Extend=轮廓面积/矩形边界面积下面,我们来计算Extend,代码如下:import cv2 img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) x, y, w, h = cv2.boundingRect(contours[0]) rectArea=w*h#矩形边界面积 cntArea=cv2.contourArea(contours[0])#轮廓面积 extend=float(cntArea)/rectArea print(extend) 复制代码本例中,轮廓面积与矩形边界面积的比值Extend大约为0.8:Solidity我们还可以使用轮廓面积与凸包面积之比Solidity来衡量图像,轮廓以及凸包的特征。其数学计算公式为:Slidity=轮廓面积/凸包面积下面,我们来计算Slidity,代码如下:import cv2 img = cv2.imread("26_1.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) x, y, w, h = cv2.boundingRect(contours[0]) cntArea=cv2.contourArea(contours[0])#轮廓面积 hull=cv2.convexHull(contours[0]) hullArea=cv2.contourArea(hull)#凸包面积 solidity=float(cntArea)/hullArea print(solidity) 复制代码运行之后,本例轮廓面积与凸包面积的比值solidity约为1:作者:极客学编程链接:https://juejin.cn/post/6987744292550754318来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(28)---凸包
    前言逼近多边形是某个图像轮廓的高度近似,而凸包的提出是为了简化逼近多边形的。其实,凸包跟逼近多边形很像,只不过它是物体最外层的“凸”多边形。简单的概括,凸包是指完全包含原有轮廓,并且仅由轮廓上的点所构成的多边形。凸包的特点是每一处都是凸的,即在凸包内连接任意两点的直线都在凸包的内部,并且任意连续3个点的内角小于180度。在OpenCV中,它给我们提供cv2.convexHull()来获取轮廓的凸包。其完整定义如下:def convexHull(points, hull=None, clockwise=None, returnPoints=None): 复制代码points:轮廓hull:返回值,为凸包角点。可以理解为多边形的点坐标,或索引。clockwise:布尔类型,为True时,凸包角点将按顺时针方向排列;为False时,为逆时针。returnPoints:布尔类型,默认值True,函数返回凸包角点的x/y坐标;为False时,函数返回轮廓中凸包角点的索引。获取凸包角点既然,我们已经了解了凸包的作用,并且理解了OpenCV提供的函数。下面,我们随便选取一张图,获取凸包角点。具体代码如下所示:import cv2 img = cv2.imread("24.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) hull=cv2.convexHull(contours[0]) print(hull) 复制代码这里,我们随便获取了一张图像,并获取其凸包的角点。运行之后,角点坐标如下:如果修改参数returnPoints为False,会返回对应的6个索引值。这里我们再添加一行代码就可以绘制凸包多边形了,具体添加的代码如下:#获取hull之后 cv2.polylines(img, [hull], True, (0, 255, 0), 2) cv2.imshow("img1", img) 复制代码运行之后,效果如下所示:凸缺陷凸包与轮廓之间的部分我们称之为凸缺陷。在OpenCV中使用函数cv2.convexityDefects()获取凸缺陷,其完整定义如下:def convexityDefects(contour, convexhull, convexityDefects=None): 复制代码contour:轮廓convexhull:凸包convexityDefects:返回值,为凸缺陷点集。它是一个数组,返回的指包括[起点,终点,轮廓上的距离凸包最远点,最远点到凸包的近似距离]特别注意,用该函数计算凸缺陷之前,我们需要使用函数cv2.convexHull()获取凸包,但其参数returnPoints必须为False。下面,我们来使用该函数计算上图的凸缺陷。代码如下:import cv2 img = cv2.imread("24.jpg") cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) hull = cv2.convexHull(contours[0], returnPoints=False) defects = cv2.convexityDefects(contours[0], hull) print(defects) for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(contours[0][s][0]) end = tuple(contours[0][e][0]) far = tuple(contours[0][f][0]) cv2.line(img, start, end, [0, 255, 0], 2) cv2.circle(img, far, 5, [0, 0, 255], -1) cv2.imshow("img1", img) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,效果如下:如上图所示,我们用点标记出来的凸缺陷,可以看到五角星的每个凹肩都是凸缺陷。作者:极客学编程链接:https://juejin.cn/post/6987248981545844766来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(27)---轮廓拟合--最小外包三角形
    在OpenCV,它还提供了cv2.minEnclosingTriangle()函数来绘制最小外包三角形。其完整定义如下:def minEnclosingTriangle(points, triangle=None): 复制代码其中points与前文类似,其返回值triangle为外包三角形的三个顶点集。下面,我们直接构建最小外包三角形,具体代码如下:import cv2 img = cv2.imread("27.jpg") cv2.imshow("img1", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) area, trg1 = cv2.minEnclosingTriangle(contours[0]) print(area) print(trg1) for i in range(0, 3): cv2.line(img, tuple(trg1[i][0]), tuple(trg1[(i + 1) % 3][0]), (0, 255, 0), 2) cv2.imshow("img2", img) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,效果如下:需要注意的是,在cv2中没有直接绘制三角形的函数,所以我们通过绘制三条直线,绘制三角形,minEnclosingTriangle()函数第一个返回值为三角形面积,第二返回值是三点坐标。逼近多边形在OpenCV中,它还提供了cv2.approxPolyDP()函数构建指定边数的逼近多边形。其完整定义如下:def approxPolyDP(curve, epsilon, closed, approxCurve=None): 复制代码curve:轮廓epsilon:精度,原始轮廓的边界点与逼近多边形边界之间的最大距离closed:布尔类型。为True时,表示逼近多边形是封闭的。为False时,biao表示毕竟多边形是不封闭的。approxCurve为该函数的返回值,是逼近多边形的点集。。下面,我们来实现各类逼近多边形的绘制,代码如下:import cv2 img = cv2.imread("24.jpg") list=[0.1,0.09,0.055,0.05,0.02] cv2.imshow("img", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) for i, val in enumerate(list): epsilon = val * cv2.arcLength(contours[0], True) approx = cv2.approxPolyDP(contours[0], epsilon, True) cv2.drawContours(img, [approx], 0, (0, 255, 0), 2) cv2.imshow("img"+str(i), img) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,效果如下:作者:极客学编程链接:https://juejin.cn/post/6987018772653539341来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • [其他] OpenCV(27)---轮廓拟合--最优拟合直线&
    在OpenCV中,它还提供了cv2.fitLine()函数绘制最优拟合直线,其完整定义如下:def fitLine(points, distType, param, reps, aeps, line=None): 复制代码points:与前文一样,是轮廓distType:距离类型。拟合直线时,要使输入点到拟合直线的距离之和最小。详细参数定义参考开发文档,这里不在赘述。param:距离参数,与所选距离类型有关。当该参数为0时,自动选择最优值。reps:用于表示拟合直线所需要的径向精度,通常该值被设定为0.01aeps:用于表示拟合直线所需要的角度精度,通常该值被设定为0.01对于二维直线,返回值line为4维,前两维代表拟合出的直线的方向,后两位代表直线上的一点。下面,我们来直接使用代码绘制最优拟合直线。import cv2 img = cv2.imread("27.jpg") cv2.imshow("img1", img) # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) rows, cols = img.shape[:2] [vx, vy, x, y] = cv2.fitLine(contours[0], cv2.DIST_L2, 0, 0.01, 0.01) lefty = int((-x * vy / vx) + y) righty = int(((cols - x) * vy / vx) + y) cv2.line(img, (cols - 1, righty),(0, lefty), (0, 0, 255), 3) cv2.imshow("img2", img) cv2.waitKey() cv2.destroyAllWindows() 复制代码运行之后,效果如下所示:作者:极客学编程链接:https://juejin.cn/post/6987018772653539341来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总条数:322 到第
上滑加载中