当前位置: 首页 > wzjs >正文

纳溪区城乡住房建设局网站南京企业网站建设

纳溪区城乡住房建设局网站,南京企业网站建设,自己编写网站,免费一键生成名片教程:深入理解轮廓、采样点与 pointPolygonTest 及其在测量线距中的应用 1. 轮廓与采样点 1.1 轮廓是什么? 在图像处理中,轮廓(contour) 是指图像中物体的边界或边缘。例如: 一个圆形物体的轮廓是圆周。…

教程:深入理解轮廓、采样点与 pointPolygonTest 及其在测量线距中的应用


1. 轮廓与采样点

1.1 轮廓是什么?

在图像处理中,轮廓(contour) 是指图像中物体的边界或边缘。例如:

  • 一个圆形物体的轮廓是圆周。
  • 一个方形物体的轮廓是四条边的集合。

在 OpenCV 中,轮廓是通过 findContours 函数检测出来的,结果是一个由多个点组成的列表,这些点被称为采样点。但需要明确以下两点:

  • 真实轮廓:是连续的边界线,比如一个完整的圆周或方形的四条边。
  • 采样点:是这条连续边界上的离散点,用于近似表示轮廓。

图示(用文字模拟):

真实轮廓(连续的边界)/\/  \/    \
/______\采样点(离散的点).  ..      .
.        .
  • 真实轮廓:一条完整的、连续的线。
  • 采样点:在这条线上抽取的一些点,可能稀疏也可能密集,取决于检测算法的参数(如 CV_CHAIN_APPROX_SIMPLECV_CHAIN_APPROX_NONE)。
1.2 采样点的意义与局限性

采样点是轮廓的离散表示,OpenCV 使用这些点之间的直线段来近似描述整个轮廓。也就是说,轮廓的边界不仅仅是这些采样点本身,还包括它们之间的连线。

举个例子
假设有一个正方形轮廓,采样点是四个顶点:

  • (0,0)

  • (10,0)

  • (10,10)

  • (0,10)

  • 真实轮廓:包括四条边上的所有点,例如 (5,0)(在底边上)、(10,5)(在右边上)。

  • 采样点:只有四个顶点,(5,0) 并不是采样点,但它是轮廓边界的一部分。

图示(文字模拟):

正方形轮廓:
(0,0) ---- (10,0)|           |
(0,10) --- (10,10)边界上的点(非采样点):
(5,0) 在底边上,(10,5) 在右边上

局限性
采样点是离散的,无法完全覆盖轮廓的每一个位置。如果只关注采样点本身,可能会忽略边界上其他关键点的位置。例如,(5,0) 不在采样点中,但它是轮廓的一部分,在计算距离时可能非常重要。


2. pointPolygonTest 函数详解

2.1 函数的作用

pointPolygonTest 是 OpenCV 中一个非常有用的函数,它的主要功能是:
计算一个点到轮廓边界的最短距离。

函数签名(简化版):

distance = cv2.pointPolygonTest(contour, pt, measureDist=True)
  • contour:轮廓的采样点列表(比如正方形的四个顶点)。
  • pt:要测试的点坐标,比如 (15,5)
  • measureDist=True:表示返回实际距离(而不是仅仅判断点在轮廓内、外还是边界上)。

返回值

  • 正值:点在轮廓外部,值是到边界的最短距离。
  • 负值:点在轮廓内部,值是到边界的最短距离的负数。
  • 0:点在轮廓边界上。

在测量线距的代码中,通常会使用 abs 取绝对值,确保距离总是正数。

2.2 计算的是什么距离?

你可能会问:这个距离是到采样点的距离吗?
答案是否定的
pointPolygonTest 计算的是点到轮廓整个边界的最短距离,而不是仅仅到某个采样点的距离。轮廓的边界包括采样点以及它们之间的直线段。

举个例子
假设轮廓是一个正方形,采样点是:

  • (0,0)
  • (10,0)
  • (10,10)
  • (0,10)

