我需要计算-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.
这些只是主要方向,其他角度我想相应调整。 我该如何修改我的方法来实现这一目标?
任何帮助或建议将不胜感激!
也许我问错了你的问题。
曲率是您可以根据导数计算轮廓的每个点的值: 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 };
也许你可以添加一个显示轮廓和预期角度的小草图?