当前位置: 首页 > news >正文

网站 建设理由免费的推广引流软件下载

网站 建设理由,免费的推广引流软件下载,网站建设增值税税率是多少,一个刚有官网的公司怎么做网站运营二值图像骨架线提取HilditchThin算法Rosenfeld算法OpenCV_Contrib中的算法示例其他细化算法查表法HilditchThin的另一种算法参考二值图像骨架线提取算法:HilditchThin算法、Rosenfeld算法、OpenCV_Contrib中的算法 HilditchThin算法 1、使用的8邻域标记为&#xff…

二值图像骨架线提取

  • HilditchThin算法
  • Rosenfeld算法
  • OpenCV_Contrib中的算法
  • 示例
  • 其他细化算法
    • 查表法
    • HilditchThin的另一种算法
  • 参考

二值图像骨架线提取算法:HilditchThin算法、Rosenfeld算法、OpenCV_Contrib中的算法

HilditchThin算法

1、使用的8邻域标记为:
在这里插入图片描述2、下面看下它的算法描述:
复制目地图像到临时图像,对临时图像进行一次扫描,对于不为0的点,如果满足以下四个条件,则在目地图像中删除该点(就是设置该像素为0)

条件一:2<=p2+p3+p4+p5+p6+p7+p8+p9<=6
大于等于2会保证p1点不是端点或孤立点,因为删除端点和孤立点是不合理的,小于等于6保证p1点是一个边界点,而不是一个内部点。等于0时候,周围没有等于1的像素,所以p1为孤立点,等于1的时候,周围只有1个灰度等于1的像素,所以是端点(注:端点是周围有且只能有1个值为1的像素)。
在这里插入图片描述
条件二:p2->p9的排列顺序中,01模式的数量为1
比如下面的图中,有p2p3 => 01, p6p7=>01,所以该像素01模式的数量为2。
在这里插入图片描述
之所以要01模式数量为1,是要保证删除当前像素点后的连通性。比如下面的图中,01模式数量大于1,如果删除当前点p1,则连通性不能保证。
在这里插入图片描述
条件三:p2.p4.p8 = 0 or A(p2)!=1
A(p2)表示p2周围8邻域的01模式和。这个条件保证2个像素宽的垂直条不完全被腐蚀掉。
在这里插入图片描述
条件四:p2.p4.p6 = 0 or A(p4)!=1
A(p4)表示p4周围8邻域的01模式和。这个条件保证2个像素宽的水平条不完全被腐蚀掉。
在这里插入图片描述
如果图像中没有可以删除的点时,结束循环。
算法代码如下(输入归一化二值图像):

void HilditchThin(cv::Mat& src, cv::Mat& dst) //传入归一化图像src
{if(src.type()!=CV_8UC1){printf("只能处理二值或灰度图像\n");return;}//非原地操作时候,copy src到dstif(dst.data!=src.data)src.copyTo(dst);int i, j;int width, height;//之所以减2,是方便处理8邻域,防止越界width = src.cols -2;height = src.rows -2;int step = src.step;int  p2,p3,p4,p5,p6,p7,p8,p9;uchar* img;bool ifEnd;int A1;cv::Mat tmpimg;while(1){dst.copyTo(tmpimg);ifEnd = false;img = tmpimg.data+step;for(i = 2; i < height; i++){img += step;for(j =2; 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;//计算AP2,AP4int A2, A4;A2 = 0;//if(p[-step]>0){if(p[-2*step]==0&&p[-2*step+1]>0) A2++;if(p[-2*step+1]==0&&p[-step+1]>0) A2++;if(p[-step+1]==0&&p[1]>0) A2++;if(p[1]==0&&p[0]>0) A2++;if(p[0]==0&&p[-1]>0) A2++;if(p[-1]==0&&p[-step-1]>0) A2++;if(p[-step-1]==0&&p[-2*step-1]>0) A2++;if(p[-2*step-1]==0&&p[-2*step]>0) A2++;}A4 = 0;//if(p[1]>0){if(p[-step+1]==0&&p[-step+2]>0) A4++;if(p[-step+2]==0&&p[2]>0) A4++;if(p[2]==0&&p[step+2]>0) A4++;if(p[step+2]==0&&p[step+1]>0) A4++;if(p[step+1]==0&&p[step]>0) A4++;if(p[step]==0&&p[0]>0) A4++;if(p[0]==0&&p[-step]>0) A4++;if(p[-step]==0&&p[-step+1]>0) A4++;}//printf("p2=%d p3=%d p4=%d p5=%d p6=%d p7=%d p8=%d p9=%d\n", p2, p3, p4, p5, p6,p7, p8, p9);//printf("A1=%d A2=%d A4=%d\n", A1, A2, A4);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)||A2!=1)&&((p2==0||p4==0||p6==0)||A4!=1)) {dst.at<uchar>(i,j) = 0; //满足删除条件,设置当前像素为0ifEnd = true;//printf("\n");//PrintMat(dst);}}}}}//printf("\n");//PrintMat(dst);//PrintMat(dst);//已经没有可以细化的像素了,则退出迭代if(!ifEnd) break;}
}

