【问题标题】:How to find height and width for each individual contour on an image using OpenCV如何使用 OpenCV 查找图像上每个单独轮廓的高度和宽度
【发布时间】:2023-04-10 12:46:02
【问题描述】:

在上图中,如果指定整个宽度为 30'5"。如何使用 opencv 计算该图像上每个单独轮廓的高度和宽度

【问题讨论】:

    标签: image opencv image-processing computer-vision contour


    【解决方案1】:

    要获取轮廓的高度和宽度,可以使用cv2.boundingRect。该函数以x,y,w,h的形式返回轮廓信息。特定轮廓的高度为h,宽度为w。这是将w 绘制到图像上的结果(以像素为单位)。

    import cv2
    
    # Load image, convert to grayscale, Otsu's threshold
    image = cv2.imread('1.jpg')
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    # Find contours, obtain bounding rect, and draw width
    cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        x,y,w,h = cv2.boundingRect(c)
        cv2.putText(image, str(w), (x,y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (36,255,12), 2)
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 1)
    
    cv2.imshow('image', image)
    cv2.waitKey()
    

    【讨论】:

      【解决方案2】:

      我的方法是使用minAreaRect

      #include "opencv2/highgui/highgui.hpp"
      #include "opencv2/imgproc/imgproc.hpp"
      #include <iostream>
      #include <stdio.h>
      #include <stdlib.h>
      
      using namespace cv;
      using namespace std;
      
      
      int main()
      {
      
          Mat src; Mat src_gray;
          int thresh = 100;
          RNG rng(12345);
          /// Load source image and convert it to gray
          src = imread( "/ur/img/directory/image.jpg", 1 );
          Mat original = src.clone();
          /// Convert image to gray and blur it
          cvtColor( src, src_gray, CV_BGR2GRAY );
      
          Mat threshold_output;
          vector<vector<Point> > contours;
          vector<Vec4i> hierarchy;
      
          /// Detect edges using Threshold
          threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
          /// Find contours
          findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
      
          /// Find the rotated rectangles for each contour
          vector<RotatedRect> minRect( contours.size() );
      
          for( int i = 0; i < contours.size(); i++ )
              minRect[i] = minAreaRect( Mat(contours[i]) );
      
          /// Draw contours + rotated rects
          Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
          Mat result_zero = Mat::zeros( threshold_output.size(), CV_8UC3 );
      
          for( int i = 0; i< contours.size(); i++ )
          {
              Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
              // detect contours
              drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
              // detect rectangle for each contour
              Point2f rect_points[4]; minRect[i].points( rect_points );
      
              double length_1 = cv::norm(cv::Mat(rect_points[0]),cv::Mat(rect_points[1]));
              double length_2 = cv::norm(cv::Mat(rect_points[1]),cv::Mat(rect_points[2]));
      
      
              for( int j = 0; j < 4; j++ )
              {
                  int temp1 = (int)length_1;
                  int temp2 = (int)length_2;
      
                  if(length_1>length_2)
                      putText(original,to_string(temp1),rect_points[0],FONT_HERSHEY_SIMPLEX,1.0,Scalar(0,255,255),2);
                  else
                      putText(original,to_string(temp2),rect_points[0],FONT_HERSHEY_SIMPLEX,1.0,Scalar(0,255,255),2);
      
                  line( result_zero, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
              }
      
          }
      
          /// Show in windows
          imshow("First",original);
          imshow( "Contours", drawing );
          waitKey(0);
          return(0);
      }
      

      源图片:

      每行检测到的矩形:

      像素线长:

      【讨论】:

      • 很好的解决方案!但是从下一次开始,如何使用 python,因为它更容易测试。大多数人可能没有 C++ 环境设置!
      • 把它转换成python没什么大不了的。转换它没有困难。我的环境只是基于 c++ 的。这就是我用 C++ 回答的原因
      【解决方案3】:
      std::vector<std::vector<cv::Point2i>> vecContours;
      cv::Mat mat = cv::imread("[path to image]", cv::IMREAD_GRAYSCALE);
      cv::threshold(mat, mat, 200, 255, cv::THRESH_BINARY);
      cv::findContours(mat, vecContours, cv::RetrievalModes::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
      float inchPerPixel = 30.5f / mat.cols;
      for (const std::vector<cv::Point2i>& vecContour : vecContours) {
          cv::Rect2i contourRect = cv::boundingRect(vecContour);
          printf("Contour width pixels : %d, width inches %f\n", contourRect.width, inchPerPixel*contourRect.width);
      }
      

      您可以通过以下方式实现:

      1. 使用阈值法创建二值图像
      2. 使用 findContours 方法查找图像中矩形的轮廓
      3. 使用boundingRect方法获取矩形轮廓的大小
      4. 将轮廓的 with 乘以计算出的每像素英寸系数

      【讨论】:

        猜你喜欢
        • 2016-08-09
        • 2021-06-15
        • 2011-06-13
        • 1970-01-01
        • 2022-11-24
        • 2012-06-23
        • 1970-01-01
        • 1970-01-01
        • 2017-03-24
        相关资源
        最近更新 更多