圆形物体旋转角度检测

Dun*_*gNH 7 python opencv

我正在尝试检测两个圆形物体之间的角度差异,如下图 2 所示。

我正在考虑以一些小角度旋转其中一张图像。每次旋转一张图像时,都会计算旋转图像和另一张图像之间的 SSIM。SSIM 最大的角度就是角度差。

但是,找到极端从来都不是一件容易的事。所以我的问题是:在这种情况下是否可以使用其他算法(opencv)?

图片#1 主图

图片#2 在此输入图像描述

编辑:

谢谢@Micka,我只是按照他建议的方式进行操作,并像@Yves Daoust 所说的那样删除黑色区域,以缩短处理时间。这是我的最终结果:

原图 图片1 旋转 + 移动图像 图2

Mic*_*cka 8

这是一种方法:

\n
    \n
  1. 检测圆圈(例如,我假设圆圈位于图像中心,半径为图像宽度的 50%)
  2. \n
  3. 通过极坐标展开圆形图像
  4. \n
  5. 确保第二个图像在第一个图像中完全可见,没有“圆端溢出”
  6. \n
  7. 简单的模板匹配
  8. \n
\n

以下代码的结果:

\n
min: 9.54111e+07\npos: [0, 2470]\nangle-right: 317.571\nangle-left: -42.4286\n
Run Code Online (Sandbox Code Playgroud)\n

我认为这通常应该运作得很好。

\n
int main()\n{\n    // load images\n    cv::Mat image1 = cv::imread("C:/data/StackOverflow/circleAngle/circleAngle1.jpg");\n    cv::Mat image2 = cv::imread("C:/data/StackOverflow/circleAngle/circleAngle2.jpg");\n\n    // generate circle information. Here I assume image center and image is filled by the circles.\n    // use houghCircles or a RANSAC based circle detection instead, if necessary\n    cv::Point2f center1 = cv::Point2f(image1.cols/2.0f, image1.rows/2.0f);\n    cv::Point2f center2 = cv::Point2f(image2.cols / 2.0f, image2.rows / 2.0f);\n    float radius1 = image1.cols / 2.0f;\n    float radius2 = image2.cols / 2.0f;\n\n    cv::Mat unrolled1, unrolled2;\n    // define a size for the unrolling. Best might be to choose the arc-length of the circle. The smaller you choose this, the less resolution is available (the more pixel information of the circle is lost during warping)\n    cv::Size unrolledSize(radius1, image1.cols * 2);\n\n    // unroll the circles by warpPolar\n    cv::warpPolar(image1, unrolled1, unrolledSize, center1, radius1, cv::WARP_POLAR_LINEAR);\n    cv::warpPolar(image2, unrolled2, unrolledSize, center2, radius2, cv::WARP_POLAR_LINEAR);\n\n    // double the first image (720\xc2\xb0 of the circle), so that the second image is fully included without a "circle end overflow"\n    cv::Mat doubleImg1;\n    cv::vconcat(unrolled1, unrolled1, doubleImg1);\n\n    // the height of the unrolled image is exactly 360\xc2\xb0 of the circle\n    double degreesPerPixel = 360.0 / unrolledSize.height;\n\n    // template matching. Maybe correlation could be the better matching metric\n    cv::Mat matchingResult;\n    cv::matchTemplate(doubleImg1, unrolled2, matchingResult, cv::TemplateMatchModes::TM_SQDIFF);\n\n    double minVal; double maxVal; cv::Point minLoc; cv::Point maxLoc;\n    cv::Point matchLoc;\n    cv::minMaxLoc(matchingResult, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());\n\n    std::cout << "min: " << minVal << std::endl;\n    std::cout << "pos: " << minLoc << std::endl;\n\n    // angles in clockwise direction:\n    std::cout << "angle-right: " << minLoc.y * degreesPerPixel << std::endl;\n    std::cout << "angle-left: " << minLoc.y * degreesPerPixel -360.0 << std::endl;\n    double foundAngle = minLoc.y * degreesPerPixel;\n    \n    // visualizations:\n    // display the matched position\n    cv::Rect pos = cv::Rect(minLoc, cv::Size(unrolled2.cols, unrolled2.rows));\n    cv::rectangle(doubleImg1, pos, cv::Scalar(0, 255, 0), 4);\n\n    // resize because the images are too big\n    cv::Mat resizedResult;\n    cv::resize(doubleImg1, resizedResult, cv::Size(), 0.2, 0.2);\n    \n    cv::resize(unrolled1, unrolled1, cv::Size(), 0.2, 0.2);\n    cv::resize(unrolled2, unrolled2, cv::Size(), 0.2, 0.2);\n\n    double startAngleUpright = 0;\n    cv::ellipse(image1, center1, cv::Size(100, 100), 0, startAngleUpright, startAngleUpright + foundAngle, cv::Scalar::all(255), -1, 0);\n\n    cv::resize(image1, image1, cv::Size(), 0.5, 0.5);\n    cv::imshow("image1", image1);\n\n    cv::imshow("unrolled1", unrolled1);\n    cv::imshow("unrolled2", unrolled2);\n\n    cv::imshow("resized", resizedResult);\n\n    cv::waitKey(0);\n\n    \n}\n
Run Code Online (Sandbox Code Playgroud)\n

中间图像和结果如下所示:

\n

展开的图像 1 / 展开的 2 / 展开的 1 (720\xc2\xb0) / 展开的 2 在展开的 1 (720\xc2\xb0) 中的最佳匹配:

\n

\n