Rosenfeld算法

1、使用下面的八邻域表示法:
在这里插入图片描述
2、对于前景点像素p1, 如果p2=0,则p1 称作北部边界点。如果p6=0,p1称作南部边界点,p4=0,p1称作东部边界点,p8=0,p1称作西部边界点。
在这里插入图片描述
p1周围8个像素的值都为0,则p1为孤立点,如果周围8个像素有且只有1个像素值为1,则此时p1称作端点。
3、另外还要了解的一个概念就是8 simple。就是我们把p1的值设置为0后,不会改变周围8个像素的8连通性。下面的三个图中,如果p1=0后,则会改变8连通性。
在这里插入图片描述
而下面的则不会改边8连通性,此时可以称像素p1是8 simple
4、Rosenfeld细化算法描述如下:

  • 扫描所有像素,如果像素是北部边界点,且是8simple,但不是孤立点和端点,删除该像素。
  • 扫描所有像素,如果像素是南部边界点,且是8simple,但不是孤立点和端点,删除该像素。
  • 扫描所有像素,如果像素是东部边界点,且是8simple,但不是孤立点和端点,删除该像素。
  • 扫描所有像素,如果像素是西部边界点,且是8simple,但不是孤立点和端点,删除该像素。
  • 执行完上面4个步骤后,就完成了一次迭代,我们重复执行上面的迭代过程,直到图像中再也没有可以删除的点后,退出迭代循环。

5、算法代码如下(输入归一化二值图像):

void Rosenfeld(Mat& src, Mat& dst)//输入的目标像素为1,背景像素为0
{if (src.type() != CV_8UC1){printf("只能处理二值或灰度图像\n");return;}//非原地操作时候,copy src到dstif (dst.data != src.data){src.copyTo(dst);}int i, j, n;int width, height;//之所以减1,是方便处理8邻域,防止越界width = src.cols - 1;height = src.rows - 1;int step = src.step;int  p2, p3, p4, p5, p6, p7, p8, p9;uchar* img;bool ifEnd;Mat tmpimg;int dir[4] = { -step, step, 1, -1 };while (1){//分四个子迭代过程,分别对应北,南,东,西四个边界点的情况ifEnd = false;for (n = 0; n < 4; n++){dst.copyTo(tmpimg);img = tmpimg.data;for (i = 1; i < height; i++){img += step;for (j = 1; j < width; j++){uchar* p = img + j;//如果p点是背景点或者且为方向边界点,依次为北南东西,继续循环if (p[0] == 0 || p[dir[n]] > 0) continue;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;//8 simple判定int is8simple = 1;if (p2 == 0 && p6 == 0){if ((p9 == 1 || p8 == 1 || p7 == 1) && (p3 == 1 || p4 == 1 || p5 == 1))is8simple = 0;}if (p4 == 0 && p8 == 0){if ((p9 == 1 || p2 == 1 || p3 == 1) && (p5 == 1 || p6 == 1 || p7 == 1))is8simple = 0;}if (p8 == 0 && p2 == 0){if (p9 == 1 && (p3 == 1 || p4 == 1 || p5 == 1 || p6 == 1 || p7 == 1))is8simple = 0;}if (p4 == 0 && p2 == 0){if (p3 == 1 && (p5 == 1 || p6 == 1 || p7 == 1 || p8 == 1 || p9 == 1))is8simple = 0;}if (p8 == 0 && p6 == 0){if (p7 == 1 && (p9 == 1 || p2 == 1 || p3 == 1 || p4 == 1 || p5 == 1))is8simple = 0;}if (p4 == 0 && p6 == 0){if (p5 == 1 && (p7 == 1 || p8 == 1 || p9 == 1 || p2 == 1 || p3 == 1))is8simple = 0;}int adjsum;adjsum = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;//判断是否是邻接点或孤立点,0,1分别对于那个孤立点和端点if (adjsum != 1 && adjsum != 0 && is8simple == 1){dst.at<uchar>(i, j) = 0; //满足删除条件,设置当前像素为0ifEnd = true;}}}}if (!ifEnd) break;}
}

