记录准研一小白第一次动手实践课题组师姐安排的任务,非常感谢CSDN前辈们所撰写的博客对我的帮助。
一、项目背景
二、研究思路
读取图片——>提取图中黄色部分——>腐蚀操作剔除细小轮廓——>查找所有轮廓——>筛选并绘制出符合条件的轮廓——>绘制最小矩形框并标记出坐标
三、代码实现
读取图片代码如下:
# 1.读取图片
# 使用函数cv2.imread(filepath,flags)读入一副图片
image = cv2.imread(img_path)
print(image.shape)
# (5792,4344,3)
# 源图像:3通道图像
height, width, channel = image.shape
# 通过resize()函数进行图像缩放
# 缩小图像,比例为(0.125,0.125)
# 插值方法:基于4x4像素邻域的3次插值法
image = cv2.resize(image, (int(0.125*width), int(0.125*height)), interpolation=cv2.INTER_CUBIC)
# 使用函数cv2.imshow(wname,img)显示图像,第一个参数是显示图像的窗口的名字,第二个参数是要显示的图像(imread读入的图像)
cv2.imshow("original", image)
# 2.提取图片中的黄色部分
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
low_hsv = np.array([26,43,46])
high_hsv = np.array([34,255,255])
mask = cv2.inRange(hsv,lowerb=low_hsv,upperb=high_hsv)
cv2.imshow("find_yellow",mask)
#腐蚀,消除图像边缘小的部分,并将图像缩小,从而使其补集扩大,原型为:dst=cv2.erode(src表示原图像,kernel表示卷积核,iterations表示迭代次数)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) #设置kernel卷积核为 3 * 3 正方形,8位uchar型,全1结构元素
mask = cv2.erode(mask, kernel,15)
cv2.imshow("morphology", mask)
可以发现经过此操作后得到的图像明显干净了很多
查找所有轮廓的代码如下:
# 4.查找轮廓,输出找到的轮廓个数为5个
contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print("find", len(contours), "contours")
# 绘制轮廓函数
# 自定义绘制轮廓的函数(为简化操作)
# 输入1:winName:窗口名
# 输入2:image:原图
# 输入3:contours:轮廓
# 输入4:draw_on_blank:绘制方式,True在白底上绘制,False:在原图image上绘制
def drawMyContours(winName, image, contours, draw_on_blank):
# cv2.drawContours(image, contours, index, color, line_width)
# 输入参数:
# image:与原始图像大小相同的画布图像(也可以为原始图像)
# contours:轮廓(python列表)
# index:轮廓的索引(当设置为-1时,绘制所有轮廓)
# color:线条颜色,
# line_width:线条粗细
# 返回绘制了轮廓的图像image
if (draw_on_blank): # 在白底上绘制轮廓
temp = np.ones(image.shape, dtype=np.uint8) * 255
cv2.drawContours(temp, contours, -1, (0, 0, 0), 2)
else:
temp = image.copy()
cv2.drawContours(temp, contours, -1, (0, 0, 255), 2)
cv2.imshow(winName, temp)
# 5.绘制原始轮廓
drawMyContours("find contours", image, contours, True)
# 自定义函数:用于删除列表指定序号的轮廓
# 输入 1:contours:原始轮廓
# 输入 2:delete_list:待删除轮廓序号列表
# 返回值:contours:筛选后轮廓
def delet_contours(contours, delete_list):
delta = 0
for i in range(len(delete_list)):
# print("i= ", i)
del contours[delete_list[i] - delta]
delta = delta + 1
return contours
# 6.筛选轮廓,计算每个轮廓长度
lengths = list()
for i in range(len(contours)):
length = cv2.arcLength(contours[i], True)
lengths.append(length)
print("轮廓%d 的周长: %d" % (i, length))
# 使用轮廓长度滤波
min_size = 20
max_size = 200
delete_list = []
for i in range(len(contours)):
if (cv2.arcLength(contours[i], True) < min_size) or (cv2.arcLength(contours[i], True) > max_size):
delete_list.append(i)
# 根据列表序号删除不符合要求的轮廓
contours = delet_contours(contours, delete_list)#筛选后的轮廓
print("find", len(contours), "contours left after length filter")#打印筛选后的轮廓
drawMyContours("contours after length filtering", image, contours, False)
分别绘制出所筛选出轮廓的最小覆盖矩形并标记出左上角坐标值的代码如下:
# 7.形状描述子
# 7.1 最小覆盖矩形
result = image.copy()
for i in range(len(contours)):
rect = cv2.minAreaRect(contours[i])
box = cv2.boxPoints(rect)
box = np.int0(box)
draw_rect = cv2.drawContours(image.copy(), [box], -1, (0, 0, 255), 2)
#左上角坐标值
pt = (box[1][0],box[1][1])
#画红点
cv2.circle(result, pt, 2, (0, 0, 255), 2)
text = "(" + str(pt[0]) + ", " + str(pt[1]) + ")"
cv2.putText(result, text, (pt[0] + 10, pt[1] + 10), cv2.FONT_HERSHEY_PLAIN, 1.5, (255, 255, 255), 1, 8, 0)
print("box_{}:{},左上角坐标为{}\n".format(i, box, box[1]))
image = draw_rect
cv2.imshow("draw_rect", draw_rect)
cv2.imshow("only_res", result)
将所筛选轮廓的最小覆盖矩形以及左上角坐标值绘制在同一张图片中的代码如下:
# 8.标记左上角坐标点(轮廓和点在同一张图中显示)
for i in range(len(contours)):
rect = cv2.minAreaRect(contours[i])
box = cv2.boxPoints(rect)
box = np.int0(box)
draw_rect = cv2.drawContours(image.copy(), [box], -1, (0, 0, 255), 2)
# 左上角坐标值
pt = (box[1][0], box[1][1])
# 画绿点
circle = cv2.circle(draw_rect.copy(), pt, 2, (0, 255, 0), 2)
text = "(" + str(pt[0]) + ", " + str(pt[1]) + ")"
all = cv2.putText(circle.copy(), text, (pt[0] + 10, pt[1] + 10), cv2.FONT_HERSHEY_PLAIN, 1.5, (255, 255, 255), 1, 8, 0)
image = all
cv2.imshow("all_res", all)
#防止窗口闪现
cv2.waitKey()
#销毁所有窗口
cv2.destroyAllWindows()
四、资料分享
关于OpenCv轮廓操作部分的详细讲解,请参考轮廓操作
关于OpenCv不同形状的轮廓拟合,请参考轮廓形状拟合
以及RGB配色表
后续会不断进行改进,希望能与大家共同进步!