Finding Lines

本文介绍了一种通过随机采样解决FindingLines问题的方法。利用概率论原理,通过多次随机选取点集中的两点来判断是否可能找到一条包含特定比例点数的直线。文章提供了完整的C++实现代码。

Finding Lines

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4967

概率

在听题解前毫无头绪,题解帮我打开了新世界的大门:

随机取一个点在答案直线(如果存在这个直线)上的概率是p%,

那么随机取到两个点构成的直线就是答案直线的概率是p%*p%;

也就是说,随机取到两个点构成的直线不是答案直线的概率为1-p%*p%<=24/25.

如果我们每次随机取两个点,判定一下这条直线上是否存在p%*n个点,

进行k次后得到错误答案的概率是(1-p%*p%)k.

k取足够大,可以使错误答案的概率趋向于0;当k=100时,错误概率为0.01687.

注意:n<=2时需要特判

代码如下:

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<ctime>
 4 #define N 100005
 5 using namespace std;
 6 typedef long long ll;
 7 struct point{
 8     ll x,y;
 9 }a[N];
10 ll n,p,ans;
11 ll check(ll first,ll second){
12     ll sum=2;
13     ll x1=a[first].x-a[second].x;
14     ll y1=a[first].y-a[second].y;
15     for(int i=0;i<n;++i){
16         if(i==first||i==second)continue;
17         ll x2=a[i].x-a[second].x;
18         ll y2=a[i].y-a[second].y;
19         if(x1*y2-x2*y1==0)sum++;
20     }
21     if(sum*100-p*n>=0)return 1;
22     return 0;
23 }
24 int main(void){
25     while(cin>>n>>p){
26         for(ll i=0;i<n;++i)
27             cin>>a[i].x>>a[i].y;
28         if(n<=2){
29             cout<<"possible\n";
30             continue;
31         }
32         ans=0;
33         srand((int)time(0));
34         for(ll t=0;t<100;++t){
35             ll first=rand()%n,second=rand()%n;
36             if(first==second)continue;
37             ans+=check(first,second);
38         }
39         if(ans)cout<<"possible\n";
40         else cout<<"impossible\n";
41     }
42 }

 

转载于:https://www.cnblogs.com/barrier/p/6240647.html