OpenCV_Contrib中的算法

OpenCV细化算法大致描述如下:
1、复制源图,进行一次全图扫描,对于不为0的点,如果满足以下四个条件

  • (1)保证当前点不是孤立点或端点
  • (2)保证删除当前像素点后的连通性
  • (3)上 * 右 * 下 = 0
  • (4)左 * 右 * 下 = 0
  • 在第一次子迭代中,只是移去东南的边界点,而不考虑西北的边界点。

2、把目地图像再次复制到临时图像,接着对临时图像进行一次扫描,如果不为0的点它的八邻域满足以下4个条件,则在目地图像中删除该点(就是设置该像素为0)

  • (1) 周围8个点,2<= p2+p3+p4+p5+p6+p7+p8+p9<=6
  • (2) p2->p9的排列顺序中,01模式的数量(这里假设二值图非零值为1)为1。
  • (3) 左 * 右 * 上 = 0
  • (4) 左 * 下 * 上 = 0

执行完上面两个步骤后,就完成了一次细化算法,我们可以多次迭代执行上述过程,得到最终的骨架图。
算法源代码(输入二值图,无需归一化,一般的:thinningType=ZHANGSUEN):

// Apply the thinning procedure to a given image
void thinning(InputArray input, OutputArray output, int thinningType) {Mat processed = input.getMat().clone();CV_CheckTypeEQ(processed.type(), CV_8UC1, "");// Enforce the range of the input image to be in between 0 - 255processed /= 255;Mat prev = Mat::zeros(processed.size(), CV_8UC1);Mat diff;do {thinningIteration(processed, 0, thinningType);thinningIteration(processed, 1, thinningType);absdiff(processed, prev, diff);processed.copyTo(prev);} while (countNonZero(diff) > 0);processed *= 255;output.assign(processed);
}// Applies a thinning iteration to a binary image
void thinningIteration(Mat img, int iter, int thinningType) {Mat marker = Mat::zeros(img.size(), CV_8UC1);if (thinningType == THINNING_ZHANGSUEN) {for (int i = 1; i < img.rows - 1; i++){for (int j = 1; j < img.cols - 1; j++){uchar p2 = img.at<uchar>(i - 1, j);uchar p3 = img.at<uchar>(i - 1, j + 1);uchar p4 = img.at<uchar>(i, j + 1);uchar p5 = img.at<uchar>(i + 1, j + 1);uchar p6 = img.at<uchar>(i + 1, j);uchar p7 = img.at<uchar>(i + 1, j - 1);uchar p8 = img.at<uchar>(i, j - 1);uchar p9 = img.at<uchar>(i - 1, j - 1);int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +(p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +(p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +(p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)marker.at<uchar>(i, j) = 1;}}}if (thinningType == THINNING_GUOHALL) {for (int i = 1; i < img.rows - 1; i++){for (int j = 1; j < img.cols - 1; j++){uchar p2 = img.at<uchar>(i - 1, j);uchar p3 = img.at<uchar>(i - 1, j + 1);uchar p4 = img.at<uchar>(i, j + 1);uchar p5 = img.at<uchar>(i + 1, j + 1);uchar p6 = img.at<uchar>(i + 1, j);uchar p7 = img.at<uchar>(i + 1, j - 1);uchar p8 = img.at<uchar>(i, j - 1);uchar p9 = img.at<uchar>(i - 1, j - 1);int C = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);int N = N1 < N2 ? N1 : N2;int m = iter == 0 ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0)))marker.at<uchar>(i, j) = 1;}}}img &= ~marker;
}

