logo资料库

opencv 骨架提取算法 (查表索引法).doc

第1页 / 共14页
第2页 / 共14页
第3页 / 共14页
第4页 / 共14页
第5页 / 共14页
第6页 / 共14页
第7页 / 共14页
第8页 / 共14页
资料共14页,剩余部分请下载后查看
//Mat 类型 骨架算法 查索引表法
原理
//Mat 类型 骨架算法 查索引表法 //20141009 //opencv 2.4.9 vs2012 Mat 类型图像 原图 细化结果 示例代码: 原理及 iplimage 类型实现详见后文 //xx.h using namespace std; using namespace cv; //std::string Mat VThin( Mat &tmp, int array[256] ); Mat HThin( Mat &XihuaTmp, int array[256] ); //XX.cpp int array[256] = {0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1, 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1, 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1, 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1, 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1, 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1, 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, 1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0, 1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0}; ********************** //细化 Mat iXihua(gray_img.size(),CV_8UC1); Mat XihuaTmp(gray_img.size(),CV_8UC1); //20141009 索引表法 //取反 for(int h=0;h(h,w)==0) Close_morphologyEx_img.at(h,w)=255; else Close_morphologyEx_img.at(h,w)=0; { } } //注意这里取反为什么不是 0-1,而是 0<—>255 呢?因为 opencv 里面的图像深度是 8 位的,并不仅仅是//0,1 两位 // for (int i = 0;i<20;i++) //阈值 20 是可变的,根据每个区域的大小改变,若最大区域 较大,则将阈值增大,反之变小,可通过测试看出效果 { } XihuaTmp = VThin(Close_morphologyEx_img,array); iXihua = HThin(XihuaTmp,array); //水平细化 //垂直细化 imwrite("音孔检测\\08-1 音孔_dTF1_xihua1.bmp",iXihua); ************************* Mat Cglass_locateDlg::VThin( Mat &tmp, int array[256] ) //细化主程序调用垂直细化 { int NEXT = 1; int M =0; int a[9]; int sum; int width = tmp.size().width;//int width = Close_morphologyEx_img.cols int height = tmp.size().height;////int width = Close_morphologyEx_img.rows
for (int h = 0;h0 &&wimageData + tmp->widthStep*(h)))[w-1]+((uchar*)(tmp->imageData + tmp->widthStep*(h)))[w]+((uchar*)(tmp->imageData + tmp->widthStep*(h)))[w+1]; M=tmp.at(h,w-1)+tmp.at(h,w)+tmp.at(h,w+1); } else { M = 1; } if((tmp.at(h,w)) == 0 && M!=0) { a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 0; for(int i = 0;i<3;i++) { for(int j = 0;j<3;j++) { if((h-1+i) > -1 &&(h-1+i) -1&&(w-1+j)(h-1+i,w-1+j))==255) { a[i*3+j] = 1; } } } } } sum = a[0]*1+a[1]*2+a[2]*4+a[3]*8+a[5]*16+a[6]*32+a[7]*64+a[8]*128; //(uchar*)(tmp->imageData + tmp->widthStep*h))[w] = array[sum]*255; tmp.at(h,w)=array[sum]*255;
if(array[sum]==1) { NEXT = 0; } } } } } return tmp; } Mat Cglass_locateDlg::HThin( Mat &XihuaTmp, int array[256] ) //细化主程序调用水平细化 { int NEXT = 1; int M =0; int A[9]; int sum; int width = XihuaTmp.size().width;//int width = Close_morphologyEx_img.cols int height = XihuaTmp.size().height;////int width = Close_morphologyEx_img.rows for (int w = 0;w0 &&himageData + XihuaTmp->widthStep*(h-1)))[w]+((uchar*)(XihuaTmp->imageData + XihuaTmp->widthStep*(h)))[w]+((uchar*)(XihuaTmp->imageData + XihuaTmp->widthStep*(h+1)))[w]; M=XihuaTmp.at(h-1,w)+XihuaTmp.at(h,w)+XihuaTmp.at(h+1,w); } else { M = 1;
} //if(((uchar*)(XihuaTmp->imageData + XihuaTmp->widthStep*(h)))[w] == 0 && M!=0) if(XihuaTmp.at(h,w)==0 && M!=0) { A[0] = A[1] = A[2] = A[3] = A[4] = A[5] = A[6] = A[7] = A[8] = 0; for(int i = 0;i<3;i++) { for(int j = 0;j<3;j++) { if((h-1+i) > -1 &&(h-1+i) -1&&(w-1+j)imageData + XihuaTmp->widthStep*(h-1+i)))[w-1+j] == 255) if(XihuaTmp.at(h-1+i,w-1+j)==255) { } A[i*3+j] = 1; } } } } sum = A[0]*1+A[1]*2+A[2]*4+A[3]*8+A[5]*16+A[6]*32+A[7]*64+A[8]*128; //((uchar*)(XihuaTmp->imageData + XihuaTmp->widthStep*h))[w] = array[sum]*255; XihuaTmp.at(h,w)=array[sum]*255; if(array[sum]==1) { NEXT = 0; } } } } } return XihuaTmp; }
原理 像的细化主要是针对二值图而言 所谓骨架,可以理解为图像的中轴,,一个长方形的骨架,是它的长方向上的中轴线, 圆的骨架是它的圆心,直线的骨架是它自身,孤立点的骨架也是自身。 骨架的获取主要有两种方法: (1)基于烈火模拟 设想在同一时刻,将目标的边缘线都点燃,火的前沿以匀速向内部蔓延,当前沿相交时火焰熄灭, 火焰熄灭点的结合就是骨架。 (2)基于最大圆盘 目标的骨架是由目标内所有内切圆盘的圆心组成 我们来看看典型的图形的骨架(用粗线表示) 细化的算法有很多种,但比较常用的算法是查表法 细化是从原来的图中去掉一些点,但仍要保持原来的形状。 实际上是保持原图的骨架。 判断一个点是否能去掉是以 8 个相邻点(八连通)的情况来作为判据的,具体判据为: 1,内部点不能删除 2,鼓励点不能删除 3,直线端点不能删除 4,如果 P 是边界点,去掉 P 后,如果连通分量不增加,则 P 可删除
看看上面那些点(中心点,八领域)。 第一幅图中心点不能去除,因为它是内部点 第二个点不能去除,它也是内部点 第三个点不能去除,删除后会使原来相连的部分断开 第四个点可以去除,这个点不是骨架 第五个点不可以去除,它是直线的端点 第六个点不可以去除,它是直线的端点 对于所有的这样的点,我们可以做出一张表,来判断这样的点能不能删除 我们对于黑色的像素点,对于它周围的 8 个点,我们赋予不同的价值, 若周围某黑色,我们认为其价值为 0,为白色则取九宫格中对应的价值
对于前面那幅图中第一个点,也就是内部点,它周围的点都是黑色,所以他的总价值是 0,对应 于索引表的第一项 前面那幅图中第二点,它周围有三个白色点,它的总价值为 1+4+32=37,对应于索引表中第 三十八项 我们用这种方法,把所有点的情况映射到 0~255 的索引表中 我们扫描原图,对于黑色的像素点,根据周围八点的情况计算它的价值,然后查看索引表中对应 项来决定是否要保留这一点 我们很容易写出程序 import cv def Thin(image,array): h = image.height w = image.width iThin = cv.CreateImage(cv.GetSize(image),8,1) cv.Copy(image,iThin) for i in range(h): for j in range(w): if image[i,j] == 0: a = [1]*9 for k in range(3): for l in range(3): if -1<(i-1+k)
分享到:
收藏