测试点 pt = (15,5)

  • 如果只计算到采样点的距离

    • (10,0) 的距离 = √((15-10)² + (5-0)²) ≈ 7.07
    • (10,10) 的距离 = √((15-10)² + (5-10)²) ≈ 7.07
    • (0,0) 的距离 = √((15-0)² + (5-0)²) ≈ 15.81
    • (0,10) 的距离 = √((15-0)² + (5-10)²) ≈ 15.81
    • 最小距离 ≈ 7.07。
  • 实际 pointPolygonTest 的计算

    • 轮廓的右边是 (10,0)(10,10) 的直线段。
    • pt = (15,5) 到这条边的最近点是 (10,5)(垂直投影点)。
    • 距离 = |15 - 10| = 5。

结果pointPolygonTest 返回 5,而不是 7.07。

图示(文字模拟):

正方形轮廓:
(0,0) ---- (10,0)|           |
(0,10) --- (10,10)点 pt:(15,5)  <- 到右边界的最近点是 (10,5),距离 = 5

结论
pointPolygonTest 考虑的是轮廓的连续边界(采样点之间的直线段),而不是仅仅计算到采样点的距离。这也是它在测量线距时更准确的原因,因为它能捕捉到边界上非采样点的贡献。


3. 为什么需要双向计算?

在测量两个轮廓之间的距离时,代码通常会进行双向计算:

  • 从轮廓 A 的采样点到轮廓 B 的距离。
  • 从轮廓 B 的采样点到轮廓 A 的距离。
    然后取两者的最小值作为最终结果。为什么不能只算一个方向呢?
3.1 单向计算的不足

单向计算(比如只从轮廓 A 到轮廓 B)可能会漏掉某些关键的最近点。因为两个轮廓的形状可能复杂,采样点的分布也不均匀,单向计算无法保证捕捉到全局最小距离。

举个例子

  • 轮廓 A:一个五角星形状,有尖锐的角。
  • 轮廓 B:一个圆形。

图示(文字模拟):

五角星(轮廓 A)       圆(轮廓 B)/\                  O/  \                / \/    \              /   \
  • 只从轮廓 B(圆)到轮廓 A(五角星)计算

    • 圆的采样点可能是均匀分布的,比如 12 个点(像时钟上的刻度)。
    • 这些点到五角星的距离可能都不包括五角星尖角到圆的最短距离(因为尖角可能不在圆的采样点附近)。
  • 反过来,从轮廓 A 到轮廓 B 计算

    • 五角星的采样点包括尖角(比如 (5,10))。
    • pointPolygonTest 从尖角 (5,10) 到圆的边界,可能会发现更小的距离(比如尖角几乎碰到圆)。

结果

  • 单向计算(从圆到五角星)可能得到较大的距离(比如 10)。
  • 双向计算能捕捉到更小的距离(比如 2)。
3.2 双向计算的优势
  • 全面性:从两个方向计算,利用了两组采样点,增加了捕捉最近点的机会。
  • 弥补采样点的局限性:采样点只是轮廓的近似,双向计算通过 pointPolygonTest 考虑了两条边界的完整形状。

结论
双向计算确保了无论轮廓形状如何复杂,都能找到两个轮廓之间的全局最小距离。这是算法鲁棒性的关键。


4. 综合例子

假设我们有两个轮廓:

  • 轮廓 A:正方形,采样点 (0,0), (10,0), (10,10), (0,10)
  • 轮廓 B:三角形,采样点 (15,0), (20,5), (15,10)

目标:计算两轮廓的最短距离。

  1. 从轮廓 A 到轮廓 B

    • (10,0) 到三角形边界的最短距离(用 pointPolygonTest 计算)。
      • 三角形底边 (15,0)(20,5)(10,0) 的最近点可能是 (15,0),距离 = 5。
    • (10,10) 到三角形边界的最短距离。
      • 三角形顶边 (15,10)(20,5)(10,10) 的最近点可能是 (15,10),距离 = 5。
    • 其他点如 (0,0)(0,10) 距离更远。
    • 最小值 ≈ 5。
  2. 从轮廓 B 到轮廓 A

    • (15,0) 到正方形边界的最短距离。
      • 正方形右边 (10,0)(10,10),最近点 (10,0),距离 = 5。
    • (20,5) 到正方形边界的最短距离。
      • 正方形右边 (10,0)(10,10),最近点 (10,5),距离 = 10。
    • (15,10) 到正方形边界的最短距离。
      • 正方形顶边 (0,10)(10,10),最近点 (10,10),距离 = 5。
    • 最小值 ≈ 5。
  3. 最终结果

    • 比较两方向的最小值(5 和 5),全局最小距离 = 5。

