OpenCV:检查像素是否在边界线内,由等高线

时间:2015-11-23 16:47:54

标签: c++ opencv

我有一个图像蒙版,有一些我从Canny得到的轮廓。我可以计算一个边界矩形(具有固定的给定角度)。

enter image description here

现在我需要将2个区域分隔到该矩形的左侧和右侧。 我怎么能这样做?

请注意,我想处理矩形内的区域,而不是轮廓的像素。

编辑

这是我从掩码中获取每个边界矩形的方法:

cv::Mat img_edges; // mask with contours

// Apply clustering to the edge mask from here
// http://stackoverflow.com/questions/33825249/opencv-euclidean-clustering-vs-findcontours?noredirect=1#comment55433731_33825249

// Find boundary rectangle
for (auto &contour: contours) { // Iterate over every contour cluster
  cv::Mat Srot = cv::getRotationMatrix2D(cv::Point2f(float(img_edges.cols) / 2., float(img_edges.rows) / 2.), -ILLUMINATION_ANGLE_DEG, 1.0);

  cv::transform(contour, contour, Srot);

  float min_x, min_y, max_x, max_y;

  min_x = min_y = std::numeric_limits<float>::max();
  max_x = max_y = -std::numeric_limits<float>::max();

  // Simply find edges of aligned rectangle, then rotate back by inverse of Srot
}

1 个答案:

答案 0 :(得分:1)

  

好吧,假设我可以获得连接组件。那我该怎么办呢?

从评论到问题,我们同意此程序适用于轴对齐的矩形。这不会失去一般性,因为您可以将旋转的矩形旋转为轴对齐,应用此过程,然后将点旋转回来。

从具有一些边缘的样本图像开始,例如:

enter image description here

你可以得到这样的东西,其中 blue 是由边缘分隔的边界框中的左边部分, red 是正确的部分:

enter image description here

这种算法可能不是最聪明的方法,但在实践中可行。

找到每条边的边界框后:

  1. 在给定的roi上创建一个矩阵tmp,在左边加1列,在右边加1。这将使算法对特定情况具有鲁棒性。
  2. 移动新坐标系中的所有边界点,然后绘制到tmp
  3. 应用floodFill算法查找左侧点。种子是tmp的左上角。
  4. 应用floodFill算法查找正确的点数。种子是tmp的右上角。
  5. 检索两个区域中的点,切换到原始坐标系。
  6. 这里是评论的代码,如果有什么不明确的话,请告诉我:

    #include <opencv2/opencv.hpp>
    #include <vector>
    using namespace std;
    using namespace cv;
    
    
    void separateAreas(const Rect& roi, const vector<Point>& points, vector<Point>& left, vector<Point>& right)
    {
        left.clear();
        right.clear();
    
        // Temporary matrix
        // 0 : background pixels
        // 1 : boundary pixels
        // 2 : left pixels
        // 3 : right pixels
        Mat1b tmp(roi.height, roi.width + 2, uchar(0));
    
        // Shift points to roi origin, i.e tmp(0,1)
        vector<Point> pts(points);
        for (int i = 0; i < points.size(); ++i)
        {
            pts[i] -= roi.tl();
    
            // Draw boundary on tmp matrix
            tmp(pts[i] + Point(1,0)) = 1;
        }
    
        // Fill left area, seed top left point
        floodFill(tmp, Point(0, 0), Scalar(2));
    
        // Fill right area, seed top right point
        floodFill(tmp, Point(tmp.cols-1, 0), Scalar(3));
    
        // Find left and right points
        findNonZero(tmp.colRange(1, tmp.cols - 1) == 2, left);
        findNonZero(tmp.colRange(1, tmp.cols - 1) == 3, right);
    
        // Shift back
        for (int i = 0; i < left.size(); ++i)
        {
            left[i] += roi.tl();
        }
        for (int i = 0; i < right.size(); ++i)
        {
            right[i] += roi.tl();
        }
    }
    
    
    int main()
    {
        Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
    
        Mat3b res;
        cvtColor(img, res, COLOR_GRAY2BGR);
    
        vector<vector<Point>> contours;
        findContours(img.clone(), contours, RETR_LIST, CV_CHAIN_APPROX_NONE);
    
        for (int i = 0; i < contours.size(); ++i)
        {
            Rect roi = boundingRect(contours[i]);
            //rectangle(res, roi, Scalar(0,255,0));
    
            vector<Point> left, right;
            separateAreas(roi, contours[i], left, right);
    
            // Draw areas on res
            for (int j = 0; j < left.size(); ++j)
            {
                res(left[j]) = Vec3b(255,0,0); // Blue for left
            }
            for (int j = 0; j < right.size(); ++j)
            {
                res(right[j]) = Vec3b(0, 0, 255); // Red for right
            }
        }
    
        imshow("Image", img);
        imshow("Result", res);
        waitKey();
    
        return 0;
    }