这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 企业专区» OpenVINO生态社区» 【原创】OpenCV-Python系列之轮廓特征中阶(二十九)

共3条 1/1 1 跳转至

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

高工
2020-07-11 21:06:51 打赏

OpenCV-Python系列之轮廓特征中阶

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

边界矩形

有两类边界矩形

直边界矩形—boundingRect()

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

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

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

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

参数解释

第一个参数:img是原图

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

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

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

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

我们来看代码:

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()

image.png

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

旋转的边界矩形

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

用到的函数为

cv2.minAreaRect(cnt)

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

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

我们来看代码:

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()

image.png

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

最小外接圆

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

函数原型:

center, radius = cv.minEnclosingCircle( points )

image.png

直接来看代码:

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()

image.png

椭圆拟合

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

retval=cv.fitEllipse(points)

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

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()

image.png

直线拟合

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

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|

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

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

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

代码:

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()

image.png

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

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

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

我们使用图片:

image.png

代码:

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)

image.png

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

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


对计算机视觉感兴趣?这个社区推荐给你~

>>点击了解OpenVINO生态开发社区



高工
2020-07-11 21:11:44 打赏
2楼

楼主这个系列非常棒


工程师
2020-07-11 21:16:08 打赏
3楼

学到了


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]