Opencv 使用线条绘制简单图形的近似照片
作为输入,我有一张简单符号的照片,例如: 我想检测其中的直线,比如直线的起点和终点。在这种情况下,假设符号的左上角为(0,0),则行的定义如下:Opencv 使用线条绘制简单图形的近似照片,opencv,line,detection,approximation,Opencv,Line,Detection,Approximation,作为输入,我有一张简单符号的照片,例如: 我想检测其中的直线,比如直线的起点和终点。在这种情况下,假设符号的左上角为(0,0),则行的定义如下: 起点-终点(直线起点和终点的坐标) 1.(0,0); (0,10)(垂直线) 2.(0,10); (15,15) 3.(15,15); (0,20) 4.(0,20); (0,30) 我如何做到这一点(完全使用OpenCV)?我想是关于霍夫线的,但它们似乎适合完美的细直线,而在绘画中则不是这样。我可能也会处理二值化图像。您应该尝试霍夫线变换。这里有一个
起点-终点(直线起点和终点的坐标)
1.(0,0); (0,10)(垂直线)
2.(0,10); (15,15)
3.(15,15); (0,20)
4.(0,20); (0,30)
我如何做到这一点(完全使用OpenCV)?我想是关于霍夫线的,但它们似乎适合完美的细直线,而在绘画中则不是这样。我可能也会处理二值化图像。您应该尝试
霍夫线变换。这里有一个来自
#包括“opencv2/highgui/highgui.hpp”
#包括“opencv2/imgproc/imgproc.hpp”
#包括
使用名称空间cv;
使用名称空间std;
int main()
{
Mat src=imread(“building.jpg”,0);
Mat-dst,cdst;
Canny(src、dst、50、200、3);
CVT颜色(dst、cdst、CV_GRAY2BGR);
矢量线;
//探测线
HoughLines(dst,lines,1,CV_PI/180,150,0,0);
//划线
对于(size_t i=0;i
有了这个,你应该能够调整并获得你想要的属性(顶点)。试试这个
应用于阈值图像
对于找到的轮廓
见一些参考资料:
也许你可以做这个
- 假设一个完美的二值化:
- 运行HoughLinesP
- (未实现)尝试对检测到的行进行分组
我使用了以下代码:
int main()
{
cv::Mat image = cv::imread("HoughLinesP_perfect.png");
cv::Mat gray;
cv::cvtColor(image,gray,CV_BGR2GRAY);
cv::Mat output; image.copyTo(output);
cv::Mat g_thres = gray == 0;
std::vector<cv::Vec4i> lines;
//cv::HoughLinesP( binary, lines, 1, 2*CV_PI/180, 100, 100, 50 );
// cv::HoughLinesP( h_thres, lines, 1, CV_PI/180, 100, image.cols/2, 10 );
cv::HoughLinesP( g_thres, lines, 1, CV_PI/(4*180.0), 50, image.cols/20, 10 );
for( size_t i = 0; i < lines.size(); i++ )
{
cv::line( output, cv::Point(lines[i][0], lines[i][3]),
cv::Point(lines[i][4], lines[i][3]), cv::Scalar(155,255,155), 1, 8 );
}
cv::imshow("g thres", g_thres);
cv::imwrite("HoughLinesP_out.png", output);
cv::resize(output, output, cv::Size(), 0.5,0.5);
cv::namedWindow("output"); cv::imshow("output", output);
cv::waitKey(-1);
std::cout << "finished" << std::endl;
return 0;
}
intmain()
{
cv::Mat image=cv::imread(“HoughLinesP_perfect.png”);
cv::席灰色;
cv::CVT颜色(图像,灰色,cv_bgr2灰色);
cv::Mat输出;image.copyTo(输出);
cv::Mat g_thres=灰色==0;
std::矢量线;
//cv::HoughLinesP(二进制,行,1,2*cv_PI/180100100,50);
//cv::HoughLinesP(h_thres,lines,1,cv_PI/180100,image.cols/2,10);
cv::HoughLinesP(g_thres,lines,1,cv_PI/(4*180.0),50,image.cols/20,10);
对于(size_t i=0;i=0)
{
行_过滤[覆盖]=行[i];
}
其他的
{
行过滤。向后推(行[i]);
}
}
}
对于(size\u t i=0;i std::我不能感谢您的意见。我决定试试你的想法,但正如我担心的那样,它似乎不合适。在调整一些参数后,您可以在这里看到我的结果:;我先用大津阈值对它进行了二值化,但它似乎不会影响结果。我想主要的问题是,由于边缘的原因,我必须平行线,但即使不是这样,它也会检测最直的线-调整参数可能会有所帮助,但它不是通用的。还有其他想法吗?谢谢!实际上可能就是这样。我会检查一下,稍后发布我的结果:)我按照你的建议做了,这正是我所需要的。再次感谢:)谢谢。这是一个非常有趣的方法,我认为它实际上可以工作。然而,对于我的例子来说,这种分组在计算上可能太昂贵了。然后,也许可以尝试一些细化,尝试HoughLinesP而不是HoughLines,因为它更适合非完美线。但是你可能不想分组,而只想选择最长的“相似”线,我想这并不需要花费太多的计算时间。是的,但是你仍然需要创建“相似”线的分组,所以这会变得更复杂。我将尝试使用Haris提出的方法,但我会记住您的方法。@user3704596使用简单的相似行聚类编辑了我的答案,只是为了完成谢谢您的努力!事实上,我检查了你的解决方案,效果很好。我决定使用另一个,因为它一次给出了近似的直线,这让我可以很容易地计算相邻直线之间的角度。谢谢
float minimum_distance(cv::Point2f v, cv::Point2f w, cv::Point2f p) {
// Return minimum distance between line segment vw and point p
const float l2 = cv::norm(w-v) * cv::norm(w-v); // i.e. |w-v|^2 - avoid a sqrt
if (l2 == 0.0) return cv::norm(p-v); // v == w case
// Consider the line extending the segment, parameterized as v + t (w - v).
// We find projection of point p onto the line.
// It falls where t = [(p-v) . (w-v)] / |w-v|^2
//const float t = dot(p - v, w - v) / l2;
float t = ((p-v).x * (w-v).x + (p-v).y * (w-v).y)/l2;
if (t < 0.0) return cv::norm(p-v); // Beyond the 'v' end of the segment
else if (t > 1.0) return cv::norm(p-w); // Beyond the 'w' end of the segment
const cv::Point2f projection = v + t * (w - v); // Projection falls on the segment
return cv::norm(p - projection);
}
int main()
{
cv::Mat image = cv::imread("HoughLinesP_perfect.png");
cv::Mat gray;
cv::cvtColor(image,gray,CV_BGR2GRAY);
cv::Mat output; image.copyTo(output);
cv::Mat g_thres = gray == 0;
std::vector<cv::Vec4i> lines;
cv::HoughLinesP( g_thres, lines, 1, CV_PI/(4*180.0), 50, image.cols/20, 10 );
float minDist = 100;
std::vector<cv::Vec4i> lines_filtered;
for( size_t i = 0; i < lines.size(); i++ )
{
bool keep = true;
int overwrite = -1;
cv::Point2f a(lines[i][0], lines[i][6]);
cv::Point2f b(lines[i][7], lines[i][3]);
float lengthAB = cv::norm(a-b);
for( size_t j = 0; j < lines_filtered.size(); j++ )
{
cv::Point2f c(lines_filtered[j][0], lines_filtered[j][8]);
cv::Point2f d(lines_filtered[j][9], lines_filtered[j][3]);
float distCDA = minimum_distance(c,d,a);
float distCDB = minimum_distance(c,d,b);
float lengthCD = cv::norm(c-d);
if((distCDA < minDist) && (distCDB < minDist))
{
if(lengthCD >= lengthAB)
{
keep = false;
}
else
{
overwrite = j;
}
}
}
if(keep)
{
if(overwrite >= 0)
{
lines_filtered[overwrite] = lines[i];
}
else
{
lines_filtered.push_back(lines[i]);
}
}
}
for( size_t i = 0; i < lines_filtered.size(); i++ )
{
cv::line( output, cv::Point(lines_filtered[i][0], lines_filtered[i][10]),
cv::Point(lines_filtered[i][11], lines_filtered[i][3]), cv::Scalar(155,255,155), 2, 8 );
}
cv::imshow("g thres", g_thres);
cv::imwrite("HoughLinesP_out.png", output);
cv::resize(output, output, cv::Size(), 0.5,0.5);
cv::namedWindow("output"); cv::imshow("output", output);
cv::waitKey(-1);
std::cout << "finished" << std::endl;
return 0;
}