#include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp" #include <iostream> using namespace cv; using namespace std; static void help() { cout << "\nThis program demonstrates line finding with the Hough transform.\n" "Usage:\n" "./houghlines <image_name>, Default is ../data/pic1.png\n" << endl; } int main(int argc, char** argv) { cv::CommandLineParser parser(argc, argv, "{help h||}{@image|../data/pic1.png|}" ); if (parser.has("help")) { help(); return 0; } string filename = parser.get<string>("@image"); if (filename.empty()) { help(); cout << "no image_name provided" << endl; return -1; } Mat src = imread(filename, 0); if(src.empty()) { help(); cout << "can not open " << filename << endl; return -1; } Mat dst, cdst; Canny(src, dst, 50, 200, 3); cvtColor(dst, cdst, COLOR_GRAY2BGR); #if 0 vector<Vec2f> lines; HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 ); for( size_t i = 0; i < lines.size(); i++ ) { float rho = lines[i][0], theta = lines[i][1]; Point pt1, pt2; double a = cos(theta), b = sin(theta); double x0 = a*rho, y0 = b*rho; pt1.x = cvRound(x0 + 1000*(-b)); pt1.y = cvRound(y0 + 1000*(a)); pt2.x = cvRound(x0 - 1000*(-b)); pt2.y = cvRound(y0 - 1000*(a)); line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA); } #else vector<Vec4i> lines; HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 ); for( size_t i = 0; i < lines.size(); i++ ) { Vec4i l = lines[i]; line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA); } #endif imshow("source", src); imshow("detected lines", cdst); waitKey(); return 0; }对这段代码详细解析
03-08
<think>嗯,用户让我详细解析一段OpenCV的C++代码。之前用户问过关于vector<Vec2f> lines的问题,现在这个代码看起来是霍夫变换检测直线的例子。我需要先通读代码,理解每个部分的作用。 首先,用户提供的代码包含了头文件,比如imgcodecs、highgui、imgproc,这些是OpenCV常用的模块。然后有using namespace cv和std,这是为了简化代码。静态函数help()用来输出帮助信息,说明程序用途和用法。 主函数里使用了CommandLineParser处理命令行参数,检查是否有帮助请求,并获取图像路径。如果没提供图像或者读取失败,会输出错误信息。这部分是OpenCV命令行程序的常见结构,需要解释清楚。 接着,代码读取灰度图像(imread第二个参数是0),然后进行Canny边缘检测,生成dst。之后将边缘图像转换为彩色图像cdst,可能是因为后面要画彩色线条。 接下来有个条件编译#if 0,里面是用标准的霍夫变换HoughLines,得到的是vector<Vec2f> lines,然后通过极坐标参数画线。而#else部分使用的是HoughLinesP,得到的是vector<Vec4i>,直接画线段的端点。用户可能对这两种方法的区别感兴趣,需要对比说明。 最后显示原图和检测结果,并等待按键。这部分比较直观,但需要指出每个imshow的作用,以及waitKey的必要性。 用户可能的需求是理解整个代码的结构,各个函数的作用,以及霍夫变换的不同方法。他们可能在学习OpenCV的直线检测,或者在调试类似的代码时遇到问题。需要详细解释每个关键步骤,比如Canny的作用,HoughLines和HoughLinesP的区别,参数含义,以及如何将极坐标转换为直线端点。 还要注意代码中的一些细节,比如COLOR_GRAY2BGR的转换,条件编译的使用,以及Vec4i和Vec2f的不同。可能需要用表格或示例说明两种霍夫变换的输出差异。同时,用户可能想知道如何选择参数,比如Canny的阈值,霍夫变换的阈值等,对结果的影响。 确保解释清晰,结构分明,分点说明,让用户能逐步理解代码的每个部分,以及背后的原理和用途。如果有更好的实践建议,比如参数调整或方法选择,也可以加入,帮助用户更好地应用这段代码。</think>以下是对这段OpenCV霍夫直线检测代码的详细解析(按代码执行顺序分模块说明): --- ### **Ⅰ. 头文件命名空间** ```cpp #include "opencv2/imgcodecs.hpp" // 图像读写 #include "opencv2/highgui.hpp" // 图形界面 #include "opencv2/imgproc.hpp" // 图像处理算法 #include <iostream> // 输入输出流 using namespace cv; // OpenCV命名空间 using namespace std; // 标准库命名空间 ``` - `imgproc.hpp` 包含霍夫变换等核心算法 - `highgui.hpp` 提供`imshow`等显示功能 - 命名空间简化代码书写(实际工程中建议显式指定) --- ### **Ⅱ. 帮助函数** ```cpp static void help() { cout << "\n演示霍夫直线检测的用法..." << endl; } ``` - 输出程序用途和默认图像路径 - 通过`CommandLineParser`触发显示 --- ### **Ⅲ. 主函数结构** #### **1. 命令行参数解析** ```cpp cv::CommandLineParser parser(argc, argv, "{help h||}{@image|../data/pic1.png|}"); if (parser.has("help")) { help(); return 0; } ``` - `{help h||}`:定义帮助参数`-h/--help` - `{@image|...|}`:定义位置参数,默认使用`pic1.png` #### **2. 图像加载验证** ```cpp string filename = parser.get<string>("@image"); Mat src = imread(filename, 0); // 以灰度模式读取 if(src.empty()) { /* 错误处理 */ } ``` - `imread`第二个参数`0`表示`IMREAD_GRAYSCALE` - 必须验证图像是否加载成功 --- ### **Ⅳ. 核心处理流程** #### **1. 边缘检测** ```cpp Mat dst, cdst; Canny(src, dst, 50, 200, 3); // Canny边缘检测 cvtColor(dst, cdst, COLOR_GRAY2BGR); // 转换为彩色图像 ``` - Canny参数: - 低阈值:50 - 高阈值:200(高低阈值比建议1:2或1:3) - Sobel核大小:3×3 #### **2. 霍夫直线检测(两种模式)** ```cpp #if 0 // 标准霍夫变换(检测无限长直线) vector<Vec2f> lines; HoughLines(dst, lines, 1, CV_PI/180, 100); #else // 概率霍夫变换(检测线段) vector<Vec4i> lines; HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10); #endif ``` - **参数对比表**: | 参数 | HoughLines | HoughLinesP | |------------------|------------------|-------------------| | 输出类型 | vector<Vec2f> | vector<Vec4i> | | 检测目标 | 直线(无限长) | 线段(有限长度) | | 第5个参数 | 累加器阈值 | 累加器阈值 | | 特有参数 | 无 | 最小线段长度(50)、最大间隔(10) | #### **3. 直线绘制** **模式1:极坐标→直角坐标转换** ```cpp double a = cos(theta), b = sin(theta); double x0 = a*rho, y0 = b*rho; // 计算直线端点(延长1000像素) pt1.x = cvRound(x0 + 1000*(-b)); pt2.x = cvRound(x0 - 1000*(-b)); ``` - 通过三角函数将(rho,theta)转换为两点式 **模式2:直接绘制线段** ```cpp line(cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA); ``` - `Vec4i`直接存储线段端点坐标(x1,y1,x2,y2) --- ### **Ⅴ. 结果显示** ```cpp imshow("source", src); // 显示原始图像 imshow("detected lines", cdst);// 显示检测结果 waitKey(); // 保持窗口显示 ``` - `waitKey()`参数为0时无限等待,无参数时需任意键继续 --- ### **Ⅵ. 关键函数原型** ```cpp // 标准霍夫变换 void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0); // 概率霍夫变换 void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0); ``` --- ### **Ⅶ. 效果优化建议** 1. **Canny参数调整**:根据实际图像调整阈值组合 2. **霍夫参数调节**: - 提高累加器阈值可减少误检 - 降低角度分辨率(增大`theta`步长)提升速度 3. **后处理**: ```cpp GaussianBlur(src, src, Size(3,3), 0); // 预处理降噪 dilate(edges, edges, Mat()); // 边缘连接 ``` --- ### **Ⅷ. 代码执行示意图** ``` 原始图像 → 灰度化 → Canny边缘 → 霍夫变换 → 直线绘制 (src) (dst) (lines) (cdst) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值