图示(文字模拟):

正方形(轮廓 A)       三角形(轮廓 B)
(0,0) ---- (10,0)         (15,0)|           |               \
(0,10) --- (10,10)            (20,5)/(15,10)

5. 代码实现与详细讲解:getLineSpace 函数

5.1 代码功能

getLineSpace 函数的目的是测量图像中两个最大轮廓之间的最小距离。输入参数包括:

  • src:原始图像。
  • mask:掩膜,用于过滤感兴趣区域。
  • result:输出参数,存储计算出的最小距离。
  • rects:输出参数,存储两个轮廓的旋转矩形。
5.2 完整代码
int getLineSpace(Mat src, Mat mask, double& result, vector<RotatedRect>& rects) {if (src.empty() || mask.empty()) return 0;Mat dst;if (src.channels() != 1) {cvtColor(src, dst, CV_BGR2GRAY);bitwise_and(dst, mask, dst);} else {bitwise_and(src, mask, dst);}if (IsEmptyMat(dst)) return 0;vector<vector<Point>> contours;findContours(dst, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);if (contours.size() < 2) return 0;// 找出两个最大轮廓double maxArea1 = 0, maxArea2 = 0;int id1 = -1, id2 = -1;for (size_t i = 0; i < contours.size(); i++) {double area = contourArea(contours[i]);if (area > maxArea1) {maxArea2 = maxArea1;id2 = id1;maxArea1 = area;id1 = i;} else if (area > maxArea2) {maxArea2 = area;id2 = i;}}vector<vector<Point>> twoContours = { contours[id1], contours[id2] };rects = { minAreaRect(contours[id1]), minAreaRect(contours[id2]) };if (rects.size() != 2) return 0;// 双向计算最小距离double minDist = 2500;for (const auto& pt : twoContours[1]) {double realDist = abs(pointPolygonTest(twoContours[0], pt, true));if (minDist > realDist) minDist = realDist;}for (const auto& pt : twoContours[0]) {double realDist = abs(pointPolygonTest(twoContours[1], pt, true));if (minDist > realDist) minDist = realDist;}result = minDist;return 1;
}
5.3 详细讲解
5.3.1 图像预处理:为轮廓检测做准备
if (src.empty() || mask.empty()) return 0;
Mat dst;
if (src.channels() != 1) {cvtColor(src, dst, CV_BGR2GRAY);bitwise_and(dst, mask, dst);
} else {bitwise_and(src, mask, dst);
}
if (IsEmptyMat(dst)) return 0;
  • 输入检查
    • 检查输入图像 src 和掩膜 mask 是否为空。如果为空,返回 0,表示处理失败。这是基本的鲁棒性设计,避免后续操作崩溃。
  • 图像转换与掩膜应用
    • 如果 src 是多通道图像(例如彩色图像,channels() != 1),通过 cvtColor 将其转换为灰度图,存储在 dst 中。然后,使用 bitwise_and 将灰度图与 mask 按位与,保留掩膜中非零区域的像素。
    • 如果 src 已为单通道图像(例如灰度图),直接与 mask 按位与,结果存储在 dst 中。
    • 目的:无论输入是什么格式,最终得到一个单通道的 dst,其中只包含掩膜允许的区域。例如,在文档扫描中,掩膜可以屏蔽背景,只保留文本行。
  • 结果检查
    • 使用 IsEmptyMat(dst) 检查 dst 是否为空(例如掩膜将所有像素都屏蔽,导致 dst 全为零)。如果是,返回 0,表示没有可处理的区域。
