如何判断点在轮廓内?【OpenCV】【计算机视觉】

  1. 本人对计算机视觉感兴趣,正在阅读《OpenCV计算机视觉编程攻略(第3版)》一书,非专业,纯属业余爱好。本文是为了记录学习过程中所思所想。
  2. 如有错误,请多指教。
  3. 本文基于OpenCV。

学到了第7.5节 提取连续区域。本节用到了 cv::findContours 函数来查找二值图像(非边缘图)中的连续区域。

std::vector<cv::Vec4i> hierarchy;
cv::findContours(	image, 
					contours, // 存放轮廓的向量
					hierarchy, // 层次结构
					cv::RETR_TREE, // 树状结构的轮廓
					cv::CHAIN_APPROX_NONE); // 每个轮廓的全部像素

该函数不仅能找到连续区域,也能识别出轮廓间的父子关系。

如何判断点在轮廓内?【OpenCV】【计算机视觉】_第1张图片
识别出连续区域。图像上半部分大轮廓为父轮廓,内部小轮廓为子轮廓。父子关系存放于对象hierarchy中。详见Opencv官方文档或书籍P161。

那么怎么能判断一个区域在另一个区域内呢?根据连续区域的定义,只需要判断小区域上某个点在大区域内即可。所以问题变成了怎么判断点在一个区域内。 通过google得到Opencv有pointPolygonTest函数可实现此功能。但是没有查到该函数的原理,本人水平有限,还不能顺利读通源码。所以自己思考了一下如何实现这个功能。请注意,下文并不是Opencv内pointPolygonTest的原理。

如何判断点在轮廓内?【OpenCV】【计算机视觉】_第2张图片
随手画个示意图。对一个点P(x, y),依x轴、y轴方向分别一条线Lx、Ly,以向右为正。Lx和轮廓的交点是A1、A2、…、A2n。Ly和轮廓的交点是B1、B2、…、B2m。轮廓是有限封闭区域,所以直线与其交点必为偶数个(切点的情况,请移至 “ 如何处理切点 ” 处)。如果P点实际位置与其中任意点重合,那么P点在轮廓上。一下讨论不重合的情况。

如果P点在轮廓内,Lx、Ly与轮廓都必有交点;反之,都没有交点。需考察一条直线即可。

以x轴方向Lx为说明

若P点从负向无穷远处沿Lx向正向移动。那么P点依次经过A1、A2、…、A2n。经过点,也可以理解为穿过边缘。P点经过第一个点时,有外部穿过边缘,P点进入轮廓内。第二次经过点时,有内部穿过边缘,P点进入外部。以此类推。

可见,只需要对A1、A2、…、A2n各点的横坐标进行排序,与P点实际横坐标进行比较,即可知P点是否在轮廓内。

如何处理切点?

  1. 当某个点是切点时,穿过切点并不会使P点与轮廓的关系发生变化,所以要把切点去除掉。如何去除切点呢?——利用点的梯度方向。
  2. 实现时,可使用drawcontours函数,在空白图像上绘制轮廓图(绘制findContours函数的结果)。在轮廓图上计算每个交点的梯度,如果交点梯度方向与直线垂直,则可判断该点就是切点。
  3. 同理。如果Lx恰好与轮廓的一边重合,会出现很多个点。这些点都可视为切点,与上述处理过程相同。即在对交点进行预处理时,不需要考虑交点的性质、点是否连接等,只需要计算梯度决定是否去除即可。

思考

如果是其他方法得到的边缘图,可能存在边缘厚度大于1的情况。那么在同一处,边缘与直线的相交处可能不是一个点,而是一条线段。这对于判定、求梯度都会带来麻烦。这篇论文[1]第4.8节中关于“广义霍夫变换误差”的处理方法可能会起到作用,继续思考…

如果看官有想法欢迎评论交流。

思考果然使我快乐~~~<( ̄︶ ̄)>

  • 关于梯度,推荐博主马同学的文章,我看完之后学到了很多:如何直观形象的理解方向导数与梯度以及它们之间的关系?
  • 本人在网上搜集了部分计算机视觉相关书籍。如有兴趣,可下方留言。我为人人,人人为我。

[1]Ballard D H . Generalizing the Hough transform to detect arbitrary shapes[J]. Pattern Recognition, 1981, 13(2):111-122.

你可能感兴趣的:(计算机视觉)