基于索引表的图像细化程序有详细注解

时间:2019-02-20 10:17:11
【文件属性】:

文件名称:基于索引表的图像细化程序有详细注解

文件大小:13KB

文件格式:CPP

更新时间:2019-02-20 10:17:11

opencv 索引表 细化

// XiHua.cpp : 定义控制台应用程序的入口点。 // //基于索引表的图像细化算法 //#include "stdafx.h" #include "highgui.h" #include "cv.h"//包含cvCreateStructuringElementEx();颜色空间转换函数cvCvtColor()需要 //#include "cxcore.h" //#pragma comment(lib, "opencv_core249.lib")//opencv_core249.lib取代cv.lib等---(不懂以后再一一对应) //#pragma comment(lib,"opencv_highgui249.lib") //#pragma comment(lib,"opencv_imgproc249.lib") #include #include //基于索引表的细化细化算法 //功能:对图象进行细化 //参数:lpDIBBits:代表图象的一维数组 // lWidth:图象高度 // lHeight:图象宽度 // 代表图象的一维数组 图象宽度 图象高度 bool ThiningDIBSkeleton(unsigned char* imagedata, int lWidth, int lHeight) { /* unsigned char* imagedata; imagedata = new uchar[sizeof(char) * src->width * src->height](); */ /* deletemark[256]为前人据8领域总结的是否可以被删除的256种情况 不可以删除用0来表示,能被删除的用1来表示 */ unsigned char deletemark[256] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 };//索引表 //循环变量 //long i; //long j; unsigned char p0, p1, p2, p3, p4, p5, p6, p7; unsigned char *pmid, *vergeMark; // pmid 用来指向二值图像 vergeMark用来指向存放是否为边缘 unsigned char sum; bool bStart = true; //动态创建一个长度为sizeof(char) * src->width * src->height的数组 //并且初始化把数组元素都设置为0 //长度与imagedata长度一样 long lLength; lLength = lWidth * lHeight; //数组长度 unsigned char *pTemp = new uchar[sizeof(unsigned char) * lLength](); // P0 P1 P2 // P7 P3 // P6 P5 P4 while (bStart) { bStart = false; //每次循环pTemp所有元素都置0 memset(pTemp, 0, lLength);//初始化pTemp指向的lLength空间全部初始化为0 /*---------------首先求边缘点----------------*/ pmid = (unsigned char *)imagedata + lWidth + 1; // pmid 用来指向二值图像矩阵的第二行 +1 表示不考虑图像第一行 vergeMark = (unsigned char *)pTemp + lWidth + 1; //pmidtemp用来指向存放是否为边缘 如果是边缘点 则将其设为1 for (int i = 1; i < lHeight - 1; i++) //lHeight -1表示不考虑图像最后一行 第一列 { for (int j = 1; j < lWidth - 1; j++) //lWidth - 1表示不考虑图像最后一列 { //图像已经是01化,如果是0我们不考虑 if (*pmid == 0) { pmid++; vergeMark++; continue; } //如果是1,是我们考虑的点 我们需要对周围8个进行判断是否边缘 p0 = *(pmid - lWidth - 1); p1 = *(pmid - lWidth); // P0 P1 P2 p2 = *(pmid + 1 - lWidth); // P7 P3 p3 = *(pmid + 1); // P6 P5 P4 p4 = *(pmid + lWidth + 1); p5 = *(pmid + lWidth); p6 = *(pmid + lWidth - 1); p7 = *(pmid - 1); //p0--到---p7的值不是0就是1 sum = p0 & p1 & p2 & p3 & p4 & p5 & p6 & p7;//如果是边缘,肯定周围的P0P1P2P3P4P5P6P7 中一定至少有一个为0 if (sum == 0) { *vergeMark = 1;// 表记边缘 } pmid++; vergeMark++; } pmid++;//跳过图像最后一列,不考虑 vergeMark++; pmid++;//跳过图像第一列,不考虑 vergeMark++; } /*---------------沿着边缘现在开始删除----------------*/ pmid = (unsigned char *)imagedata + lWidth + 1; vergeMark = (unsigned char *)pTemp + lWidth + 1; for (long i = 1; i < lHeight - 1; i++) // 不考虑图像第一行 第一列 最后一行 最后一列 { for (long j = 1; j < lWidth - 1; j++) { //*vergeMark=0表示这个点不是边缘,即不进行删除 if (*vergeMark == 0) { pmid++; vergeMark++; continue; } //如果是1,是我们考虑的点 我们需要对周围8个进行判断 //判断一个点是否能去掉, 要根据它的八个相邻点的情况来判断 p0 = *(pmid - lWidth - 1); p1 = *(pmid - lWidth); // P0 P1 P2 p2 = *(pmid - lWidth + 1 ); // P7 P3 p3 = *(pmid + 1); // P6 P5 P4 p4 = *(pmid + lWidth + 1); p5 = *(pmid + lWidth); p6 = *(pmid + lWidth - 1); p7 = *(pmid - 1); /*根据它的八个相邻点的情况形成的索引表进行删除操作 * * 经过预处理后得到待细化的图像是0、1二值图像。 * 像素值为1的是需要细化的部分,像素值为0的是背景区域。 * * 基于索引表的算法就是"依据一定的判断依据",所做出的一张表, * 因为一个像素的8个邻域,我们可以用8位二进制表示,共有256中可能情况, * 因此,索引表的大小一般为256。 * 根据索引值对应表中的位置存0或1, * 当前像素不能删除存为0, * 可以删除存为1。 * * 然后根据要细化的点的八个邻域的在索引表中情况查询, * 若表中元素是1,则删除该点(改为背景) * 若是0则保留。 * * * ---------------------------------------- * |p7 | p6 | p5 | p4 | p3 | p2 | p1 | p0 |---索引值对应表中的位置-----》共有256中可能情况 * ---------------------------------------- (位置1)0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0(位置256) */ //此时p0--到---p7的值不是0就是1 p1 *= 2; p2 *= 4; p3 *= 8; p4 *= 16; p5 *= 32; p6 *= 64; p7 *= 128; sum = p0 | p1 | p2 | p3 | p4 | p5 | p6 | p7; // sum = p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7; if (deletemark[sum] == 1)//可以删除 { *pmid = 0; bStart = true; // 表明本次扫描进行了细化 } pmid++; vergeMark++; } pmid++;//跳过图像最后一列,不考虑 vergeMark++; pmid++;//跳过图像第一列,不考虑 vergeMark++; } } //循环结束说明没有可以继续细化的点了,则为细化结束 delete[]pTemp; return true; } int main(int argc, char* argv[]) { //加载原图像 IplImage* src = cvLoadImage("F:\\zhengning\\QtOpencv\\Images\\xihua.PNG", 0); //---------------------------预处理二值化------------------------------------ //对原图像进行二值化 阈值 cvThreshold(src, src, 100, 255, CV_THRESH_BINARY); /* 图像二值化就是将图像上的像素点的灰度值设置为0或255, 也就是将整个图像呈现出明显的黑白效果 CV_THRESH_BINARY 意思为: if src(x,y) > 100 src(x,y)=255 else src(x,y)=-0 原图像由0到255---->0或255 */ cvNamedWindow("s", 0); cvShowImage("s", src); //-----------------------------预处理0/1化------------------------------------- /* 将imagedata指向的与原图像大小一下的数组空间进行0或1赋值 二值图有原来的0或255----->------0或1 */ //动态创建一个长度为sizeof(char) * src->width * src->height的字符数组 //并且初始化把数组元素都设置为0 unsigned char* imagedata; imagedata = new uchar[sizeof(char) * src->width * src->height](); int x, y; for (y = 0; yheight; y++) { /* widthStep表示存储一行像素需要的字节数 偏移到第y行 */ unsigned char* ptr = (unsigned char*)(src->imageData + y*src->widthStep); for (x = 0; xwidth; x++) { /* 判断第y行第x列的元素值是否大于0 大于0时将数组对应的位置元素设置为1 不大于0则设置为0 imagedata数组里面不是0就时1 */ imagedata[y*src->width + x] = ptr[x] > 0 ? 1 : 0; //经过预处理后得到待细化的图像是0、1二值图像。 } } //----------------------------细化----------------------------------------- //经过预处理后得到待细化的图像是0、1二值图像。 //细化一次,和细化多次,由于索引表不变,每次细化效果都一样,想采用多次细化无法消除毛刺 ThiningDIBSkeleton(imagedata, src->width, src->height); //--------------------对细化后的0/1图二值化(0/255)----------------------------- /* 将ptr指向的与原图像大小一下的数组空间进行0或255赋值 */ for (y = 0; yheight; y++) { /* widthStep表示存储一行像素需要的字节数 偏移到第y行 */ unsigned char* ptr = (unsigned char*)(src->imageData + y*src->widthStep); for (x = 0; xwidth; x++) { /* 判断第y行第x列的元素值是否大于0 大于0时将数组对应的位置元素设置为1 不大于0则设置为0 ptr指向的空间的值不是0就是255 也就是细化之后再次变为二值图 */ ptr[x] = imagedata[y*src->width + x]>0 ? 255 : 0; } } //------------------------------------------------------------------------- cvNamedWindow("src", 0); cvShowImage("src", src); cvWaitKey(0); delete[]imagedata; return 0; }


网友评论