【转载】OpenCV-Python系列之轮廓特征中阶(二十九)

本次我们将讨论OpenCV中图像轮廓的另一些特征,它们将非常有用。

边界矩形

有两类边界矩形

直边界矩形—boundingRect()

一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。所以边界矩形的面积不是最小的。可以使用函数 cv2.boundingRect() 查找得到,我们来看函数原型:

x,y,w,h = cv2.boundingRect(cnt)

(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高,通常情况下,cnt代表识别的轮廓。

之后我们利用cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)画出矩形、

参数解释

第一个参数:img是原图

第二个参数:(x,y)是矩阵的左上点坐标

第三个参数:(x+w,y+h)是矩阵的右下点坐标

第四个参数:(0,255,0)是画线对应的rgb颜色

第五个参数:2是所画的线的宽度

我们来看代码:

view plaincopy to clipboardprint?
import cv2  
  
# 读取图片并转至灰度模式  
img = cv2.imread("tubao.png", 1)  
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  
# 二值化,取阈值为235  
ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)  
  
# 寻找图像中的轮廓  
contours, hierarchy = cv2.findContours(thresh, 2, 1)  
  
cnt = contours[0]  
x, y, w, h = cv2.boundingRect(cnt)  
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)  
  
cv2.imshow('finger', img)  
cv2.waitKey()  

在这里插入图片描述

可以看到一个外接矩形,但是它不是最小的外接矩形,接下来我们讨论最小外接矩形。

旋转的边界矩形

这个边界矩形是面积最小的,因为它考虑了对象的旋转。

用到的函数为 :

cv2.minAreaRect(cnt)。

在这里的cnt仍然跟上面的相同,该函数返回的是一个 Box2D 结构:

Box2D结构 rect:(最小外接矩形的中心(x,y),(宽度,高度),旋转角度),但是要绘制此矩形,我们需要矩形的4个角。 它是通过函cv2.boxPoints()获得的。

我们来看代码:

view plaincopy to clipboardprint?
import cv2  
import numpy as np  
  
# 读取图片并转至灰度模式  
img = cv2.imread("tubao.png", 1)  
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  
# 二值化,取阈值为235  
ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)  
  
# 寻找图像中的轮廓  
contours, hierarchy = cv2.findContours(thresh, 2, 1)  
  
cnt = contours[0]  
  
rect = cv2.minAreaRect(cnt)  
box = cv2.boxPoints(rect)  
box = np.int0(box)  
cv2.drawContours(img,[box],0,(0,0,255),2)  
  
cv2.imshow('finger', img)  
cv2.waitKey()  

在这里插入图片描述

可以看到,这里得出的结果是最小外接矩形。

最小外接圆

跟之前一样,轮廓可以外接矩形,同时也可以外接圆形。接下来,我们使用函数cv.minEnclosingCircle()找到对象的外接圆。 它是一个以最小面积完全覆盖对象的圆圈。

函数原型:

  center, radius     =     cv.minEnclosingCircle(   points    )

在这里插入图片描述

直接来看代码:

view plaincopy to clipboardprint?
import cv2  
import numpy as np  
  
# 读取图片并转至灰度模式  
img = cv2.imread("tubao.png", 1)  
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  
# 二值化,取阈值为235  
ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)  
  
# 寻找图像中的轮廓  
contours, hierarchy = cv2.findContours(thresh, 2, 1)  
  
cnt = contours[0]  
  
(x, y), radius = cv2.minEnclosingCircle(cnt)  
center = (int(x), int(y))  
radius = int(radius)  
cv2.circle(img, center, radius, (0, 255, 0), 2)  
  
cv2.imshow('finger', img)  
cv2.waitKey()  

在这里插入图片描述

椭圆拟合

轮廓同样也可以进行椭圆拟合,函数原型:

retval=cv.fitEllipse(points)

输入参数跟之前的外界矩形是一样的,就不一一详述了。代码:

view plaincopy to clipboardprint?
import cv2  
import numpy as np  
  
# 读取图片并转至灰度模式  
img = cv2.imread("tubao.png", 1)  
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  
# 二值化,取阈值为235  
ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)  
  
# 寻找图像中的轮廓  
contours, hierarchy = cv2.findContours(thresh, 2, 1)  
  
cnt = contours[0]  
  
ellipse = cv2.fitEllipse(cnt)  
cv2.ellipse(img,ellipse,(0,255,0),2)  
  