示例

总结:其实几种算法的效果都差不多,但第一种算法在细化时会忽略4行4列图像数据,如果目标在边缘位置,最好使用后两种算法。
原图:
在这里插入图片描述
细化图:
在这里插入图片描述
直接使用细化算法可能有很多毛刺,你可以先删除突出部分,然后再细化会好很多。

其他细化算法

查表法

//查表法//
Mat lookUpTable(Mat& mat, int lut[])
{Mat mat_in;mat.convertTo(mat_in, CV_16UC1);		 //8 转 16int MatX = mat_in.rows;int MatY = mat_in.cols;int num = 512;//表的维数和卷积核中的数据有关,小矩阵初始化按行赋值Mat kern = (Mat_<int>(3, 3) << 1, 8, 64, 2, 16, 128, 4, 32, 256);		//卷积核Mat mat_out = Mat::zeros(MatX, MatY, CV_16UC1);Mat mat_expend = Mat::zeros(MatX + 2, MatY + 2, CV_16UC1);Rect Roi(1, 1, MatY, MatX);				//(列,行,列,行)Mat mat_expend_Roi(mat_expend, Roi);	//确定扩展矩阵的Roi区域mat_in.copyTo(mat_expend_Roi);			//将传入矩阵赋给Roi区域Mat Mat_conv;//实用卷积核和和每一个八邻域进行点乘再相加,其结果为表的索引,对应值为0能去掉,为1则不能去掉filter2D(mat_expend, Mat_conv, mat_expend.depth(), kern);				//卷积Mat mat_index = Mat_conv(Rect(1, 1, MatY, MatX));for (int i = 0; i < MatX; i++){for (int j = 0; j < MatY; j++){int matindex = mat_index.at<short>(i, j);if ((matindex < num) && (matindex > 0)){mat_out.at<short>(i, j) = lut[matindex];}else if (matindex > num){mat_out.at<short>(i, j) = lut[num - 1];}}}return mat_out;
}//细化查表法//
Mat img_bone(Mat& mat)
{// mat 为细化后的图像Mat mat_in = mat;//在数字图像处理时,只有单通道、三通道 8bit 和 16bit 无符号(即CV_16U)的 mat 才能被保存为图像mat.convertTo(mat_in, CV_16UC1);int lut_1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 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, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 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,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };int lut_2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 };Mat mat_bool;threshold(mat_in, mat_bool, 0, 1, THRESH_BINARY);	//二值图像归一化Mat mat_out;Mat image_iters;while (true){mat_out = mat_bool;//查表:水平、垂直image_iters = lookUpTable(mat_bool, lut_1);mat_bool = lookUpTable(image_iters, lut_2);Mat diff = mat_out != mat_bool;//countNonZero函数返回灰度值不为0的像素数bool mat_equal = countNonZero(diff) == 0;		//判断图像是否全黑if (mat_equal){break;}}Mat Matout;mat_bool.convertTo(Matout, CV_8UC1);return Matout;
}

HilditchThin的另一种算法

