使用Python,OpenCV进行基本的图像处理——提取红色圆圈轮廓并绘制
Posted 程序媛一枚~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Python,OpenCV进行基本的图像处理——提取红色圆圈轮廓并绘制相关的知识,希望对你有一定的参考价值。
写这篇博客源于博友的提问,想提取图片中的红色圆圈坐标,并绘制封闭的轮廓。
看到这个首先有几个解决思路:
1. 霍夫圆提取
2. 圆圈均是红色,可以转换HSV色彩空间提取
3. 应用一系列图像处理:灰度图、形态学操作、阈值化进行简单提取
一个一个尝试,霍夫圆不是很理想,调整了参数,也没有全部提取到,只提取到了部分。
HSV色彩空间提取红色,因为对红色的HSV范围设置的不够合理,效果也不是很好。
还是使用一系列图像处理,得到了比较理想的结果。
1. 效果图
检测原始图 VS 效果图如下:
可以看到右图中,轮廓被用闭合的绿色轮廓连接起来。
检测过程1——原图 VS 剪裁后图如下:
- 裁剪后图:忽略边界坐标轴对轮廓提取的影响;
检测过程2—— 灰度图 VS 白帽图 VS 梯度图 VS 形态学闭合图如下:
- 灰度图:忽略色彩影响;
- 白帽图:从较暗的背景中提取较亮的区域
- 梯度图:计算Schaar梯度图,使用梯度来检测图像中的边缘,更好的在图像中找到对象的轮廓和边缘线;
- 形态学闭合图:矩形框形态学闭合操作,以帮助闭合轮廓间小的缝隙
检测过程3——形态学闭合图 VS 二值化图1 VS 阈值化图2 如下:
- 二值化图:使得图像以白色前景和黑色背景呈现,以便于轮廓提取
- 阈值化图:方形框形态学闭合操作,以二次帮助闭合小的缝隙
识别过程3——轮廓过滤图 VS 提取最终效果图 如下:
轮廓过滤图:根据面积只保留够大的轮廓图(截取完的图片只包含俩个轮廓,无需过滤,用原始图则需要过滤)
最终效果图:俩个大的轮廓被成功提取
绘制检测到的轮廓的组成点为蓝色空心圆形,绘制轮廓为绿色矩形。
检测结果——裁剪后图检测效果图 VS 原图直接检测效果图对比:
可以看到当直接使用原图进行上述检测,坐标轴边界会有干扰,结果中会检测出多余的轮廓。
2. 源码
# 提取圆圈的轮廓,并绘制
import cv2
import imutils
import numpy as np
# 初始化矩形和方形结构内核
# 在图像上滑动它来进行(卷积)操作,如模糊、锐化、边缘检测或其他图像处理操作。
# 使用矩形函数作为Top-hat形态学运算符,使用方形函数作为闭合运算。
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 加载输入图像,转换为灰度图
origin = cv2.imread('images/circle.png')
image = origin.copy()
width = 75
height = 34
# # 只截取有轮廓的区域,避免坐标轴线等干扰
image = image[height:369, width:512]
cv2.imshow("origin", origin)
cv2.imshow("crop", image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
# 执行形态学操作
# 应用tophat(白帽)形态学操作以在暗的背景中提取出亮的区域
# Top hat操作在深色背景(即信用卡号)下显示浅色区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv2.imshow("tophat", tophat)
# 计算Scharr梯度,计算梯度值
# 在白色礼帽上,计算x方向的Scharr梯度,然后缩放到范围[0, 255]
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
# 最小/最大归一化, 由float转换gradX到uint8范围[0-255]
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")
cv2.imshow("gradient", gradX)
# 使用矩形框应用闭合操作以帮助闭合信用卡数字之间的小的缝隙
# 应用Otsu's阈值方法二值化图像
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv2.imshow("morphologyEx", gradX)
thresh = cv2.threshold(gradX, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("thresh1", thresh)
# 在二值化图像上,应用二次闭合操作
# 再一次方形框形态学操作,帮助闭合小的的缝隙
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
cv2.imshow("thresh2", thresh)
# 阈值图像中查找轮廓,然后初始化数字位置列表
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
print(len(cnts))
img = image.copy()
# 遍历轮廓
for (i, c) in enumerate(cnts):
area = cv2.contourArea(c)
print(i, area)
# 根据面积过滤掉不符合的轮廓
if (area < 4000):
continue
# print(' c: ', type(c), c.shape, c[0], type([c]))
cc = c.copy()
cc[:, :, 0] += width
cc[:, :, 1] += height
# print('cc: ', type(cc), cc.shape, cc[0])
for coor in c:
# 在轮廓的每个小圆上绘制蓝色圆圈
cv2.circle(img, (coor[0][0],coor[0][1]),5, (255, 0, 0), 1)
cv2.drawContours(origin, [cc], -1, (0, 255, 0), 2)
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
cv2.imshow("origin res", origin)
cv2.imshow("img res", img)
cv2.imshow("image res", image)
cv2.imwrite("images/crop_circle_extract.jpg",image)
cv2.waitKey(0)
以上是关于使用Python,OpenCV进行基本的图像处理——提取红色圆圈轮廓并绘制的主要内容,如果未能解决你的问题,请参考以下文章
Python 计算机视觉—— OpenCV 进行图像量化与采样