
程序编码是指经典的改进或骨架算法文章:
T. Y. Zhang和C. Y. Suen,“一种用于稀疏数字图案的快速并行算法”,通讯. ACM,第一卷27号3,第236-239页,1984年.
它的原理也很简单:
我们对二值图像执行骨架提取,即删除不必要的轮廓点,仅保留其骨架点. 假设一个像素点,我们将该点定义为p1,其下一个八邻点p2-> p9如下所示. 该算法考虑p1点邻域的实际情况,以便决定是否删除p1点. 假设我们正在处理一个二进制图像,背景是黑色,值为0opencv图像细化,要精炼的前景对象的像素值为1.

算法描述如下.
首先将源图像复制到目标图像,然后创建一个临时图像,然后执行以下操作:

1. 将目标图像复制到临时图像,然后扫描一次. 对于不为0的点,如果满足以下四个条件,则删除目标图像中的点(即将像素设置为0),其中p2,...,p9是像素的灰度值相应的位置(为1或0).
a. 2
等于或大于2将确保点p1不是端点或孤立点,因为删除端点和孤立点是不合理的,并且小于或等于6可确保点p1是边界点,不是内在的观点. 当它等于0时,不存在等于1的像素,因此p1是一个孤立点. 等于1时,只有1个像素的灰度等于1,因此它是一个端点(注意: 该端点被1个像素包围,并且只能有1个值).

按照
的排列顺序
b. p2-> p9,01个图案的数量为1. 例如opencv图像细化,在下图中,p2p3 => 01,p6p7 => 01,因此该像素的01个图案的数量为2.


01个图案的数量为1的原因是为了确保删除当前像素后的连通性. 例如,在下图中,01个图案的数量大于1. 如果删除了当前点p1,则不能保证连接.

c. P2 * p4 * p6 = 0
d. p4 * p6 * p8 = 0

在第一个子迭代中,无论西北边界点如何,都仅删除东南边界点. 请注意,p4和p6出现两次,也就是说,其中一个为0,则满足c和d.

2. 接下来,将目标图像再次复制到临时图像,然后扫描一次. 如果不为0的点及其八个邻域满足以下4个条件,则删除目标图像中的点(即将像素设置为0)
a. 2
b. p2->在p9的排列顺序中,01个模式的数目(这里假设二元图的非零值为1)是1.
c. p2 * p4 * p8 = 0
d. p2 * p6 * p8 = 0

第二次迭代是相反的. 西北的边界点将被删除. 请注意,p2和p8出现两次,也就是说,如果其中之一为0,则满足c和d.

执行上述两个步骤后,完善算法. 我们可以多次重复上述过程以获得最终的骨架图.
细化算法代码如下:
void gThin::cvThin(cv::Mat& src, cv::Mat& dst, int intera)
{
if(src.type()!=CV_8UC1)
{
printf("只能处理二值或灰度图像\n");
return;
}
//非原地操作时候,copy src到dst
if(dst.data!=src.data)
{
src.copyTo(dst);
}
int i, j, n;
int width, height;
width = src.cols -1;
//之所以减1,是方便处理8邻域,防止越界
height = src.rows -1;
int step = src.step;
int p2,p3,p4,p5,p6,p7,p8,p9;
uchar* img;
bool ifEnd;
int A1;
cv::Mat tmpimg;
//n表示迭代次数
for(n = 0; n<intera; n++)
{
dst.copyTo(tmpimg);
ifEnd = false;
img = tmpimg.data;
for(i = 1; i < height; i++)
{
img += step;
for(j =1; j<width; j++)
{
uchar* p = img + j;
A1 = 0;
if( p[0] > 0)
{
if(p[-step]==0&&p[-step+1]>0) //p2,p3 01模式
{
A1++;
}
if(p[-step+1]==0&&p[1]>0) //p3,p4 01模式
{
A1++;
}
if(p[1]==0&&p[step+1]>0) //p4,p5 01模式
{
A1++;
}
if(p[step+1]==0&&p[step]>0) //p5,p6 01模式
{
A1++;
}
if(p[step]==0&&p[step-1]>0) //p6,p7 01模式
{
A1++;
}
if(p[step-1]==0&&p[-1]>0) //p7,p8 01模式
{
A1++;
}
if(p[-1]==0&&p[-step-1]>0) //p8,p9 01模式
{
A1++;
}
if(p[-step-1]==0&&p[-step]>0) //p9,p2 01模式
{
A1++;
}
p2 = p[-step]>0?1:0;
p3 = p[-step+1]>0?1:0;
p4 = p[1]>0?1:0;
p5 = p[step+1]>0?1:0;
p6 = p[step]>0?1:0;
p7 = p[step-1]>0?1:0;
p8 = p[-1]>0?1:0;
p9 = p[-step-1]>0?1:0;
if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7 && A1==1)
{
if((p2==0||p4==0||p6==0)&&(p4==0||p6==0||p8==0)) //p2*p4*p6=0 && p4*p6*p8==0
{
dst.at<uchar>(i,j) = 0; //满足删除条件,设置当前像素为0
ifEnd = true;
}
}
}
}
}
dst.copyTo(tmpimg);
img = tmpimg.data;
for(i = 1; i < height; i++)
{
img += step;
for(j =1; j<width; j++)
{
A1 = 0;
uchar* p = img + j;
if( p[0] > 0)
{
if(p[-step]==0&&p[-step+1]>0) //p2,p3 01模式
{
A1++;
}
if(p[-step+1]==0&&p[1]>0) //p3,p4 01模式
{
A1++;
}
if(p[1]==0&&p[step+1]>0) //p4,p5 01模式
{
A1++;
}
if(p[step+1]==0&&p[step]>0) //p5,p6 01模式
{
A1++;
}
if(p[step]==0&&p[step-1]>0) //p6,p7 01模式
{
A1++;
}
if(p[step-1]==0&&p[-1]>0) //p7,p8 01模式
{
A1++;
}
if(p[-1]==0&&p[-step-1]>0) //p8,p9 01模式
{
A1++;
}
if(p[-step-1]==0&&p[-step]>0) //p9,p2 01模式
{
A1++;
}
p2 = p[-step]>0?1:0;
p3 = p[-step+1]>0?1:0;
p4 = p[1]>0?1:0;
p5 = p[step+1]>0?1:0;
p6 = p[step]>0?1:0;
p7 = p[step-1]>0?1:0;
p8 = p[-1]>0?1:0;
p9 = p[-step-1]>0?1:0;
if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7 && A1==1)
{
if((p2==0||p4==0||p8==0)&&(p2==0||p6==0||p8==0)) //p2*p4*p8=0 && p2*p6*p8==0
{
dst.at<uchar>(i,j) = 0; //满足删除条件,设置当前像素为0
ifEnd = true;
}
}
}
}
}
//如果两个子迭代已经没有可以细化的像素了,则退出迭代
if(!ifEnd) break;
}
}
以下是经过三次细化的结果. 可以看出,H在垂直方向上变短,这是不完美的.

下面我们对两个汉字进行5次迭代优化,结果如下:


程序代码: Engineering FirstOpenCV11
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-289104-1.html
#吴亦凡1106生日快乐##吴亦凡原来你还在这里##吴亦凡夏有乔木##吴亦凡##吴亦凡赴约演爵迹##挑战者吴亦凡##吴亦凡银尘#新歌去不了现场