棋盘边界是一个黑色的正方形,为了定位这个正方形,我们先查找出图片中的所有轮廓。
查找轮廓
List<MatOfPoint> contourList = new ArrayList<>();
Imgproc.findContours(src, contourList, hierarchy, mode, method);
参数列表:
- src:源Mat,推荐使用二值化后的Mat
- contourList:检测到的轮廓列表,每个轮廓用MatOfPoint类表示
-
hiararchy:我们检测轮廓的时候,有时候轮廓会有嵌套关系,这时候我们称外面的轮廓为parent,内部的轮廓为child。此时轮廓之间就有了一定的关系,我们称之为层次结构。
hierarchy.png
比如0、1、2为外轮廓,他们处于相同层级,2a、3、3a、4、5为2的内部轮廓,其中2a为2的第一个内部轮廓,称为first_child。我们就可以用相同层级、外轮廓、子轮廓、父轮廓、第一个子轮廓来描述这些关系。
我们用一个长度为4的数组来存储这些关系[Next, Previous, First_Child, Parent],即hiararchy。前两个代表相同层级的上一个和下一个轮廓的编号,第三个代表第一个子轮廓的编号,第四个代表父轮廓编号,没有的话就是-1。
- mode:轮廓的检索模式,有四个值
- RETR_LIST:检索所有轮廓,但不创建任何父子关系,因此hiararchy数组后两项永远是-1。
- RETR_EXTERNAL:只检索外轮廓。hiararchy数组后两项也永远是-1。
-
RETR_CCOMP:检索所有轮廓,并将他们排列为2级层次结构。即对象的外部轮廓被放在层级1中,内部轮廓被放在层级2中。如果对象的内部还有对象,则内部对象的外轮廓重新被放在层级1中,内轮廓放层级2。如下图,红色数字代表轮廓编号,绿色数字代表层级:
ccomp_hierarchy.png
9个轮廓对应的hiararchy:
[ 3, -1, 1, -1],//轮廓0
[ 2, -1, -1, 0],//轮廓1
[-1, 1, -1, 0],//轮廓2
[ 5, 0, 4, -1],//轮廓3
[-1, -1, -1, 3],//轮廓4
[ 7, 3, 6, -1],//轮廓5
[-1, -1, -1, 5],//轮廓6
[ 8, 5, -1, -1],//轮廓7
[-1, 7, -1, -1]//轮廓8
这里简单解释一下轮廓2:父轮廓为0,0下的同一层次中没有下一个轮廓,所以第一项是-1,而不是4,因为4位于轮廓3下面。轮廓4和6同理。
-
RETR_TREE:检索所有轮廓,并排列成一个完美的层级结构,包括爷爷、父亲、自己、儿子、孙子等等。依旧看图理解:红色数字代表轮廓编号,绿色数字代表层级:
tree_hierarchy.png
9个轮廓对应的hiararchy:
[ 7, -1, 1, -1],//轮廓0
[-1, -1, 2, 0],//轮廓1
[-1, -1, 3, 1],//轮廓2
[-1, -1, 4, 2],//轮廓3
[-1, -1, 5, 3],//轮廓4
[ 6, -1, -1, 4],//轮廓5
[-1, 5, -1, 4],//轮廓6
[ 8, 0, -1, -1],//轮廓7
[-1, 7, -1, -1]//轮廓8
- method:轮廓是具有相同色值强度的边界,它存储这边界坐标,method代表了存储的方式。比如CHAIN_APPROX_NONE代表存储所有边界点坐标,CHAIN_APPROX_SIMPLE只存储关键坐标,比如说存储一条直线只需要两个端点,存储一个矩形只需要四个端点。
更多关于轮廓的知识请参考https://docs.opencv.org/master/d3/d05/tutorial_py_table_of_contents_contours.html
获取轮廓的外包矩形
Rect rect = Imgproc.boundingRect(mp);//mp为一个轮廓MatOfPoint
到此基本就可以定位出我需要的棋盘区域了。
网友评论