void cvHilditchThin(cv::Mat& src, cv::Mat& dst)
{if (src.type() != CV_8UC1){printf("只能处理二值或灰度图像\n");return;}//非原地操作时候,copy src到dstif (dst.data != src.data){src.copyTo(dst);}//8邻域的偏移量int offset[9][2] = { {0,0},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1} };//四邻域的偏移量int n_odd[4] = { 1, 3, 5, 7 };int px, py;int b[9];                      //3*3格子的灰度信息int condition[6];              //1-6个条件是否满足int counter;                   //移去像素的数量int i, x, y, copy, sum;uchar* img;int width, height;width = dst.cols;height = dst.rows;img = dst.data;int step = dst.step;do{counter = 0;for (y = 0; y < height; y++){for (x = 0; x < width; x++){//前面标记为删除的像素,我们置其相应邻域值为-1for (i = 0; i < 9; i++){b[i] = 0;px = x + offset[i][0];py = y + offset[i][1];if (px >= 0 && px < width &&    py >= 0 && py < height){// printf("%d\n", img[py*step+px]);if (img[py*step + px] == WHITE){b[i] = 1;}else if (img[py*step + px] == GRAY){b[i] = -1;}}}for (i = 0; i < 6; i++){condition[i] = 0;}//条件1,是前景点if (b[0] == 1) condition[0] = 1;//条件2,是边界点sum = 0;for (i = 0; i < 4; i++){sum = sum + 1 - abs(b[n_odd[i]]);}if (sum >= 1) condition[1] = 1;//条件3, 端点不能删除sum = 0;for (i = 1; i <= 8; i++){sum = sum + abs(b[i]);}if (sum >= 2) condition[2] = 1;//条件4, 孤立点不能删除sum = 0;for (i = 1; i <= 8; i++){if (b[i] == 1) sum++;}if (sum >= 1) condition[3] = 1;//条件5, 连通性检测if (func_nc8(b) == 1) condition[4] = 1;//条件6,宽度为2的骨架只能删除1边sum = 0;for (i = 1; i <= 8; i++){if (b[i] != -1){sum++;}else{copy = b[i];b[i] = 0;if (func_nc8(b) == 1) sum++;b[i] = copy;}}if (sum == 8) condition[5] = 1;if (condition[0] && condition[1] && condition[2] && condition[3] && condition[4] && condition[5]){img[y*step + x] = GRAY; //可以删除,置位GRAY,GRAY是删除标记,但该信息对后面像素的判断有用counter++;//printf("----------------------------------------------\n");//PrintMat(dst);}}}if (counter != 0){for (y = 0; y < height; y++){for (x = 0; x < width; x++){if (img[y*step + x] == GRAY)img[y*step + x] = BLACK;}}}} while (counter != 0);
}

参考

https://www.cnblogs.com/mikewolf2002/p/3321732.html

http://www.hrbkazy.com/news/54102.html

相关文章:

  • 网上设计网站江西seo推广
  • 湖滨网站建设百度竞价官网
  • 公司网站毕业设计论文公司网站如何制作设计
  • 手机端网站开发教程深圳网站建设
  • 做外贸有什么免费网站正规电商培训学校排名
  • 网站建站平台源码b站入口2024已更新
  • 教育培训机构官网重庆seo推广运营
  • 长沙网站优化中囯军事网
  • 佛山网站建设价格百度一下首页官网
  • 国外做足球数据的网站有哪些今日十大热点新闻事件
  • 装修案例欣赏win10系统优化软件哪个好
  • 长兴县建设局网站长沙优化科技有限公司
  • 亿建联网站是谁做的如何推广一款app
  • 广州网站建设网络百度收录情况查询
  • 企业网络搭建技能大赛广东seo外包服务
  • 哪些网站是做食品网站优化是什么意思
  • 做救助流浪动物网站的产生背景广告推广代运营公司
  • 做外贸如何建立网站企业邮箱格式
  • 织梦网站建设google官网入口注册
  • 中山网站建设价位百度一下首页问问
  • 个人简介网站源码腾讯企点客服
  • 查看网站有没有备案百度广告一级代理
  • 武汉城市建设招标网站雅思培训班价格一般多少
  • 如何联系百度人工客服宁波seo推广如何收费
  • 广州乐地网站建设公司自助网站建设
  • 网站开发 方案合肥seo排名公司
  • 个人能备案多少个网站百度搜索排行榜
  • 网站站长seo推广企业邮箱登录入口
  • 网站修改解析怎么做燃灯seo
  • 多行业品牌企业公司网站模板360优化大师官方下载