一、轮廓发现原理
轮廓发现是在图像边缘提取的基础上寻找对象轮廓的方法,故边缘提取的阈值的选定会影响到最终轮廓发现的结果。
其本质是基于二值图像的,边缘提取常用Canny进行提取边缘
轮廓发现也是基于拓扑结构,扫描连通图,最后建立其树形结构的拓扑图
通常情况可以利用梯度来避免阈值的错误设定
二、代码实现
cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
binary:二值图像
cv2.RETR_TREE:二值图像返回结果构建模型的方法,即构建轮廓的方法,返回树形结构
cv2.CHAIN_APPROX_SIMPLE:一般为简单的返回形式
cloneImage:克隆图片信息,可忽略
contours:存放返回轮廓信息,最有用
heriachy :存放轮廓层次信息,可忽略
cv2.drawContours(image,contours,i,(0,0,255),2)
image:图像信息
contours:存放轮廓信息,绘制哪个轮廓,会从contours中找
(0,0,255):绘制轮廓的颜色
2:绘制轮廓的线宽
import cv2
import numpy as np
from matplotlib import pyplot as pltdef contour(image):gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)#先转换为灰度图ret,binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)#二值化cv2.imshow("binary image",binary)cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)for i,contour in enumerate(contours):cv2.drawContours(image,contours,i,(0,0,255),2)print(i)cv2.imshow("detect contours",image)src = cv2.imread(r"G:\Juptyer_workspace\study\opencv\opencv3\calc.jpg")
cv2.imshow("image",src)
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)
contour(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下:
三、加上滤波代码实现
cv2.GaussianBlur(image,(3,3),0)
高斯滤波,卷积核大小为3*3
import cv2
import numpy as np
from matplotlib import pyplot as pltdef contour(image):dst = cv2.GaussianBlur(image,(3,3),0)gray = cv2.cvtColor(dst,cv2.COLOR_BGR2GRAY)#先转换为灰度图ret,binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)#二值化cv2.imshow("binary image",binary)cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)for i,contour in enumerate(contours):cv2.drawContours(image,contours,i,(0,0,255),2)print(i)cv2.imshow("detect contours",image)src = cv2.imread(r"G:\Juptyer_workspace\study\opencv\opencv3\calc.jpg")
cv2.imshow("image",src)
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)
contour(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下:
四、找大轮廓
cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.RETR_EXTERNAL:返回最大轮廓结果
import cv2
import numpy as np
from matplotlib import pyplot as pltdef contour(image):dst = cv2.GaussianBlur(image,(3,3),0)gray = cv2.cvtColor(dst,cv2.COLOR_BGR2GRAY)#先转换为灰度图ret,binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)#二值化cv2.imshow("binary image",binary)cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)for i,contour in enumerate(contours):cv2.drawContours(image,contours,i,(0,0,255),2)print(i)cv2.imshow("detect contours",image)src = cv2.imread(r"G:\Juptyer_workspace\study\opencv\opencv3\calc.jpg")
cv2.imshow("image",src)
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)
contour(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下:
五、填充轮廓
cv2.drawContours(image,contours,i,(0,0,255),-1)
最后一个参数为绘制轮廓线段的宽度,-1表示填充
import cv2
import numpy as np
from matplotlib import pyplot as pltdef contour(image):dst = cv2.GaussianBlur(image,(3,3),0)gray = cv2.cvtColor(dst,cv2.COLOR_BGR2GRAY)#先转换为灰度图ret,binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)#二值化cv2.imshow("binary image",binary)cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)for i,contour in enumerate(contours):cv2.drawContours(image,contours,i,(0,0,255),-1)print(i)cv2.imshow("detect contours",image)src = cv2.imread(r"G:\Juptyer_workspace\study\opencv\opencv3\calc.jpg")
cv2.imshow("image",src)
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)
contour(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下:
六、Canny提取轮廓
import cv2
import numpy as np
from matplotlib import pyplot as pltdef edge(image):blurred = cv2.GaussianBlur(image,(3,3),0)gray = cv2.cvtColor(blurred,cv2.COLOR_BGR2GRAY)xgrad = cv2.Sobel(gray,cv2.CV_16SC1,1,0)#x Gradientygrad = cv2.Sobel(gray,cv2.CV_16SC1,0,1)#y Gradientedge_output = cv2.Canny(gray,50,150)cv2.imshow("Canny Edge",edge_output)return edge_outputdef contour(image):binary = edge(image)cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)for i,contour in enumerate(contours):cv2.drawContours(image,contours,i,(0,0,255),-1)print(i)cv2.imshow("detect contours",image)src = cv2.imread(r"G:\Juptyer_workspace\study\opencv\opencv3\calc.jpg")
cv2.imshow("image",src)
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)
contour(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下:
七、若寻找轮廓寻找到图像最外边缘,取反一下即可
import cv2
import numpy as np
from matplotlib import pyplot as pltdef contour(image):dst = cv2.GaussianBlur(image,(3,3),0)gray = cv2.cvtColor(dst,cv2.COLOR_BGR2GRAY)#先转换为灰度图ret,binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)#二值化cv2.imshow("binary image",binary)cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)for i,contour in enumerate(contours):cv2.drawContours(image,contours,i,(0,0,255),2)print(i)cv2.imshow("detect contours",image)src = cv2.imread(r"G:\Juptyer_workspace\study\opencv\opencv3\by.jpg")
cv2.imshow("image",src)
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)
contour(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下:
解决方法:cv2.THRESH_BINARY_INV
import cv2
import numpy as np
from matplotlib import pyplot as pltdef contour(image):dst = cv2.GaussianBlur(image,(3,3),0)gray = cv2.cvtColor(dst,cv2.COLOR_BGR2GRAY)#先转换为灰度图ret,binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)#二值化cv2.imshow("binary image",binary)cloneImage,contours,heriachy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)for i,contour in enumerate(contours):cv2.drawContours(image,contours,i,(0,0,255),2)print(i)cv2.imshow("detect contours",image)src = cv2.imread(r"G:\Juptyer_workspace\study\opencv\opencv3\by.jpg")
cv2.imshow("image",src)
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)
contour(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果图如下: