5.RV1126-OPENCV 图形计算面积

发布于:2025-06-03 ⋅ 阅读:(28) ⋅ 点赞:(0)

一.图形面积、弧长计算介绍

        前面我们已经把图形轮廓的检测、画框等功能讲解了一遍。这次主要结合轮廓检测的 API 去计算图形的面积,这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能,常用的 API 如 contourArea(主要用于曲线面积计算)、arcLength(主要用于计算轮廓的周长)、minAreaRect(主要用于计算最小外接矩形,矩形可以根据图像旋转而旋转)、boundingRect(主要用于计算最小外接矩形,矩形只能是方正的矩形)、rectangle(绘制矩形)、line(绘制线)等等

二.计算面积的API

  • contourArea:主要的用途是计算轮廓的曲线面积,例如计算下图白色区域面积,方法就是微积分计算。    

CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false );
第一个参数:contour 指的是每一个轮廓的数据,也称之为轮廓的点
第二个参数:oriented 表示的是某一个方向上轮廓的面积值
返回值:计算后的轮廓面积

  • arcLength :主要的用途是计算轮廓的周长,也就是图形形状本身的曲线弧度周长。例如下图计算的是每个点连接的长度,并计算出来。

CV_EXPORTS_W double arcLength( InputArray curve, bool closed );
第一个参数:curve 轮廓曲线的 2D 像素点
第二个参数:closed 轮廓或者曲线是否闭合标志,true 表示闭合
返回值:计算后的轮廓周长

  • minAreaRect :主要的用途是计算最小的外接矩形,这个矩形就是根据图像找到最小给他包围的矩形,所以这个矩形可能会是斜的,不是方正的。如下图,斜的8就被最小外接矩形包围

CV_EXPORTS_W RotatedRect minAreaRect( InputArray points );
第一个参数:points 输入的二维点数,可以 Mat 类型也可以是 std::vector 的向量类型
返回值:RotatedRect 的矩形对象, 它表示的是一个轮廓的最小外接矩形

  • boundingRect :主要的用途是计算图形轮廓垂直边界的最小矩形,这个矩形一定是方方正正,不管图像怎么样,矩形一定是方正的围住图像,例如下图:

CV_EXPORTS_W Rect boundingRect( InputArray array );
第一个参数:array 输入的灰度图像或者 2D 点集,数据类型为 vector 或者 Mat 矩阵数据
返回值:Rect 的矩形对象,它表示的是物体轮廓的最大外接矩形。我们来看看 Rect 主要的成员变量

  • rectangle:作用是绘制矩形,有两种方式:1.以两个顶点的方式画矩形(一个左上角点,另一个右下角点,绘制出一个矩形);2.以 Rect 的方式画矩形(给出一个起始点,给出宽和高,绘制出图像)。

 1.void cv::rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar & color, int thickness = 1,int lineType = LINE_8, int shift = 0)
第一个参数:输入的矩阵图像数据
第二个参数:pt1 是矩形的一个顶点,左上角的顶点
第三个参数:pt2 矩形中与 pt1 相对的顶点,也就是两个点在对角线上,也就是右下角的顶点
第四个参数:Scalar 颜色的标量
第五个参数:thickness 线宽
第六个参数:lineType 线的类型,默认是 LINE_8 就行
第七个参数:shift 坐标的小数点位,默认为 0 就可以

 2.void cv::rectangle(InputOutputArray img, Rect rec, const Scalar & color, int thickness = 1,int lineType = LINE_8, int shift = 0)
第一个参数:输入的矩阵图像数据
第二个参数:Rect 的结构体,我们来看看这个 Rect 的重要成员变量
                      x:矩形的 x 坐标轴
                      y: 矩形的 y 坐标轴
                      width:矩形的宽度
                      height:矩形的高度
第三个参数:Scalar 颜色的标量
第四个参数:thickness 线宽,默认是 1
第五个参数:lineType 线的类型,默认是 LINE_8 就行,line 的类型如下:
第六个参数:shift 坐标点的小数点位数

  • line:主要作用是通过两个点绘制直线

CV_EXPORTS_W void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
int thickness = 1, int lineType = LINE_8, int shift = 0);

第一个参数:输入的矩阵图像数据
第二个参数:pt1 是线的起始坐标,也就是图上 x1 坐标和 y1 坐标
第三个参数:pt2 是线的终点坐标,也就是图上 x2 坐标和 y2 坐标
第四个参数:Scalar 是颜色标量,绘制直线的颜色
第五个参数:thickness 它是线的粗细程度,默认为 1
第六个参数:lineType 线的类型,默认是 LINE_8 就行,具体的类型
第七个参数:shift 坐标点的小数点位数 

  •  threshold :主要用途是把图像进行二值化处理,二值化操作可以使图像中的数据量大大降低图像的复杂度,并且能够凸显出图像中的轮廓。

CV_EXPORTS_W double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type );
第一个参数:src 源图像,可以是 8 位灰度图,也可以是 32 位的三通道图像(彩色图像和灰度图像)
第二个参数:dst 目标图像
第三个参数:thresh 阈值
第四个参数:maxval 二值图像中灰度最大值,maxval 只能在 THRESH_BINARY 和 THRESH_BINARY_INV 有用,但是其他选项也需要填这个值,不能空着。
第五个参数:type 阈值操作类型,具体的阈值操作如下图: 

1.THRESH_BINARY:二值化阈值处理会将原始图像作为仅有的两个值图像,它针对的像素的处理方式是对于灰度值大于阈值 thresh的像素点,将其灰度值设定为 maxval 最大值。而对于灰度值小于或等于阈值 thresh 的像素点,将其灰度值设定为 0。 

2.THRESH_BINARY_INV:反二值化阈值处理也会将原始图像作为仅有的两个值图像,但是它处理的方式和 THRESH_BINARY 不一样,它的特点是:对于灰度值大于阈值的像素点,将其设置为 0。而对于灰度值小于或者等于阈值的像素点,将这部分的部分设置为maxval 最大像素点

3.THRESH_TRUNC:截断阈值化处理会把图像中大于阈值的像素点设定为阈值小于或者等于该阈值的像素点保持不变。比方说阈值设置成 127,则说明对于像素超过 127 的像素点,而其像素值就被设置成 127。而小于或者等于 127 的像素点,其数值保持不变。

4.THRESH_TOZERO_INV:超阈值处理会对图像中大于阈值的像素点处理为 0小于或者等于该阈值的像素点保持不变。比方说阈值的值设定为 127,若当前像素点大于 127 则把像素点处理为 0;若当前像素点小于或者等于阈值的像素点,那么该像素点保持不变

5.THRESH_TOZERO:低阈值处理会对图像中小于或者等于阈值的像素点处理为 0大于阈值的像素点则保持不变。比方说当前阈值设定为 127,若当前像素点小于或者等于 127 则把像素点处理为 0;若当前像素点大于 127 则保持像素点不变。

6.THRESH_OTSU:OTSU 方法会遍历所有可能的阈值,从而找到一个最佳的阈值。值得注意的是,在使用 OTSU 方法的时候需要把阈值设定为 0。这个时候,threshold 会自动寻找最优的值。
 

三.代码实战:计算轮廓面积

 1.例如计算下面10的各种面积:

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
  
  //读取图片
  Mat src = imread("ten.png");

  //灰度化图片,将彩色原图转化成灰度图
  Mat gray;
  cvtColor(src, gray, COLOR_RGB2GRAY);

  //二值化图片
  Mat bin_img;
  threshold(gray, bin_img, 150, 255, THRESH_BINARY_INV);//二值化处理阈值150,最大值255是白色,THRESH_BINARY_INV是将原图设置反色(黑的变白的,白的变黑的)

  //轮廓检测,并获取轮廓像素点数量
  vector<vector<Point>> contours;//定义一个二维点向量,用于存储轮廓
  findContours(bin_img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);//RETR_EXTERNAL表示只检测外部轮廓,CHAIN_APPROX_SIMPLE表示只存储轮廓的拐点

  //循环轮廓数量并计算轮廓面积
  Point2f pts[4];//定义一个二维点向量,用于存储最小外接矩形的四个顶点
  for (int i = 0; i < contours.size(); i++)
  {
      //*************计算最小外接矩形面积**********************//
      RotatedRect rects =  minAreaRect(contours[i]);
      rects.points(pts);//获取最小外接矩形的四个顶点
      //将外接四个顶点连接起来
      line(src, pts[0], pts[1], Scalar(0, 0, 255), 2);//用line连接p[0]->p[1]
      line(src, pts[1], pts[2], Scalar(0, 0, 255), 2);//用line连接p[1]->p[2]
      line(src, pts[2], pts[3], Scalar(0, 0, 255), 2);//用line连接p[2]->p[3]
      line(src, pts[3], pts[0], Scalar(0, 0, 255), 2);//用line连接p[3]->p[0]
      
      int minArea = rects.size.width * rects.size.height;//计算轮廓面积
      printf("minArea = %d\n", minArea);

      //*************计算边界矩形(垂直矩形)面积**********************//
      Rect bArea = boundingRect(contours[i]);//调用boundingRect查找边界矩形
      int boundingArea = bArea.width * bArea.height;//计算边界矩形面积
      printf("boundingArea = %d\n", boundingArea);
      rectangle(src, bArea, Scalar(255,255,0));//rectangle矩形画框
      
      //*************计算轮廓面积(就是1,0这个面积)**********************//
      double cArea = contourArea(contours[i]);//计算轮廓面积
      printf("cArea = %f\n", cArea);
  }

  imwrite("area.jpg", src);
  return 0;
}

2.效果图

minArea:就是斜长方形面积; boundingArea:就是白正方形面积;cArea:就是黑色部分面积


网站公告

今日签到

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