边缘是零零散散的,而轮廓是一个整体
cv2.findContours(img,mode,method)
img:输入图像对象名称
mode:轮廓检索模式
RETR_EXTERNAL:只检索最外面的轮廓
RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中
RETR_CCOMP:检索所有的轮廓,并将他们组织为两层;顶层是各部分的外部边界,第二层为空洞的边界
RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次(最常用)
method:轮廓逼近方法
CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)
CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分
为了更高的精确率,尽量最好使用二值图像
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()#做之前需要对照片进行二值处理
img = cv2.imread('E:\Jupyter_workspace\study\data/cfx.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
show_photo('thresh',thresh)binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)show_photo('binary',binary)#就是作完二值操作的结果np.array(contours).shape#是一群list结构的轮廓点,保存一些轮廓的信息
#结果为:(2,)#hierarchy是一个层级,把结果全部保存到层级里面
二值处理后的图像
binary参数实则就是二值处理后的图像
绘制轮廓
cv2.drawContours(draw_img,contours,-1,(0,0,255),2)
参数1:一个照片对象名称
参数2:轮廓是什么
参数3:画第几个轮廓,-1表示把所有的轮廓都画出来
参数4:(B,G,R)画轮廓的线是什么颜色的
参数5:线条的宽度
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()#做之前需要对照片进行二值处理
img = cv2.imread('E:\Jupyter_workspace\study\data/cfx.png')
show_photo('img ',img )gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)draw_img = img.copy()#注意一定要copy要不然会对原图进行改变!!!
res = cv2.drawContours(draw_img,contours,-1,(0,0,255),2)#-1表示显示所有轮廓,(0,0,225)BGR表示红色,2为轮廓粗细
show_photo('-1 is All',res)draw_img = img.copy()#注意一定要copy要不然会对原图进行改变!!!
res = cv2.drawContours(draw_img,contours,0,(0,0,255),2)#0表示显示第0个轮廓,(0,0,225)BGR表示红色,2为轮廓粗
show_photo('zero',res)draw_img = img.copy()#注意一定要copy要不然会对原图进行改变!!!
res = cv2.drawContours(draw_img,contours,1,(0,0,255),2)#1表示显示第1个轮廓,(0,0,225)BGR表示红色,2为轮廓粗
show_photo('one',res)
原图:
显示所有轮廓(里外)
显示第0个轮廓(外)
显示第1个轮廓(内)
轮廓特征
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/cfx.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)cnt = contours[0]#contours存放所有轮廓的信息,这里取第一个轮廓cv2.contourArea(cnt)#第一个轮廓所对应的面积
#结果为:20909.0cv2.arcLength(cnt,True)#第一个轮廓所对应的周长,True表示闭合的
#结果为:612.0
轮廓近似
轮廓近似:举例子拿曲线AB进行近似计算
1,首先直线连接AB,再曲线AB上找到离AB直线最远的一点C,点C到直线AB的距离为d1
2,用户需要自定义一个值epsilon作为阈值
3,将d1与阈值epsilon进行比较;若d1 < epsilon可直接将直线AB代替曲线AB,近似结束若d1 > epsilon则,连接直线AC和直接BC在曲线AC上找离直线AC最短的一点D,点D到直线AC的距离为d2若d2 < epsilon可直接将直线AC代替曲线AC若d2 > epsilon则做同样的操作在曲线BC上找离直线BC最短的一点E,点E到直线BC的距离为d3同样的操作
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo.png')
show_photo('img ',img )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),2)
show_photo('res',res)
原图:
轮廓近似后效果
近似函数:
cv2.approxPolyDP(cnt,epsilon,True)
参数1:传入要近似的轮廓
参数2:自定义一个值来进行轮廓比较,一般是按周长的百分比进行设置的
参数3:轮廓是否封闭
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo.png')
show_photo('img ',img )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)epsilon = 0.1*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)
show_photo('res',res)
原图:
近似函数处理过后的图像:
边界矩形
获得轮廓的边缘矩形:cv2.boundingRect(cnt)
参数:指定操作的对象是哪个轮廓
返回值:轮廓对应的边缘矩形的x,y坐标和w,h宽高值
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo1.png')
show_photo('img',img)#原图gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
res, 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]#这里的轮廓取得是第0个,当然也可以取其他的轮廓x, y, w, h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
show_photo('img',img)area = cv2.contourArea(cnt)#轮廓面积
x, y, w, h = cv2.boundingRect(cnt)
rect_area = w * h #轮廓对应的边缘矩形的面积,宽×高为对应边缘矩形的面积
extent = float(area) / rect_area
print('轮廓面积与边界矩形之比',extent)
#结果为:轮廓面积与边界矩形之比 0.5113636363636364
原图:
获取第0个轮廓边界矩形:
外接圆
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo1.png')
show_photo('img',img)gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
res, 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]#对轮廓0操作,当然也可以换成其他的轮廓x, y, w, h = cv2.boundingRect(cnt)
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)#(B,G,R),2为轮廓粗细程度
show_photo('img',img)
原图:
对第0轮廓进行外接圆操作: