在机器视觉领域,经常会遇到圆环型的检测目标,比如瓶口,轮胎,橡皮圈等等,比如想检测轮胎上的瑕疵,就可以通过把环形区域展开成矩形形状,然后对胎侧进行瑕疵检测,再比如对圆环扣上的字符进行识别,也可以利用该方法,当然也可以直接利用弯曲文本标注进行识别。那么具体如何实现环形区域展开成矩形长条呢?代码如下:
算法实现代码:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/imgproc/types_c.h>
#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;cv::Mat UTCH::Method::CircleToRectangle(const cv::Mat& circle, const cv::Point& Center, int Radius, int RingStride)
{cv::Mat rectangle;rectangle = cv::Mat::zeros(cv::Size(Radius * CV_PI * 2, RingStride), CV_8UC1);//矩形长为int nl = rectangle.rows; // number of lines int nc = rectangle.cols * rectangle.channels(); // total number of elements per linefor (int j = 0; j < nl; j++) {// get the address of row juchar* data = rectangle.ptr<uchar>(j);for (int i = 0; i < nc; i++) {// process each pixel ---------------------double theta = CV_PI * 2.0 / float(nc) * float(i + 1);double rho = Radius - j - 1; //-1防止超界int position_x = (float)Center.x + rho * (float)std::cos(theta) + 0.5;// +0.5四舍五入int position_y = (float)Center.y - rho * (float)std::sin(theta) + 0.5;// +0.5四舍五入data[i] = circle.at<uchar>(position_y, position_x);// end of pixel processing ----------------} // end of line}return rectangle;
}
主函数代码:
#include "myalgrithom.h"
#include <iostream>
#include<windows.h>
using namespace std;int main()
{//读取彩色图像std::string strImgFile = "image/yinzhang.jpg";cv::Mat img = cv::imread(strImgFile);if (img.empty()){std::cout << "image file read failed - " << strImgFile.c_str() << "!" << std::endl;return 0;}//转换灰度图cv::Mat gray;cvtColor(img, gray, cv::COLOR_BGR2GRAY);//GaussianBlur(gray, gray, Size(5, 5), 1.0);//检测最大的圆std::vector<cv::Vec3f> circles;HoughCircles(gray, circles, cv::HOUGH_GRADIENT, 1, 50, 50);//根据检测目标,参数自己调cv::Mat img_copy;img.copyTo(img_copy);int nMaxRadius = 0;cv::Point center;for (int i = 0; i < circles.size(); i++){cv::Vec3f cc = circles[i];//检测到圆的圆心和半径if (nMaxRadius < cc[2]){nMaxRadius = int(cc[2] + 0.5);center = cv::Point(cc[0], cc[1]);}//circle(img_copy, cv::Point(cc[0], cc[1]), cc[2], cv::Scalar(0, 255, 0), 2, cv::LINE_AA);//circle(img_copy, cv::Point(cc[0], cc[1]), 3, cv::Scalar(125, 25, 255), 2, cv::LINE_AA);}circle(img_copy, center, nMaxRadius, cv::Scalar(0, 255, 0), 2, cv::LINE_AA);circle(img_copy, center, 3, cv::Scalar(125, 25, 255), 2, cv::LINE_AA);//将最大的圆环展平,圆环高度为半径的一半cv::Mat result;result=UTCH::Method::CircleToRectangle(gray, center, nMaxRadius, nMaxRadius / 2);cv::flip(result, result,1);if (result.empty()){std::cout << "result is empty!" << std::endl;return 0;}else{//显示结果imshow("result", result);imwrite("result/result.jpg", result);cv::waitKey(0);cv::destroyAllWindows();}
}
其中,输入为
Mat& circle:输入的圆环形原始图像
原图如下
检测到的圆形如下绿线圈出
Point Center: 原始图像中圆环的圆心
int Radius: 原始图像中圆环的半径
int RingStride:圆环的宽度
最终生成的矩形长条,以圆环的外周长为长,以圆环的宽度为高。
转换后结果图:
函数中,从圆环的最外圈开始遍历,最外圈即对应着矩形中的第一行,宽度为多少,则矩形中就有多少行
以圆心为中心构成极坐标系,则圆环上任意一点可以用rho和theta来表示
再根据公式计算出该点在图上的真是坐标,把像素值赋给矩形框中对应的位置。
注:代码并不是拷贝下来就能直接使用的哦,根据自己的情况去修改调试哦,加油宝子们。