5.3.2 轮廓检测:找到图像中的对象边界
vector<vector<Point>> contours;
findContours(dst, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
if (contours.size() < 2) return 0;
  • 轮廓检测
    • 使用 OpenCV 的 findContours 函数在 dst 上检测轮廓:
      • CV_RETR_EXTERNAL:只检测最外层的轮廓,忽略嵌套的内部轮廓。
      • CV_CHAIN_APPROX_NONE:保留轮廓上的所有点,而不是简化轮廓(如 CV_CHAIN_APPROX_SIMPLE 只保留拐点)。
      • 结果存储在 contours 中,每个轮廓是一个 vector<Point>,表示边界上的采样点序列。
  • 轮廓数量检查
    • 如果检测到的轮廓数量少于 2 个,返回 0。因为目标是计算两个轮廓之间的距离,至少需要两个轮廓才能继续。
5.3.3 选择两个最大轮廓:聚焦主要目标
double maxArea1 = 0, maxArea2 = 0;
int id1 = -1, id2 = -1;
for (size_t i = 0; i < contours.size(); i++) {double area = contourArea(contours[i]);if (area > maxArea1) {maxArea2 = maxArea1;id2 = id1;maxArea1 = area;id1 = i;} else if (area > maxArea2) {maxArea2 = area;id2 = i;}
}
vector<vector<Point>> twoContours = { contours[id1], contours[id2] };
rects = { minAreaRect(contours[id1]), minAreaRect(contours[id2]) };
if (rects.size() != 2) return 0;
  • 找出最大轮廓
    • 初始化变量:
      • maxArea1maxArea2:记录最大和次大面积。
      • id1id2:记录对应轮廓的索引。
    • 遍历所有轮廓,使用 contourArea 计算每个轮廓的面积。
    • 如果当前面积大于 maxArea1
      • 将原来的 maxArea1 降级为 maxArea2id1 降级为 id2
      • 更新 maxArea1id1 为当前值。
    • 如果当前面积大于 maxArea2 但小于 maxArea1,只更新 maxArea2id2
  • 存储最大轮廓
    • 将面积最大的两个轮廓(contours[id1]contours[id2])存储在 twoContours 中。
  • 生成旋转矩形
    • 对两个轮廓分别调用 minAreaRect,生成最小面积的旋转矩形,存储在 rects 中。rects 是一个输出参数,可能用于后续可视化或分析。
  • 检查
    • 如果 rects 的大小不是 2,返回 0,确保后续操作基于两个有效轮廓。
  • 为什么要选最大轮廓?
    • 在实际应用中(例如文档分析),图像可能包含许多小噪声轮廓。选择面积最大的两个轮廓可以聚焦于主要目标(例如两条主要的文本行),过滤掉无关的小区域。
5.3.4 双向计算最小距离:确保全局最优
double minDist = 2500;
for (const auto& pt : twoContours[1]) {double realDist = abs(pointPolygonTest(twoContours[0], pt, true));if (minDist > realDist) minDist = realDist;
}
for (const auto& pt : twoContours[0]) {double realDist = abs(pointPolygonTest(twoContours[1], pt, true));if (minDist > realDist) minDist = realDist;
}
result = minDist;
return 1;
  • 初始化
    • minDist 初始化为 2500(一个较大的值),作为最小距离的初始基准。这个值应大于图像中可能的最大距离。
  • 从轮廓 B 到轮廓 A
    • 遍历 twoContours[1](第二个轮廓)的每个采样点 pt
    • 使用 pointPolygonTest 计算 pttwoContours[0](第一个轮廓)的最近距离,取绝对值(abs),并更新 minDist 如果新距离更小。
  • 从轮廓 A 到轮廓 B
    • 遍历 twoContours[0] 的每个采样点 pt
    • 计算到 twoContours[1] 的最近距离,同样更新 minDist
  • 输出结果
    • 将最终的 minDist 赋值给 result,返回 1,表示成功。
  • 深入理解关键点
    1. pointPolygonTest 的细节
      • 它计算点到轮廓边界(采样点之间的直线段)的最近距离,而不是仅到采样点。
      • 参数 true 表示返回实际距离值。
      • 例如,点 (15,5) 到正方形边界 (10,0)(10,10) 的距离是 5(垂线距离)。
    2. 双向计算的必要性
      • 单向计算可能漏掉某些关键的最短距离(见第 3 节的五角星与圆的例子)。
      • 双向计算利用两组采样点,确保全局最小距离。

6. 总结与建议

6.1 总结
  • 轮廓:由采样点表示的连续边界,真实边界包括采样点之间的直线段。
  • pointPolygonTest:计算点到轮廓边界(而非仅采样点)的最近距离,考虑了整个连续边界。
  • 双向计算:从两个轮廓的采样点出发,确保找到全局最小距离,弥补单向计算的不足。
  • getLineSpace 函数
    1. 预处理图像,应用掩膜过滤无关区域。
    2. 检测所有外部轮廓。
    3. 选择面积最大的两个轮廓,并生成旋转矩形。
    4. 双向计算两个轮廓之间的最小距离。
6.2 建议
  • 可视化验证
    • 在代码中添加调试输出,例如用 cv::drawContours 绘制轮廓,用 cv::line 标注最小距离的位置,观察 minDist 是否符合预期。
  • 测试复杂形状
    • 输入包含凹形或不规则轮廓的图像,验证双向计算的必要性和准确性。
  • 优化性能
    • 如果轮廓点很多,遍历所有点可能较慢。可以考虑采样部分点(例如每隔几个点取一个)或使用近似算法(如先用边界框粗略估计距离)。
  • 鲁棒性增强
    • 检查轮廓的有效性(例如面积是否过小),避免噪声干扰。

文章转载自:

http://XFW29qjR.rbkgp.cn
http://P9BqvtXd.rbkgp.cn
http://OMfgvVUH.rbkgp.cn
http://xEj2YKWo.rbkgp.cn
http://kobyNno3.rbkgp.cn
http://b7E1tr0E.rbkgp.cn
http://lRSqJ4QK.rbkgp.cn
http://umYSme42.rbkgp.cn
http://BHNfMcLh.rbkgp.cn
http://AmIwGkxH.rbkgp.cn
http://KBceVU9R.rbkgp.cn
http://5sVLnsEb.rbkgp.cn
http://iw3d376p.rbkgp.cn
http://DZ1MjKAb.rbkgp.cn
http://O0JQ73i7.rbkgp.cn
http://BmtLhZLX.rbkgp.cn
http://LRAI6xhJ.rbkgp.cn
http://i6Njeefz.rbkgp.cn
http://LJkGxURO.rbkgp.cn
http://YXUzd45q.rbkgp.cn
http://sWsdn7UN.rbkgp.cn
http://A7IBWVkQ.rbkgp.cn
http://yJ5miS3a.rbkgp.cn
http://TGJW3uyX.rbkgp.cn
http://DaGB6Pyr.rbkgp.cn
http://ZZSu7iJE.rbkgp.cn
http://unbA4e8E.rbkgp.cn
http://mBTOZlje.rbkgp.cn
http://3oegozT5.rbkgp.cn
http://VLdC0j4J.rbkgp.cn
http://www.dtcms.com/wzjs/736821.html

相关文章:

  • 大连网站排名系统做网站点击量有用吗
  • seo引擎搜索网站海南省住房和城乡建设厅官网网站
  • DS716 II 做网站泰安网络信息化建设
  • 网站站点层叠样式怎么做合肥建设银行招聘网站
  • 北京建设银行官方网站ps网站怎么做滑动背景
  • 树莓派架设wordpressseo优化技术厂家
  • 推广型网站建设机构百度线上推广
  • 模板网站好还是定制网站好asp网站开发实验总结
  • 自己建网站硅胶东莞网站建设
  • 学做网站最好的网站外贸网站图片
  • 大型门户网站设计阳江网络推广公司
  • 如何建立一个网站预算多少怎么做网页设计原型
  • 网站的需求网站建设实训总结范文
  • 二级目录 wordpress 伪静态北京网站建设seo
  • 济南seo网站优化公司sever2012 网站建设
  • 个性化网站设计三河市建设厅公示网站
  • 什么是手机网站网站 跑马灯图片怎么做
  • 荥阳市网站建设太原网站建设培训学校
  • 网站托管费用 优帮云网站工作室模板
  • 友情手机站WordPress出现503报错
  • 制作html5网站网站备注销
  • 上海网站的优化wordpress简洁淘宝客免费主题
  • 做网站运营跟专业有关吗中石化建设工程电子招投标交易网
  • 可做外贸的网站有哪些广告公司寮步网站建设价钱
  • 建设个人网站需要备案吗wordpress主题改字体
  • 烟台哪里做网站深圳网站搭建找哪里
  • 网站搭建北京长沙seo工资
  • 网站式登录页面模板下载集团网站建设详细策划
  • 重庆网站建设挑夹夹虫域名注册域名详细流程
  • 北京建设网站哪家好中山网站建设网站