如何在 OpenCV 中考虑轮廓的曲率来确定轮廓的角度

问题描述 投票:0回答:1

我需要计算-180到180度范围内的轮廓角度,并考虑到其曲率方向。

我找到了相关的Stack Overflow帖子并实现了以下代码来计算角度,但是用它我不知道如何考虑轮廓的曲率方向。

我还尝试使用轮廓的起点、终点和质心来计算弯曲角度。 然而,考虑到轮廓的曲率,我正在努力确定轮廓的角度。

#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

double distanceBtwPoints(const cv::Point2f& a, const cv::Point2f& b)
{
    double xDiff = a.x - b.x;
    double yDiff = a.y - b.y;

    return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}

double get_angle(const cv::Point& p1, const cv::Point& p2) {
    return std::atan2(p1.y - p2.y, p1.x - p2.x) * 180 / CV_PI;
}

void calculateAngle(cv::Mat& edgeImage) {
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(edgeImage, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_NONE);

    cv::Mat drawing = cv::Mat::zeros(edgeImage.size(), CV_8UC3);

    RotatedRect _minAreaRect;
    for (int i = 0; i < contours.size(); i = hierarchy[i][0])
    {
        _minAreaRect = minAreaRect(Mat(contours[i]));
        Point2f pts[4];
        _minAreaRect.points(pts);

        double dist0 = distanceBtwPoints(pts[0], pts[1]);
        double dist1 = distanceBtwPoints(pts[1], pts[2]);

        double angle = 0;
        if (dist0 > dist1 * 2)
        {
            angle = atan2(pts[0].y - pts[1].y, pts[0].x - pts[1].x) * 180.0 / CV_PI;
        }
        if (dist1 > dist0 * 2) {
            angle = atan2(pts[1].y - pts[2].y, pts[1].x - pts[2].x) * 180.0 / CV_PI;
        }

        putText(drawing, to_string(angle), centroid, FONT_HERSHEY_SIMPLEX, 1.5, Scalar(255, 255, 255), 2);

        Moments mu = moments(contours[i], true);
        Point2f centroid(mu.m10 / mu.m00, mu.m01 / mu.m00);

        std::vector<cv::Point> approx;
        cv::approxPolyDP(contours[i], approx, 0.2 * cv::arcLength(contours[i], true), true);
        Point2f contour_start = approx.front();
        Point2f contour_end = approx.back();

        double angle_start = get_angle(centroid, contour_start);
        double angle_end = get_angle(centroid, contour_end);
        double bending_angle = angle_end - angle_start;

        circle(drawing, centroid, 15, Scalar(255, 255, 255), -1);
        circle(drawing, contour_start, 15, Scalar(255, 255, 255), -1);
        circle(drawing, contour_end, 15, Scalar(255, 255, 255), -1);

        // Normalize the angle to the range [-180, 180)
        if (bending_angle > 180) {
            bending_angle -= 360;
        }
        else if (bending_angle < -180) {
            bending_angle += 360;
        }

        for (int j = 0; j < 4; j++)
            line(drawing, pts[j], pts[(j + 1) % 4], Scalar(0, 0, 255), 3, LINE_AA);

        drawContours(drawing, contours, i, Scalar(0, 0, 255), 2);

        circle(drawing, centroid, 15, Scalar(255, 255, 255), -1);
        line(drawing, centroid, contour_start, Scalar(255, 0, 0), 2);
        line(drawing, centroid, contour_end, Scalar(255, 0, 0), 2);

        //putText(drawing, to_string(bending_angle ), centroid, FONT_HERSHEY_SIMPLEX, 1.5, Scalar(255, 255, 255), 2);


    }
    cv::namedWindow("angle", cv::WINDOW_NORMAL);
    cv::resizeWindow("angle", 700, 700);
    cv::imshow("angle", drawing);
    cv::waitKey(0);
    cv::destroyAllWindows();
}

int main() {
     cv::Mat img = cv::imread("angletest.bmp");
        if (img.empty()) {
            std::cout << "Error loading image: " << std::endl;
            return -1;
        }

        cv::Mat grayImage;
        cv::cvtColor(img, grayImage, cv::COLOR_BGR2GRAY);
        threshold(grayImage, grayImage, 0, 255, THRESH_BINARY + THRESH_OTSU);
        cv::Mat laplacianKernel = (cv::Mat_<float>(5, 5) <<
        0, 0, -1, 0, 0,
        0, -1, -2, -1, 0,
        -1, -2, 16, -2, -1,
        0, -1, -2, -1, 0,
        0, 0, -1, 0, 0);

        // Apply the custom Laplacian kernel
        cv::Mat laplacianFiltered;
        filter2D(grayImage, laplacianFiltered, CV_8U, laplacianKernel);
        calculateAngle(laplacianFiltered);
        return 0;
  }

我正在尝试纳入以下标准来根据其曲率确定轮廓角度:

If the contour curves upwards, the angle should be 180 degrees.
If the contour curves downwards, the angle should be -180 degrees.
If the contour curves leftwards, the angle should be 90 degrees.
If the contour curves rightwards, the angle should be -90 degrees.

这些只是主要方向,其他角度我想相应调整。 我该如何修改我的方法来实现这一目标?

以下是我正在处理的轮廓图像: enter image description here

enter image description here

任何帮助或建议将不胜感激!

c++ opencv image-processing computer-vision
1个回答
0
投票

也许我问错了你的问题。

曲率是您可以根据导数计算轮廓的每个点的值: https://en.wikipedia.org/wiki/Curvature

您是在谈论一个轮廓的单一曲率值吗?

这里还有一个关于 OpenCV 旋转矩形函数的角度返回的很好的总结: https://namkeenman.wordpress.com/2015/12/18/open-cv-define-angle-of-rotatedrect-minareaect/

我认为旋转矩形可以完成这项工作,但也许你必须从结果中减去 90 度,并根据结果切换宽度和高度(请参阅上面的博客文章)。

这就是我计算轮廓角度的方法:

if ( rotatedRect.size.width > rotatedRect.size.height )
{
    const auto length1 =
        static_cast< double >( rotatedRect.size.width ) / 2.0;
    const auto length2 =
        static_cast< double >( rotatedRect.size.height ) / 2.0;
    const auto angle = static_cast< double >( rotatedRect.angle );

    return { length1, length2, angle };
}

const auto length1 = static_cast< double >( rotatedRect.size.height ) / 2.0;
const auto length2 = static_cast< double >( rotatedRect.size.width ) / 2.0;
const auto angle = static_cast< double >( rotatedRect.angle ) - 90.0;

return { length1, length2, angle };

也许你可以添加一个显示轮廓和预期角度的小草图?

© www.soinside.com 2019 - 2024. All rights reserved.