opencv实现轮廓绘制和选择

发布于:2025-09-01 ⋅ 阅读:(18) ⋅ 点赞:(0)

前面学习了opencv中图像的一些处理,但对于opencv我们更多的还是对图像做出一些判断和识别,所以下面开始学习图像的识别。

原图:

一 图像轮廓的识别

import cv2
pen=cv2.imread('pen.png',0)
ret,new_pen=cv2.threshold(pen,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',new_pen)
contours, hierarchy = cv2.findContours(new_pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(hierarchy)
print(contours)
print(len(contours))
pen1=pen.copy()
Contours = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(Contours,contours,-1,(0,255,0),2)
cv2.imshow('pen1',Contours)
cv2.waitKey(0)

1 图像二值处理

ret,new_pen=cv2.threshold(pen,120,255,cv2.THRESH_BINARY)

我们这里识别图像的时候,转化为了灰度图,目的是为了后面做灰度处理,在识别轮廓之前我们要让我们的图像更加鲜明,所以我们做了一下二值处理

2 寻找轮廓

contours, hierarchy = cv2.findContours(new_pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

这里会返回两个参数,这里contours就是我们的轮廓。hierarchy这个表示层级之间的一种嵌套方式,不是特别重要。

我们这里查看下contours

这个是一个一个的坐标,我们要知道轮廓就是一个一个点组成的。然后我们可以通过drawContours来绘制。

3 绘制

注意到我们绘制之前我们还进行了一次的转换,把我们的图像转化为了RGB图像(我们前面转换成了单维度的图像),不然的话,我们使用灰度图的线条绘制的不明显。

Contours = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(Contours,contours,-1,(0,255,0),2)

这个里面有5个参数,第一个参数是表示我们要绘制到的目标图像,第二个参数是我们绘制的轮廓信息,第三个表示我们要绘制的索引(-1表示绘制全部的轮廓),第四个表示我要绘制的轮廓颜色,第五个表示要绘制的粗度。

二 根据面积进行轮廓选择

import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours, hierarchy = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

pen1=pen.copy()
aa = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(aa,contours,-1,(0,255,0),2)
are=cv2.contourArea(contours[0])
print(are)
ls=[]
for i in contours:
    if cv2.contourArea(i) >10000:
        ls.append(i)
print(ls)
cv2.drawContours(aa,ls,-1,(0,0,255),2)
cv2.imshow('pen1',aa)
cv2.waitKey(0)
key=cv2.contourArea, reverse=True)[0]
cv2.drawContours(aa,[sorted_contours],contourIdx=-1,color=(0,0,255),thickness=3)
cv2.imshow('pen2',aa)
cv2.waitKey(0)

1 查看轮廓面积

cv2.contourArea(contours[0])

我们可以使用这个函数来查看一个轮廓的面积

2 利用面积筛选轮廓

我们对所有轮廓进行遍历,找出面积大于10000的面积,然后添加到ls中,再画出来,就找到了符合我们条件的轮廓。

ls=[]
for i in contours:
    if cv2.contourArea(i) >10000:
        ls.append(i)
print(ls)
cv2.drawContours(aa,ls,-1,(0,0,255),2)
# cv2.imshow('contours',contours)
cv2.imshow('pen1',aa)
cv2.waitKey(0)

3 先对轮廓面积进行排序

我们使用sorted对所有轮廓面积进行排序,然后打印出最大的那一个。注意我们绘制的时候也要对sorted_contours加上一个中括号,不然画出来的图像是断断续续的。

sorted_contours = sorted(contours, key=cv2.contourArea, reverse=True)[0]
cv2.drawContours(aa,[sorted_contours],contourIdx=-1,color=(0,0,255),thickness=3)
cv2.imshow('pen2',aa)
cv2.waitKey(0)

三 画出轮廓的外界圆和外接矩形

1 外接圆

import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours, hierarchy = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
pen1=pen.copy()
aa = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(aa,contours,-1,(0,255,0),2)
cnt=contours[7]
[x,y],r=cv2.minEnclosingCircle(cnt)
ab=cv2.circle(aa,(int(x),int(y)),int(r),(255,0,0),2)
cv2.imshow('pen3',ab)
cv2.waitKey(0)

这里选取了第七个轮廓也就是那个铅笔,然后使用cv2.minEnclosingCircle(cnt)来获取这个轮廓的外界圆的外界圆,会返回两个值,一个是坐标的圆心,一个是半径,然后就可以通过cv2.circle专门的画圆工具来绘制了。

cnt=contours[7]
[x,y],r=cv2.minEnclosingCircle(cnt)
ab=cv2.circle(aa,(int(x),int(y)),int(r),(255,0,0),2)
cv2.imshow('pen3',ab)
cv2.waitKey(0)

2 外接矩形

import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours, hierarchy = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
pen1=pen.copy()
aa = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(aa,contours,-1,(0,255,0),2)
cnt=contours[7]
x,y,w,h=cv2.boundingRect(cnt)
ac=cv2.rectangle(aa,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imshow('pen4',ac)
cv2.waitKey(0)

还是和上面的那个一样,选取铅笔的笔杆轮廓,然后使用boundingRect获取我们要画的坐标起点了,宽和高,然后就可以画出来了。

四 绘制近似轮廓

import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2]
# cv2.imshow('contours',contours)
# cv2.waitKey(0)
es=0.01*cv2.arcLength(contours[0],True)
approx=cv2.approxPolyDP(contours[0],0.01*cv2.arcLength(contours[0],True),True)
phone_new=pen1.copy()
aa = cv2.cvtColor(phone_new, cv2.COLOR_GRAY2BGR)
image_contours=cv2.drawContours(aa,[approx],-1,(0,255,0),2)
cv2.imshow('phone_new',image_contours)
cv2.waitKey(0)

先给结果图

我们可以看到,结果图中我们的手机的角角的地方,本来弯的变成了菱形,是因为这里采用了

es=0.01*cv2.arcLength(contours[0],True)
approx=cv2.approxPolyDP(contours[0],0.01*cv2.arcLength(contours[0],True),True)

这个es表示一个距离,就是这个地方的d如果大于我们设置的,就会直接用这个直线来取代。


网站公告

今日签到

点亮在社区的每一天
去签到