OpenCV Findcontours( ) 函数原理出自于该论文的算法:Suzuki, S. and Abe, K., TopologicalStructural Analysis of Digitized Binary Images by Border Following.CVGIP 30 1, pp32-46 (1985)
经过证实的资料:
首选:https://zhuanlan.zhihu.com/p/144807771 如果能看懂,就基本理解
看不懂可以再看:https://zhuanlan.zhihu.com/p/107257870
谢谢大牛分享。
下面记录在学习中的坑:
1、注意搜索的时候顺时针、逆时针的地方,否则就会得到不同的结果;
2、实际论文算法是得不到里面例子那个结果的,需要参考首选链接里的这段处理才可以得到相同结果:
后来想了一段时间,这里对像素左边和右边同时为0的情况,应该做特殊处理。因为轮廓是逆时针寻找,那么可以通过寻找的方位判断该赋值NBD还是-NBD,如果是从上往下扫的,则为NBD,如果是从下往上扫描的,则赋值-NBD。(具体实现可以参考代码)
3、关于轮廓的父子关系,也就是论文中的这个表,看当前轮廓类型(在步骤1里确定),然后看之前的轮廓类型来确定,例如,当前轮廓类型为Outer border,最近一次轮廓类型为Outer Border,则当前轮廓为最近一次轮廓的父轮廓,其它类似:
4、判定某个点是是否搜索过从每次轮廓开始搜索时候算,一旦NBD+1了,则重新开始算搜索没搜索过,不是历史上搜索没搜索过;
5、关于类似(i2,j2)<-(i,j)这样的话的意思是说,i2=i,j2= j的意思,直接赋值就可以了,没有特殊的意思;
6、轮廓父子关系确定,轮廓序号确定,然后根据算出来的图,可以得到轮廓情况和轮廓类型,是上面文里没说的,算出这个轮廓序号图之后再怎么操作的问题;
下面补充一下findcontours的用法:
在C++中是这么说的;
findContours( InputOutputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset=Point());
第一个参数image,是输入图像,需要是uint8的图像,但是这个图像要求,非零的都是1,即非零即1,一般是经过处理得到的二值图像;
第二个参数contours,是输出的轮廓,每一个轮廓用std::vector
第三个参数hierarchy,是输出的轮廓关系的存储;
第四个参数mode,定义检测出来的轮廓是什么,对contours和hierarchy都有影响,要根据实际应用选择:
CV_RETR_EXTERNAL:只有最外层轮廓;
CV_RETR_LIST : 检测所有的轮廓,但是轮廓之间都是单独的,没有父子关系;
CV_RETR_CCOMP : 检测所有的轮廓,但所有轮廓只建立两个等级关系;如果超过两个等级关系的,从顶层开始每两层分解成一个轮廓;
CV_RETR_TREE : 检测所有轮廓,所有轮廓按照真实的情况建立等级关系,层数不限;
第五个参数method ,定义输出的轮廓是不是要经过一些处理:
CHAIN_APPROX_NONE :算出来的轮廓不经过处理,算出来是啥就是啥;
CHAIN_APPROX_SIMPLE:压缩轮廓,把横竖撇捺都压缩得只剩下顶点;
CHAIN_APPROX_TC89_L1:用Teh-Chin chain approximation algorithm的一种算法压缩轮廓;
CHAIN_APPROX_TC89_KCOS:用Teh-Chin chain approximation algorithm的另一种算法压缩轮廓;
第六个参数offset:是输出轮廓的偏移量,视情况使用吧;
在python中参数意思是一样的,但是使用方法如下:
contours, hierarchy = cv2.findContours(np.uint8(img),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
参考:
1、OpenCV帮助文档
2、Suzuki, S. and Abe, K., TopologicalStructural Analysis of Digitized Binary Images by Border Following.CVGIP 30 1, pp32-46 (1985)