前置知识:
①cv2.findContours用于在二值化图像中寻找轮廓
②cv2.drawContours能够根据cv2.findContours找到的轮廓在图像中画出轮廓
前情提要:
笔者想要处理图像,正确的画出其轮廓,但画出的轮廓是错误的。以下为图像原图
一、错误代码及运行结果
错误代码如下:
import cv2
def show_picture(title,picture):
"""显示图像,按任意键退出"""
cv2.imshow(f'{title}',picture)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 读入图像
img = cv2.imread('right_xia.PNG')
# 转为灰度图
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 二值化【就是这里导致的问题!!!】
ret, thresh = cv2.threshold(gray_img, 200, 255, cv2.THRESH_BINARY)
# 定卷积核
element = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
# 开运算,消除黑图中小白点
open_img = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, element)
# 在二值化图像中寻找轮廓
contours, hierarchy = cv2.findContours(open_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 在原图的副本中画出轮廓
res = cv2.drawContours(img.copy(), contours, 0, ( 0, 0, 255), 2)
# 展示画完轮廓的图像
show_picture('contour_img', res)
二值化后的图像:
画完轮廓后的图像:
可以见到画出的轮廓是错误的,把整个图像窗口的白色部分都包进去了
二、原因
# 二值化【就是这里导致的问题!!!】
ret, thresh = cv2.threshold(gray_img, 200, 255, cv2.THRESH_BINARY)
此处的二值化,将像素值>200的点都变为像素值255(黑色),将其余像素点都变为像素值0(白色)
而cv2.findContours寻找的轮廓,是“白色”图像的轮廓,而在此处错误代码中,错误的将图像处理为黑色,背景处理为白色。因此,寻找到的轮廓错误。
三、解决办法
修改二值化的参数(将 cv2.THRESH_BINARY_INV 改为 cv2.THRESH_BINARY ),修改后的代码如下:
# 二值化【修改后的正确代码】
ret, thresh = cv2.threshold(gray_img, 200, 255, cv2.THRESH_BINARY_INV)
此时的二值化,是将图像处理为白色,背景处理为黑色,正确的满足了cv2.findContours的要求。
四、解决问题后的完整代码运行结果
完整代码:
import cv2
def show_picture(title,picture):
"""显示图像,按任意键退出"""
cv2.imshow(f'{title}',picture)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 读入图像
img = cv2.imread('right_xia.PNG')
# 转为灰度图
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 二值化【修改后的正确代码】
ret, thresh = cv2.threshold(gray_img, 200, 255, cv2.THRESH_BINARY_INV)
# 定卷积核
element = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
# 闭运算,消除黑图中小白点
close_img = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, element)
# 在二值化图像中寻找轮廓
contours, hierarchy = cv2.findContours(close_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 在原图的副本中画出轮廓
res = cv2.drawContours(img.copy(), contours, 0, ( 0, 0, 255), 2)
# 展示画完轮廓的图像
show_picture('contour_img', res)
二值化后图像:
画出正确轮廓的图像:
可以见到此时画出的轮廓是正确的,将所求图像全部包裹在内。