源码链接:calligraphy.cpp
一、实验要求
附件是书法毛笔字,请将附件图片中“年少有为”四个字进行笔画细化。
二、实验内容
首先观察图片,是只将黑色的毛笔字部分进行细化,所以需要先把印章这类的区域去除。先通过将图片转到hsv颜色空间,然后使用hsv阈值进行黑色像素的提取,输出成二值化图。
这里通过cvcolor函数中的COLOR_BGR2HSV参数将其转换到hsv空间,然后定义二值化的区间为h:(0,180)、s:(0,255)、v:(0,50),即为黑色部分。见下表:
H表示色调(度数表示0-180),S表示饱和度(取值0-255),V表示亮度(取值0-255)。
所以将不在黑色区间的像素都置为0。通过inrange函数进行区域二值化,即得到生成的纯毛笔字二值化图:
得到二值化图后,就可以用其进行细化了。原理是利用8邻接去除有厚度点。
对于二值图来说,我们可以看成由0,1组成的图像(也可以理解为矩阵)。在一副图中我们要去除多余的边界点保留连接点,端点,孤立点这些重要的图像节点。算法的整体思想就是用9个格子表
示这些重要点,并去掉不必要的点。
具体算法步骤如下:
对于以下九宫格
扫描图像,遇到为1的点时用上述模板,把为1的点作为P1(P1为前景点)如果同时满足以下4个条件,则另P1=0 (即删除P1点)。
- 2≤B(P1)≤ 6
- A (P1) = 1
- P2∗P4∗P6 = 0
- P4∗P6∗P8 = 0
A(P1)是以P2,P3.....P9为序时,这些点从0−>1变化的次数。
B(P1)是P2,P3.....P9,非零(即1)的个数。
被判定为删除的点暂不删除,但要加以记录。等所有边界点都被判断完后,再一起将所有标记了的点删除,接下来进入第二阶段的删除步骤。
1、条件1为控制在端点和边界点之间。刚好端点时B(P1)=2,边界点最大B (P1)=8。
所以当B (P1)∈[2, 6]时不是关键点,可以考虑进一步条件用以删除。
2、当A (P1)>1时很有可能就是连接点,所以一定要保证A (P1)=1。如下面这个就是A ( P 1 ) > 1就是连接点。
然后,按照如下条件进行第二阶段的删除,条件为
- 2≤B(P1)≤6
- A (P1)=1
- P2∗P4∗P6=0
- P2∗P4∗P8=0
同第一步一样,判定要删除的点只是加以记录而暂不删除,等待最后同时删除。对一副图像反复执行第一步与第二步的算法步骤,知道都没有可删除的点为止。
第二阶段与第一阶段不同的就在最后一个条件,因为第一阶段只是移去东南的边界点,而不考虑西北的边界点,注意p4,p6出现了2次,就是说它们有一个为0,则c,d就满足。(第一阶段P4, P6出现了两次所以东南方向的点更有可能被删除、第二次时P2, P8出现了两次所以西北方向的点更有可能被删除)。
最终结果:
原图:
二值化图:
最终骨架:
感觉效果不咋好。
三、实验收获
1、实验遇到的问题及难点
这次实验难点集中在细化的方法选择上。上网查了一下很多用了对原图像腐蚀然后保存腐蚀后的结果的方法,但是这次实验用的这个方法是很多论文里提到的,就想着试试,结果效果也不算很好,但也没时间再研究了……以后有机会再看看。
2、实验总结
这次通过opencv再次学习了几个知识点,比如图像颜色划分、图像细化的处理算法等等,收获很大。