- 1.分割和轮廓
- 2.层次结构和检索模式
- 3.逼近轮廓并找到其凸包
- 4.凸包
- 5.按形状匹配轮廓
- 6.识别形状(圆形,矩形,三角形,正方形,星形)
- 7.线路检测
- 8.斑点检测
- 9.过滤斑点–计算圆和椭圆
在先前的教程中,我们使用OpenCV进行基本的图像处理,并完成了一些高级图像编辑操作。众所周知, OpenCV是开源通勤者视觉库,具有C ++,Python和Java接口,并支持Windows,Linux,Mac OS,iOS和Android。因此,可以在具有Python和Linux环境的Raspberry Pi中轻松安装它。带有OpenCV和附加摄像头的Raspberry Pi可用于创建许多实时图像处理应用程序,例如人脸检测,人脸锁定,对象跟踪,汽车车牌检测,家庭安全系统等。在本教程中,我们将学习如何做使用OpenCV进行图像分割。下面列出了我们要执行的操作:
- 分割和轮廓
- 层次结构和检索模式
- 逼近轮廓并找到其凸包
- Conex船体
- 匹配轮廓
- 识别形状(圆形,矩形,三角形,正方形,星形)
- 线检测
- 斑点检测
- 过滤斑点–计算圆和椭圆
1.分割和轮廓
图像分割是我们将图像划分到不同区域的过程。而轮廓是连续的直线或曲线的是结合或覆盖对象的图像中的全部边界。并且,这里我们将使用称为轮廓的图像分割技术来提取图像的各个部分。
轮廓在
- 物体检测
- 形状分析
从现实世界的图像分析到MRI等医学图像分析,它们具有非常广泛的应用领域。
让我们知道如何通过提取正方形轮廓来在opencv中实现轮廓。
导入cv2 导入numpy作为np
让我们加载一个带有3个黑色正方形的简单图像
image = cv2.imread('squares.jpg') cv2.imshow('输入图像',图像) cv2.waitKey(0)
灰阶
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
找到精巧的边缘
edged = cv2.Canny(灰色,30,200) cv2.imshow('canny edge',edged) cv2.waitKey(0)
寻找轮廓
#使用图像的副本,例如-edged.copy(),因为查找轮廓会改变图像 #由于OpenCV版本 _的 升级,轮廓必须作为空参数添加_,轮廓,等级= cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)cv2.imshow('轮廓轮廓后的canny边缘',边缘) cv2.waitKey(0)
打印轮廓文件以了解轮廓包括什么
print(轮廓) print('找到的轮廓数量='+ str(len(轮廓)))
绘制所有轮廓
#使用-1作为第三个参数绘制所有轮廓 cv2.drawContours(image,contours,-1,(0,255,0),3) cv2.imshow('contours',image) cv2.waitKey(0) cv2。 destroyAllWindows()
控制台输出-],
],
],
…,
],
],
]],
dtype = int32),
array(],
],
],
…,
],
],
]],dtype = int32),array(],
],
],
…,
],
],
]],dtype = int32)]
找到的轮廓数量= 3。因此,我们总共找到了三个轮廓。
现在,在上面的代码中,我们还使用来打印轮廓文件 , 该文件说明了这些轮廓的外观,如在控制台输出中所打印的那样。
在上面的控制台输出中,我们有一个看起来像x,y点坐标的矩阵。OpenCV将轮廓存储在列表列表中。我们可以简单地显示上述控制台输出,如下所示:
轮廓1轮廓2轮廓3
],array(],array(],
],],],
],],],
…,…,…,
],],],
],],],
]],dtype = int32),]],dtype = int32),]],dtype = int32)]
现在,当我们在轮廓文件上使用长度函数时,我们得到的长度等于3,这意味着该文件中有三个列表列表,即三个轮廓。
现在,假设CONTOUR 1是该数组中的第一个元素,并且该列表包含所有坐标的列表,并且这些坐标是沿着我们刚看到的轮廓的点,即绿色矩形框。
存储这些坐标的方法不同,这些方法称为近似方法,基本上,近似方法有两种类型
- cv2.CHAIN_APPROX_NONE
- cv2.CHAIN_APPROX_SIMPLE
cv2.CHAIN_APPROX_NONE存储所有边界点,但是我们不一定需要所有边界点,如果该点形成一条直线,我们只需要该线上的起点和终点即可。
cv2.CHAIN_APPROX_SIMPLE只提供边界轮廓的起点和终点,结果是轮廓信息的存储效率更高。
_,轮廓,层次结构= cv2.findContours(镶边,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
在上面的代码中, cv2.RETR_EXTERNAL 是检索模式,而 cv2.CHAIN_APPROX_NONE 是
近似方法。
因此,我们了解了轮廓和逼近方法,现在让我们探索层次结构和检索模式。
2.层次结构和检索模式
检索模式在子轮廓或外部轮廓或所有轮廓中定义轮廓层次。
现在,根据层次结构类型有四种检索模式。
cv2.RETR_LIST –检索所有轮廓。
cv2.RETR_EXTERNAL –仅检索外部或外部轮廓。
cv2.RETR_CCOMP –在2级层次结构中检索所有内容。
cv2.RETR_TREE –检索完整层次结构中的所有内容。
层次结构以以下格式存储
现在让我们说明前两种检索模式cv2.RETR_LIST和cv2.RETR_EXTERNAL之间的区别。
导入cv2 导入numpy作为np
让我们加载带有3个黑色正方形的简单图像
image = cv2.imread('square donut.jpg') cv2.imshow('input image',image) cv2.waitKey(0)
灰阶
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
查找Canny Edges
edged = cv2.Canny(灰色,30,200) cv2.imshow('canny edge',edged) cv2.waitKey(0)
寻找轮廓
#使用图像的副本,例如-edged.copy(),因为查找轮廓会改变图像 #由于开放的cv版本 _的 升级,轮廓必须作为空参数添加_,轮廓,层次结构= cv2.findContours(镶边,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)cv2.imshow('轮廓轮廓后的canny边缘',边缘) cv2.waitKey(0)
打印轮廓文件以了解轮廓组成。
print(轮廓) print('找到的轮廓数量='+ str(len(轮廓)))
绘制所有轮廓
#使用-1作为第三个参数绘制所有轮廓 cv2.drawContours(image,contours,-1,(0,255,0),3) cv2.imshow('contours',image) cv2.waitKey(0) cv2。 destroyAllWindows
导入cv2 导入numpy作为np
让我们加载带有3个黑色正方形的简单图像
image = cv2.imread('square donut.jpg') cv2.imshow('input image',image) cv2.waitKey(0)
灰阶
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
找到精巧的边缘
edged = cv2.Canny(灰色,30,200) cv2.imshow('canny edge',edged) cv2.waitKey(0)
寻找轮廓
#使用图像的副本,例如-edged.copy(),因为查找轮廓会改变图像 #由于开放的cv版本 _的 升级,轮廓必须作为空参数添加_,轮廓,层次结构= cv2.findContours(边缘,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)cv2.imshow('轮廓轮廓后的canny边缘',边缘) cv2.waitKey(0)
打印轮廓文件以了解轮廓包括什么。
print(轮廓) print('找到的轮廓数量='+ str(len(轮廓)))
绘制所有轮廓
#使用-1作为第三个参数绘制所有轮廓 cv2.drawContours(image,contours,-1,(0,255,0),3) cv2.imshow('contours',image) cv2.waitKey(0) cv2。 destroyAllWindows()
因此,通过上面的代码演示,我们可以清楚地看到 cv2.RETR_LIST 和 cv2.RETR_EXTERNNAL 之间的 差异 ,在cv2.RETR_EXTERNNAL中,仅考虑了外部轮廓,而忽略了内部轮廓。
在 cv2.RETR_LIST中, 内部轮廓也被考虑在内。
3.逼近轮廓并找到其凸包
在近似轮廓中,轮廓形状近似于另一轮廓形状,该另一轮廓形状可能与第一轮廓形状不太相似。
为近似 起见 ,我们使用openCV的 roxPolyDP 函数,如下所述
cv2.approxPolyDP(轮廓,近似精度,封闭)
参数:
- 轮廓–是我们希望近似的单个轮廓。
- 近似精度-确定近似精度的重要参数,较小的值给出精确的近似值,较大的值给出更多的通用信息。好的拇指法则应小于轮廓周长的5%。
- 闭合-布尔值,指示近似轮廓可以打开还是闭合。
让我们尝试近似房子的简单图
导入numpy作为np 导入cv2
加载图像并保留副本
image = cv2.imread('house.jpg') orig_image = image.copy() cv2.imshow('original image',orig_image) cv2.waitKey(0)
灰度和二值化图像
灰色= cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY) ret,脱粒= cv2。阈值(灰色,127,255,cv2.THRESH_BINARY_INV)
查找轮廓
_,轮廓,层次结构= cv2.findContours(thresh.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
遍历每个轮廓并计算其边界矩形
对于轮廓中的c: x,y,w,h = cv2.boundingRect(c) cv2.rectangle(orig_image,(x,y),(x + w,y + h),(0,0,255),2) cv2.imshow('边界矩形',orig_image) cv2.waitKey(0)
遍历每个轮廓并计算近似轮廓
对于轮廓中的c:
#以轮廓周长的百分比计算 精度= 0.03 * cv2.arcLength(c,True) 大约= cv2.approxPolyDP(c,accuracy,True) cv2.drawContours(image,, 0,(0,255,0),2) cv2.imshow('Approx polyDP',图片) cv2.waitKey(0) cv2.destroyAllWindows()
4.凸包
凸包基本上是外边缘,由给定图形上的画线表示。
它可能是可以围绕对象本身的最小多边形。
导入cv2 将numpy导入为np image = cv2.imread('star.jpg') 灰色= cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) cv2.imshow('原始图像',图像) cv2.waitKey(0)
图像阈值
ret,thresh = cv2.threshold(gray,176,255,0)
查找轮廓
_,轮廓,层次结构= cv2.findContours(thresh.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
按区域对轮廓进行排序,然后删除最大的框架轮廓
n = len(轮廓)-1 轮廓=已排序(轮廓,关键= cv2.contourArea,反向=假)
遍历轮廓并绘制凸包
对于轮廓中的c:
hull = cv2.convexHull(c) cv2.drawContours(image,, 0,(0,255,0),2) cv2.imshow('convex hull',image) cv2.waitKey(0) cv2.destroyAllWindows()
5.按形状匹配轮廓
cv2.matchShapes(轮廓模板,轮廓方法,方法参数)
输出–匹配值(较低的值表示更接近的匹配)
轮廓模板–这是我们要在新图像中尝试找到的参考轮廓。
轮廓–我们要检查的单个轮廓。
方法–轮廓匹配的类型(1,2,3)。
方法参数-保留为0.0(在python opencv中未使用)
导入cv2 导入numpy作为np
加载形状模板或参考图像
template = cv2.imread('star.jpg',0) cv2.imshow('template',template) cv2.waitKey(0)
使用我们尝试匹配的形状加载目标图像
target = cv2.imread('shapestomatch.jpg') gray = cv2.cvtColor(target,cv2.COLOR_BGR2GRAY)
在使用 cv2.findContours 之前先对两个图像进行阈值 处理
ret,thresh1 = cv2.threshold(模板,127,255,0) ret,thresh2 = cv2.threshold(灰色,127,255,0)
在模板中查找轮廓
_,contours,hierarhy = cv2.findContours(thresh1,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE) #我们需要按区域对轮廓进行排序,因此我们可以删除最大的轮廓
图片轮廓
sorted_contours = sorted(contours,key = cv2.contourArea,reverse = True) #我们提取第二大轮廓,将其作为模板轮廓 tempelate_contour = contours #从第二个目标图像 _,contours,hierarchy = cv2.findContours中提取轮廓(thresh2,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE) 在轮廓中使用c: #遍历目标图像中的每个轮廓,并使用cv2.matchShape比较轮廓形状 match = cv2.matchShapes(tempelate_contour,c,1,0.0) 打印(“匹配”) #如果匹配值小于0.15, 并且如果match <0.16: 最近的轮廓= c 否则: 最近的轮廓= cv2.drawContours(target,,-1,(0,255,0),3)cv2.imshow('output' ,目标) cv2.waitKey(0) cv2.destroyAllWindows()
控制台输出–
0.16818605122199104
0.19946910256158912
0.18949760627309664
0.11101058276281539
有三种不同的方法具有不同的数学函数,我们可以通过只更换cv2.matchShapes(tempelate_contour,C,其中每个方法试验1,0.0)的方法,其从1,2和3而变化的值,对于每一个值,你会得到不同的匹配控制台输出中的值。
6.识别形状(圆形,矩形,三角形,正方形,星形)
OpenCV还可以用于从图像自动检测不同类型的形状。通过使用以下代码,我们将能够从图像中检测出圆形,矩形,三角形,正方形和星形。
导入cv2 导入numpy作为np
加载然后灰度图像
image = cv2.imread('shapes.jpg') grey = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) cv2.imshow('identifying shape',image) cv2.waitKey(0) ret,thresh = cv2.threshold(gray) ,127,255,1)
提取轮廓
_,contours,hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
对于轮廓中的cnt:
如果len(approx)== 3 , 则 获取近似多边形rox = cv2.approxPolyDP(cnt,0.01 * cv2.arcLength(cnt,True),True):shape_name =“ Triangle” cv2.drawContours(image,, 0,(0,255, 0),-1)
查找轮廓中心以将文本放置在中心
M = cv2.moments(cnt) cx = int(M / M) cy = int(M / M) cv2.putText(image,shape_name,(cx-50,cy),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0 ,0),1) elif len(approx)== 4: x,y,w,h = cv2.boundingRect(cnt) M = cv2.moments(cnt) cx = int(M / M) cy = int(M / M)
检查四边多边形是正方形还是矩形
#cv2.boundingRect返回左宽度和高度(以像素为单位),从 左上角开始,对于正方形, 如果abs(wh)<= 3,则 大致相同:shape_name =“ square” #查找轮廓中心以将文本放置在中心 cv2.drawContours(image,, 0,(0,125,255),-1) cv2.putText(image,shape_name,(cx-50,cy),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,0),1) else : shape_name =“ Reactangle” #查找轮廓中心以将文本放置在中心 cv2.drawContours(image,, 0,(0,0,255),-1) M = cv2.moments(cnt) cx = int(M / M) cy = int(M / M) cv2.putText(image,shape_name,(cx-50,cy),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,0),1) elif len(approx)== 10: shape_name = '星' cv2.drawContours(image,, 0,(255,255,0),-1) M = cv2.moments(cnt) cx = int(M / M) cy = int(M / M) cv2.putText(image,shape_name, (cx-50,cy),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,0),1) elif len(approx)> = 15: shape_name =' circle'cv2.drawContours(image,, 0,(0,255,255) ,-1) M = cv2.moments(cnt) cx = int(M / M) cy = int(M / M) cv2.putText(image,shape_name,(cx-50,cy),cv2.FONT_HERSHEY_SIMPLEX,1, (0,0,0),1) cv2.imshow('identifying shape',image) cv2.waitKey(0) cv2.destroyAllWindows()
7.线路检测
线检测是OpenCV中非常重要的概念,在现实世界中具有广阔的应用前景。自动驾驶汽车使用线路检测算法来检测车道和道路。
在线检测中,我们将处理两种算法,
- 霍夫线算法
- 概率霍夫线算法。
您可能还记得高中数学中用y = mx + c表示的线的表示。
但是,在OpenCV中用另一种方式表示行
ρ=xcosӨ+ysincosӨ上的等式是直线的OpenCV表示,其中ρ是直线到原点的垂直距离,而Ө是该直线的法线到起点的夹角(以弧度为单位,其中1pi弧度/ 180 = 1度)。
用于检测线的OpenCV功能为
cv2.HoughLines(二值化图像,ρ准确度,Ө准确度,阈值), 其中threshold是将其视为直线的最小投票。
现在,借助opencv的霍夫线功能,为盒子图像检测线条。
import cv2 import numpy as np image = cv2.imread('box.jpg')
提取灰度和坎尼边缘
灰色= cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY) 边缘= cv2.Canny(灰色,100,170,apertureSize = 3)
使用1像素的rho精度运行霍夫线
#theta精度(np.pi / 180)为1度#行 阈值设置为240(行上的点数) lines = cv2.HoughLines(edges,1,np.pi / 180,240 )#我们进行迭代通过每一行并转换为cv2.lines所要求 的格式#(对于i而言, 需要端点)range(0,len(lines)):对于rho,theta行: a = np.cos(theta) b = np.sin(theta) x0 = a * rho y0 = b * rho x1 = int(x0 + 1000 *(-b)) y1 = int(y0 + 1000 *(a)) x2 = int(x0-1000 *( -b)) y2 = int(y0-1000 *(a)) cv2.line(image,(x1,y1),(x2,y2),(0,255,0),2) cv2.imshow('hough lines' ,image) cv2.waitKey(0) cv2.destroyAllWindows()
现在让我们用概率霍夫线的其他算法来重复上面的线检测。
概率霍夫线背后的想法是获取足以进行线检测的随机点子集。
概率霍夫线的OpenCV函数表示为 cv2.HoughLinesP(二进制图像,ρ精度,accuracy精度,阈值,最小行长,最大行间距)
现在,让我们借助概率霍夫线来检测框线。
导入cv2 导入numpy作为np
提取灰度和坎尼边缘
image = cv2.imread('box.jpg') gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) edge = cv2.Canny(gray,50,150,apertureSize = 3) #我们 再次 使用相同的rho和theta精度#但是我们指定最小表决100的(沿着线分)的5个像素#,然后分的线长和10条像素的行之间最大间隙 线= cv2.HoughLinesP(边缘,如图1所示,np.pi / 180,100,100,10) 对于i在range(0,len(lines))中: 对于x1,y1,x2,y2在以下行中: cv2.line(image,(x1,y1),(x2,y2),(0,255,0),3) cv2。 imshow('probalistic hough lines',image) cv2.waitKey(0) cv2.destroyAllWindows
8.斑点检测
斑点可以描述为一组共享相同属性的连接像素。通过此流程图描述了使用OpenCV Blob检测器的方法。
为了绘制关键点,我们使用 cv2.drawKeypoints ,它 带有 以下参数。
cv2.drawKeypoints(输入图像,关键点,blank_output_array,颜色,标志)
在标志可能在哪里
cv2.DRAW_MATCHES_FLAGS_DEFAULT
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG
cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
和空白这里是几乎没有,而是由零一个矩阵一个
现在,让我们对向日葵图像执行斑点检测,其中斑点将成为花朵的中心部分,因为它们在所有花朵中都很常见。
import cv2 import numpy as np image = cv2.imread('Sunflowers.jpg',cv2.IMREAD_GRAYSCALE)
使用默认参数设置检测器
detector = cv2.SimpleBlobDetector_create()
检测斑点
关键点= detector.detect(图像)
将检测到的斑点绘制为红色圆圈
#cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS确保 圆的 #大小对应于blob blank = np.zeros(((1,1)) blobs = cv2.drawKeypoints(image,keypoints,blank,(0,255,255),cv2.DRAW_MATCHES_FLAGS)的大小
显示重点
cv2.imshow('blobs',blobs) cv2.waitKey(0) cv2.destroyAllWindows()
即使该代码运行良好,但由于花朵大小不均而错过了一些斑点,因为前面的花朵比后面的花朵大。
9.过滤斑点–计算圆和椭圆
我们可以使用参数根据斑点的形状,大小和颜色对其进行过滤。对于使用Blob检测器的参数,我们使用OpenCV的功能
cv2.SimpleBlobDetector_Params()
我们将主要通过以下四个参数来过滤斑点:
区
params.filterByArea =真/假 params.minArea =像素 params.maxArea =像素
圆
params.filterByCircularity = True / False params.minCircularity = 1是完美的,0是相反的
凸度-斑点面积/凸包面积
params.filterByConvexity =正确/错误 params.minConvexity =面积
惯性
params.filterByInertia =真/假 params.minInertiaRatio = 0.01
现在让我们尝试通过上述参数过滤斑点
import cv2 import numpy as np image = cv2.imread('blobs.jpg') cv2.imshow('original image',image) cv2.waitKey(0)
使用默认参数初始化检测器
detector = cv2.SimpleBlobDetector_create()
检测斑点
关键点= detector.detect(图像)
在我们的图像上将斑点绘制为红色圆圈
blank = np.zeros((1,1)) blobs = cv2.drawKeypoints(image,keypoints,blank,(0,0,255),cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) number_of_blobs = len( keypoints )text =“总的斑点数” + str (len(关键点)) cv2.putText(blobs,text,(20,550),cv2.FONT_HERSHEY_SIMPLEX,1,(100,0,255),2)
显示带有Blob关键点的图像
cv2.imshow('使用默认参数的blob',blobs) cv2.waitKey(0)
设置我们的过滤参数
#使用cv2.SimpleBlobDetector params = cv2.SimpleBlobDetector_Params()初始化参数设置
设置区域过滤参数
params.filterByArea =真实的 params.minArea = 100
设置圆度过滤参数
params.filterByCircularity =真实的 params.minCircularity = 0.9
设置凸度过滤参数
params.filterByConvexity =假 params.minConvexity = 0.2
设置惯性滤波参数
params.filterByInertia =真实的 params.minInertiaRatio = 0.01
使用参数创建检测器
detection = cv2.SimpleBlobDetector_create(params)
检测斑点
关键点= detector.detect(图像)
在图像上将斑点绘制为红色圆圈
blank = np.zeros(((1,1)) blobs = cv2.drawKeypoints(image,keypoints,blank,(0,255,0),cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) number_of_blobs = len( keypoints )text =“圆形斑点总数” + str(len(关键点)) cv2.putText(斑点,文本,(20,550),cv2.FONT_HERSHEY_SIMPLEX,1,(0,100,255),2)
显示斑点
cv2.imshow('过滤圆形斑点',斑点) cv2.waitKey(0) cv2.destroyAllWindows()
因此,这就是可以在Python-OpenCV中完成图像分割的方法。为了更好地了解计算机视觉和OpenCV,请阅读之前的文章(Python OpenCV入门和Python OpenCV中的图像处理入门,您将能够使用Computer Vision做出一些很棒的事情。