本篇博客记录学习OpenCV图像处理中的轮廓检测。
轮廓可以简单地认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
我们如何在一个二值图像中查找轮廓呢,当然是cv2.findContours()啦:
该函数有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个Python列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个Numpy 数组,包含对象边界点(x,y)的坐标。
轮廓检索模式:
我们经常用的是最后标红的一种。
轮廓近似方法(对所有节点, 不包括使用内部逼近的 CV_RETR_RUNS). 点的存贮情况,是不是都被存贮:
函数cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一个Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设置为-1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。
示例代码:
# -*- coding: utf-8 -*-
# @Time : 2019/10/27 9:19
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 轮廓检测.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def contours_demo(image):
# dst = cv.GaussianBlur(image, (3, 3), 0)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)
# cv.imshow("thresh image", thresh)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) # OpenCV 新版调用,返回两个参数
draw_img = src.copy() # drawContours函数返回值会将原图像覆盖,因此在做处理时先copy一份原图像
res = cv.drawContours(draw_img, contours, -1, (0, 0, 255), 2) # 颜色通道为BGR
cv.imshow("res", res)
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/contours.png") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
contours_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
res = cv.drawContours(draw_img, contours, 0, (0, 0, 255), 2) # 颜色通道为BGR,将这行代码的第三个参数改为0,是以下结果,是六边形的外部,(在不越界的情况下,可以修改其他值看看效果):
接下来我们换一张图片进行测试:
如果我们直接用上面的程序进行测试,会发现如下结果,找不到路轮廓:
这个时候就需要我们修改一些参数。
修改代码如下:
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
contours, hierarchy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE) # OpenCV 新版调用,返回两个参数
运行结果如下:
我们会发现这个结果不是我们想要的,我们加入一个高斯滤波,将一些噪点去除,修改代码如下:
# -*- coding: utf-8 -*-
# @Time : 2019/10/27 9:19
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 轮廓检测.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def contours_demo(image):
dst = cv.GaussianBlur(image, (1, 1), 0)
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# cv.imshow("thresh image", thresh)
contours, hierarchy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE) # OpenCV 新版调用,返回两个参数
draw_img = src.copy() # drawContours函数返回值会将原图像覆盖,因此在做处理时先copy一份原图像
res = cv.drawContours(draw_img, contours, -1, (0, 0, 255), 2) # 颜色通道为BGR
cv.imshow("res", res)
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/circle.png") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
contours_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
运行结果:
如果我们将这行代码的最后一个参数改为-1,他会进行填充。
res = cv.drawContours(draw_img, contours, -1, (0, 0, 255), -1) # 颜色通道为BGR
接下来我们用我们之前学过的Canny检测来提取二值化图像看看效果。
# -*- coding: utf-8 -*-
# @Time : 2019/10/27 9:19
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 轮廓检测.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def edge_demo(image):
blurred = cv.GaussianBlur(image, (3, 3), 0)
gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
grad_x = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
grad_y = cv.Sobel(gray, cv.CV_16SC1, 0, 1)
# edge_output = cv.Canny(grad_x, grad_y, 30, 150)
edge_output = cv.Canny(gray, 50, 150)
return edge_output
def contours_demo(image):
"""
dst = cv.GaussianBlur(image, (1, 1), 0)
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# cv.imshow("thresh image", thresh)
"""
thresh = edge_demo(image)
contours, hierarchy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE) # OpenCV 新版调用,返回两个参数
draw_img = src.copy() # drawContours函数返回值会将原图像覆盖,因此在做处理时先copy一份原图像
res = cv.drawContours(draw_img, contours, -1, (0, 0, 255), 2) # 颜色通道为BGR
cv.imshow("res", res)
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/circle.png") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
contours_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
我们可以修改一下参数达到更好的效果。
# -*- coding: utf-8 -*-
# @Time : 2019/10/27 9:19
# @Author : MMagicLoren
# @Email : [email protected]
# @File : 轮廓检测.py
# @Software: PyCharm
import cv2 as cv
import numpy as np
def edge_demo(image):
blurred = cv.GaussianBlur(image, (7, 7), 0)
gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
grad_x = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
grad_y = cv.Sobel(gray, cv.CV_16SC1, 0, 1)
edge_output = cv.Canny(gray, 150, 255)
return edge_output
def contours_demo(image):
"""
dst = cv.GaussianBlur(image, (1, 1), 0)
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# cv.imshow("thresh image", thresh)
"""
thresh = edge_demo(image)
contours, hierarchy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE) # OpenCV 新版调用,返回两个参数
draw_img = src.copy() # drawContours函数返回值会将原图像覆盖,因此在做处理时先copy一份原图像
res = cv.drawContours(draw_img, contours, -1, (0, 0, 255), 2) # 颜色通道为BGR
cv.imshow("res", res)
if __name__ == '__main__':
src = cv.imread("F:/Pycharm/opencv_exercises-master/images/circle.png") # 读入图片放进src中
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE) # 创建窗口, 窗口尺寸自动调整
cv.imshow("input image", src)
contours_demo(src)
cv.waitKey(0) # 等有键输入或者1000ms后自动将窗口消除,0表示只用键输入结束窗口
cv.destroyAllWindows()
今天就分享到这了,下次分享轮廓检测的特征。