前言
在OpenCV中,查找直线是经常需要用到的功能,故此用C++实现了一个寻找直线的卡尺工具。
一、卡尺工具的原理
卡尺工具的原理是基于图像边缘检测的方法,用于测量图像中的线段长度和角度。它通过在图像中选择两个点,然后沿着直线方向上的像素进行采样,通过计算采样点的像素值,可以得到线段的长度和角度等信息
二、卡尺工具的C++实现
#include <opencv2/opencv.hpp>
using namespace cv;
void DetectLines(cv::Mat srcImage, cv::Rect rect, int searchFlag, int maxGrad, int thresholdValue, bool isErode, int kernelSize, cv::Point& p1, cv::Point& p2) //二值化直线拟合检测
{
if (srcImage.channels() == 3)
cv::cvtColor(srcImage, srcImage, cv::COLOR_BGR2GRAY);
cv::Mat m_resultImg = srcImage(rect).clone();
threshold(m_resultImg, m_resultImg, thresholdValue, 255, THRESH_BINARY);
if (isErode)
{
Mat element = getStructuringElement(0, Size(kernelSize, kernelSize), Point(-1, -1));
erode(m_resultImg, m_resultImg, element); //腐蚀操作
}
std::vector<Point2f> onefitlinepoints;
switch (searchFlag)
{
case 0:
{
//从左到右查找
for (int y = 0; y < m_resultImg.rows; y++)
{
for (int x = 0; x < m_resultImg.cols; x++)
{
if ((int)m_resultImg.at<uchar>(y, x) == maxGrad)
{
onefitlinepoints.push_back(Point(y, x));
break;
}
}
}
break;
}
case 1:
{
//从右到左查找
for (int y = m_resultImg.rows - 1; y > 0; y--)
{
for (int x = m_resultImg.cols - 1; x > 0; x--)
{
if ((int)m_resultImg.at<uchar>(y, x) == maxGrad)
{
onefitlinepoints.push_back(Point(y, x));
break;
}
}
}
break;
}
case 2:
{
//从上到下查找
for (int x = m_resultImg.cols - 1; x > 0; x--)
{
for (int y = 0; y < m_resultImg.rows; y++)
{
if ((int)m_resultImg.at<uchar>(y, x) == maxGrad)
{
onefitlinepoints.push_back(Point(x, y));
break;
}
}
}
break;
}
case 3:
{
//从下到上查找
for (int x = m_resultImg.cols - 1; x > 0; x--)
{
for (int y = m_resultImg.rows - 1; y > 0; y--)
{
if ((int)m_resultImg.at<uchar>(y, x) == maxGrad)
{
onefitlinepoints.push_back(Point(x, y));
break;
}
}
}
break;
}
}
Vec4f oneline;
cv::fitLine(onefitlinepoints, oneline, cv::DIST_L1, 0, 0.01, 0.01); //根据给定的点集(比如轮廓)拟合出一条直线
Point2f point1, point2, point3;
point2.x = oneline[2];
point2.y = oneline[3];
double k = oneline[1] / oneline[0];
从左到右或从右到左
if (searchFlag == 1 || searchFlag == 0)
{
point1.y = rect.y;
point1.x = (k * (0 - point2.x) + point2.y) + rect.x;
point3.y = rect.y + rect.height;
point3.x = (k * (m_resultImg.rows - point2.x) + point2.y) + rect.x;
}
/从下到上或从上到下
else if (searchFlag == 3 || searchFlag == 2)
{
point1.x = rect.x;
point1.y = (k * (0 - point2.x) + point2.y) + rect.y;
point3.x = rect.x + rect.width;
point3.y = (k * (m_resultImg.cols - point2.x) + point2.y) + rect.y;
}
p1 = point1;
p2 = point3;
cv::cvtColor(srcImage, srcImage, COLOR_GRAY2RGB);
cv::line(srcImage, point1, point3, cv::Scalar(0, 0, 255), 5, 1, 0);
rectangle(srcImage, rect, Scalar(0, 255, 0), 5, 8, 0); //根据初始点和结束点,将矩形画到img上
cv::imwrite("./Datas/detectedLine.png", srcImage);
}
int main()
{
cv::Mat src = cv::imread("./Datas/1.png", 0);
cv::Rect rect(0, 0, src.cols, src.rows);
cv::Point p1, p2;
DetectLines(src, rect, 2, 0, 70, true, 3, p1, p2);
system("pause");
return 0;
}
三、 测试结果
原图
结果图片