在计算机视觉中,轮廓检测是一个比较重要的任务
还有一些相关的操作:计算多边形边界、形态逼近和计算感兴趣区域,后面再慢慢研究。。。
先来初步尝试下轮廓检测
检测前,先对图像进行处理
- 图像二值化
图像二值化( Image Binarization)就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程。在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。
-
threshold 固定阈值二值化
def threshold(src, thresh, maxval, type, dst=None)
其中:
src: 输入图,只能输入单通道图像,通常来说为灰度图
thresh:设定的阈值
maxval: 当灰度值大于或小于阈值时,将灰度值赋成的值
type: 二值化的方式
可以有的方式有:
cv2.THRESH_BINARY = 0 大于阈值的部分被置为255,小于部分被置为0
cv2.THRESH_BINARY_INV = 1 大于阈值部分被置为0,小于部分被置为255
cv2.THRESH_MASK = 7
cv2.THRESH_OTSU = 8
cv2.THRESH_TOZERO = 3 小于阈值部分被置为0,大于部分保持不变
cv2.THRESH_TOZERO_INV = 4 大于阈值部分被置为0,小于部分保持不变
cv2.THRESH_TRIANGLE = 16
cv2.THRESH_TRUNC = 2 大于阈值部分被置为thresh,小于部分保持原样
看看有些啥效果。。。
import cv2
import matplotlib.pyplot as plt
#灰度读取
img = cv2.imread('img/Lena.jpg', cv2.IMREAD_GRAYSCALE)
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_MASK)
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_OTSU)
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret, thresh6 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
ret, thresh7 = cv2.threshold(img, 127, 255, cv2.THRESH_TRIANGLE)
ret, thresh8 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
titles = ['img', 'BINARY','BINARY_INV','MASK','OTSU','TOZERO','TOZERO_INV','TRIANGLE','TRUNC']
imgs = [img,thresh1,thresh2,thresh3,thresh4,thresh5,thresh6,thresh7,thresh8]
for i in range(9):
plt.subplot(3,3,i+1),plt.imshow(imgs[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
补充一直二值化的图,THRESH_OTSU
-
adaptiveThreshold 自适应阈值二值化
自适应阈值可以看成一种局部性的阈值,通过规定一个区域大小,比较这个点与区域大小里面像素点的平均值(或者其他特征)的大小关系确定这个像素点的阈值
def adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None)
其中:
src: 输入图,只能输入单通道图像,通常来说为灰度图
maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
adaptiveMethod: 自适应计算方法: cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值
cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和
thresholdType: 二值化的方式 cv2.THRESH_BINARY 和cv2.THRESH_BINARY_INV
blockSize: 规定区域大小
C: 常数C,阈值等于均值或者加权值减去这个常数
返回值只有一个
thresh1 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)
thresh2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY_INV,11,2)
thresh3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
thresh4 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,11,2)
titles = ['img', 'MEAN_C','MEAN_C_INV','GAUSSIAN_C','GAUSSIAN_C_INV']
imgs = [img,thresh1,thresh2,thresh3,thresh4]
for i in range(5):
plt.subplot(3,3,i+1),plt.imshow(imgs[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
-
cv2.findContours() 寻找图像的轮廓
def findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
其中:
image:输入图像(会被修改),要求是二值图像
mode:轮廓的检索模式:
cv2.RETR_EXTERNAL | 只检测外轮廓 |
cv2.RETR_LIST | 检测的轮廓不建立等级关系 |
cv2.RETR_CCOMP | 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层 |
cv2.RETR_TREE | 建立一个等级树结构的轮廓 |
method:轮廓近似办法
cv2.CHAIN_APPROX_NONE | 存储所有的轮廓点,相邻的两个点的像素位置差不超过1 |
cv2.CHAIN_APPROX_SIMPLE | 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标 |
cv2.CHAIN_APPROX_TC89_L1 | 使用teh-Chini近似算法 |
CV_CHAIN_APPROX_TC89_KCOS | 使用teh-Chini近似算法 |
返回值:轮廓数据,轮廓对应的属性
-
cv2.drawContours() 绘制轮廓
def drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
其中:
image:输入/输出图像,指明在哪个图像上绘制轮廓。并且该函数会修改源图像image。
contours:使用findContours检测到的轮廓数据
contourIdx:绘制轮廓的索引变量(表示绘制第几个轮廓),如果为负值则绘制所有输入轮廓。
color:轮廓颜色。
thickness:绘制轮廓所用线条粗细度,如果值为负值,则在轮廓内部绘制。
lineTpye:线条类型,有默认值LINE_8
hierarchy:可选层次结构信息
maxLevel:用于绘制轮廓的最大等级。
offset:轮廓偏移参数,用制定偏移量offset=(dx, dy)给出绘制轮廓的偏移量。
做个例子将上面的方法连贯起来
生成图片——二值化——查找轮廓——绘制轮廓
img = np.zeros((400,400), dtype=np.uint8)
img[50:300,50:100] = 255
img[150:200,50:200] = 255
img[50:300, 150:200] = 255
img[150:200,250:300] = 255
绘制几个方框,设置为白色
ret, thresh = cv2.threshold(img, 127, 255, 0)
# cv2.THRESH_BINARY = 0
image, contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
color = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
img = cv2.drawContours(color, image, -1, (0,255,0), 2)
cv2.imshow('color', color)
成功标记处轮廓。。。。
-
换个图片试试
img = cv2.imread('img/mei.jpg',cv2.IMREAD_COLOR)
cv2.imshow('img', img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (11,11), 0)
ret, thresh = cv2.threshold(gray, 127, 255, 0)
image, contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(img, image, -1, (0,255,0), 2)
cv2.imshow('color', img)
百度图片里面找了张妹子图。。。 测试下。。。 感觉还是有点菜啊。。。。 有待继续研究。。。。