OpenCV(应用) —— 目标轮廓的相关应用


一、目标轮廓的获取与绘制

通常,使用findContours() 函数是为了获取一张图像内目标对象的所有轮廓,并且在 OpenCV4.x 版本中,findContours() 函数的返回值发生了变化。参数列表不列举了,下面直接给出最常用的一种语法:

// python
contours, _ = cv2.findContours(label, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

// C++
vector<std::vector<cv::Point>> contours;
cv::findContours(label, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

label:输入图,最好是二值图
cv2.RETR_EXTERNAL: 只检测最外层轮廓
cv2.CHAIN_APPROX_SIMPLE:压缩水平方向、垂直方向和对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保持轮廓信息。

调试阶段,为了直观显示出轮廓,可使用drawContours()函数进行轮廓绘制

	cv::drawContours(img, contours, -1, cv::Scalar(71, 206, 255), 1);
	cv::imshow("output_contours", img);

第三个参数为要绘制的轮廓数量,负数-1则表示全部绘制
第四个参数为轮廓的颜色
第五个参数为轮廓的粗细
后面还有参数,但都采用默认值即可

此外,还可以使用 rectangle函数 来绘制矩形边框,fillPoly函数 来填充目标区域

二、轮廓的信息(面积和周长)

检测完所有最外层轮廓后,通常还需要筛选、去除掉一些不需要的轮廓。其中,轮廓的面积是一个常用的判别值,
OpenCV提供了contourArea()函数来直接计算面积:

// python
contours, _ = cv2.findContours(label, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
     area = cv2.contourArea(contour)
     if (area < 1000):
        continue

// C++
vector<std::vector<cv::Point>> contours;
cv::findContours(label, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++)
{
    
    
	double area = cv::contourArea(contours[i]);
	if (area > 1000)
	{
    
    
		continue;
	}
}

此外,OpenCV还提供了一个计算轮廓周长的函数arcLength(),用法和计算面积函数是一样的。但实际用处不大,毕竟轮廓的周长并不能说明什么。

三、轮廓外接形状的三种表达方式

获得目标轮廓后,有三种处理方式:1)最小外接斜矩阵。 2)最大外接正矩阵。 3)逼近多边形。 前两种是最为常用的处理方式,毕竟矩阵信息在后续处理中比较方便。

  目标轮廓的使用在图像分割项目中很常见,因为分割的标签图是一个可以完美检测目标轮廓的二值图。三种处理使用的函数和常用方式如下:

image = cv2.imread('C:/Users/train/view4_20230616130920_2.jpg')
label = cv2.imread('C:/Users/mask/view4_20230616130920_2.png',0)
contours, _ = cv2.findContours(label, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for contour in contours:
    # 1、最小外接斜矩阵(带角度)
    # rect = cv2.minAreaRect(contour)  # 计算轮廓的最小外接矩形
    # box = cv2.boxPoints(rect)  # 获取旋转矩形的四个顶点坐标
    # box = np.int0(box)  # 将顶点坐标转换为整数
    #
    # (cx,cy), (boxW, boxH), angle = rect  # (中心点),(宽高),角度
    #
    # cv2.drawContours(image, [box], -1, (0,255,0), 2)  # 要绘制的轮廓必须是一个列表,所以是[box]
    # cv2.fillPoly(label, np.array([contour]), 255)  # 将目标轮廓区域填充为白色

    # 2、最大外接正矩阵
    x, y, width, height = cv2.boundingRect(contour)  # (左上角坐标,宽,高)
    cv2.rectangle(image, (x, y), (x + width, y + height), (0, 255, 0), 2)

    # 3、多边形
    # epsilon = 0.01 * cv2.arcLength(contour, True)  # 常用轮廓的周长(或弧长)的百分比作为 epsilon 的值
    # approx = cv2.approxPolyDP(contour, epsilon, True) # epsilon表示逼近后的多边形与原始轮廓之间的最大距离,True表示将轮廓视为闭合
    # cv2.drawContours(image, [approx], 0, (0, 255, 0), 2)


cv2.imshow("Contours", image)
cv2.imshow("Contours——mask", label)
cv2.waitKey(0)
cv2.destroyAllWindows()

  cv2.minAreaRect函数获取最小外接斜矩阵,它的返回值为:(中心点),(宽高),角度。若只需要获取矩形坐标,可使用cv2.boxPoints函数来得到矩形的四个顶点坐标。
  该函数获得返回的角度有一个应用,就是之前博客讲的仿射变换,它返回的中心点和角度可以作为仿射变换矩阵的参数:M = cv2.getRotationMatrix2D((cx, cy), angle, 1) ,这样我们可以将有角度的目标进行仿射变换旋转,让其处于水平方向。

猜你喜欢

转载自blog.csdn.net/qq_43199575/article/details/133904265