cv2.imshow('finger', img)  
cv2.waitKey()  

在这里插入图片描述

直线拟合

同样,我们可以将一条直线拟合到一组点。下图包含一组白点,我们可以近似一条直线。函数原型:

output = cv2.fitLine(InputArray points, distType, param, reps, aeps)

InputArray Points: 待拟合的直线的集合,必须是矩阵形式;

distType: 距离类型。fitline为距离最小化函数,拟合直线时,要使输入点到拟合直线的距离和最小化。这里的距离的类型有以下几种:

cv2.DIST_USER : User defined distance

cv2.DIST_L1: distance = |x1-x2| + |y1-y2|

cv2.DIST_L2: 欧式距离,此时与最小二乘法相同

cv2.DIST_C:distance = max(|x1-x2|,|y1-y2|)

cv2.DIST_L12:L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))

cv2.DIST_FAIR:distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998

cv2.DIST_WELSCH: distance = c2/2(1-exp(-(x/c)2)), c = 2.9846

cv2.DIST_HUBER:distance = |x|<c |x^2/2 : c(|x|-c/2), c=1.345

param: 距离参数,跟所选的距离类型有关,值可以设置为0。

reps, aeps: 第5/6个参数用于表示拟合直线所需要的径向和角度精度,通常情况下两个值均被设定为1e-2。

output : 对于二维直线,输出output为4维,前两维代表拟合出的直线的方向,后两位代表直线上的一点。(即通常说的点斜式直线)。

代码:

view plaincopy to clipboardprint?
import cv2  
import numpy as np  
  
# 读取图片并转至灰度模式  
img = cv2.imread("tubao.png", 1)  
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
  
# 二值化,取阈值为235  
ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)  
  
# 寻找图像中的轮廓  
contours, hierarchy = cv2.findContours(thresh, 2, 1)  
  
cnt = contours[0]  
rows,cols = img.shape[:2]  
  
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)  
lefty = int((-x*vy/vx) + y)  
righty = int(((cols-x)*vy/vx)+y)  
cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)  
  
cv2.imshow('finger', img)  
cv2.waitKey()  

在这里插入图片描述

现在我们可以来一个实战部分,用椭圆拟合来进行人眼识别之后标注出来,首先我们需要安装dlib库,这种一个人脸特征检测库,接下来我们设置特征检测器,dlib有已经训练的好的需要下载,也可以自己根据需要训练:

下载链接:http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2

下载完之后解压,将路径放到根目录里面,当然了,下载是需要科学上网的,否则下载速度非常慢。

我们使用图片:
在这里插入图片描述

代码:

view plaincopy to clipboardprint?
import cv2  
 import dlib  
 import numpy as np  
   
 detector = dlib.get_frontal_face_detector()  
 landmark_predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')  
   
 img = cv2.imread("min.jpg")  
 faces = detector(img,1)  
 left_eye = []  
 right_eye = []  
 if ( len(faces) > 0):  
     for k,d in enumerate(faces):  
         shape = landmark_predictor(img,d)  
         for i in range(36,42):  
             right_eye.append([shape.part(i).x,shape.part(i).y])  
         for i in range(42,48):  
             left_eye.append([shape.part(i).x,shape.part(i).y])  
  
  
 ellipse_left = cv2.fitEllipse(np.array(left_eye))  
 ellipse_right = cv2.fitEllipse(np.array(right_eye))  
 cv2.ellipse(img, ellipse_left, (0,255,0), 1)  
 cv2.ellipse(img, ellipse_right, (0,255,0), 1)  
   
 ellipse_left  
 ((275.1310119628906, 197.24081420898438),  
  (13.491097450256348, 47.203433990478516),  
  84.19256591796875)  
   
 center = ellipse_left[0]  
 size = ellipse_left[1]  
 angle = ellipse_left[2]  
     
 cv2.imshow('PIC',img)  
 cv2.waitKey(0)  

在这里插入图片描述

可以看到,人眼已经识别出来,并用椭圆进行了拟合,是不是很有趣。

本次我们主要讨论轮廓的外界图形,事实上它们都是非常有用的,下次我们将讨论轮廓特征的一些高阶方法。

查看文章汇总页https://blog.csdn.net/weixin_44237705/article/details/107864965
更多openvino技术信息可以入群交流~
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值