Opencv和EMguCV中没有用于图像细化的算法,网上有在opencv下写的图像细化算法,C#下写的图像细化算法都是用纯C#的方式写成的,用的提取像素的方式实现,速度很慢,所以今天我用指针的方式在C#中将图像细化算法写了一下。代码如下:
public unsafe Bitmap ToThinner(Bitmap srcImg) { int iw = srcImg.Width; int ih = srcImg.Height;
bool bModified; //二值图像修改标志 bool bCondition1; //细化条件1标志 bool bCondition2; //细化条件2标志 bool bCondition3; //细化条件3标志 bool bCondition4; //细化条件4标志
int nCount;
//5X5像素块 byte[,] neighbour = new byte[5, 5]; //新建临时存储图像 Bitmap NImg = new Bitmap(iw,ih,srcImg.PixelFormat);
bModified = true; //细化修改标志, 用作循环条件
BitmapData dstData = srcImg.LockBits(new Rectangle(0,0,iw,ih),ImageLockMode.ReadWrite,srcImg.PixelFormat); byte* data=(byte*)(dstData.Scan0); //将图像转换为0,1二值得图像; int step = dstData.Stride; for (int i = 0; i < dstData.Height; i++) { for (int j = 0; j < dstData.Width; j++) { if (data[i * step + j] > 128) data[i * step + j] = 0; else data[i * step + j] = 1; } }
BitmapData dstData1 = NImg.LockBits(new Rectangle(0,0,iw,ih),ImageLockMode.ReadWrite,NImg.PixelFormat); byte* data1 = (byte*)(dstData1.Scan0); int step1=dstData1.Stride; //细化循环开始 while (bModified) { bModified = false;
//初始化临时二值图像NImg for (int i = 0; i < dstData1.Height;i++ ) { for (int j = 0; j < dstData1.Width;j++ ) { data1[i * step1 + j] = 0; } } for (int i = 2; i < ih - 2; i++) { for (int j = 2; j < iw - 2; j++) { bCondition1 = false; bCondition2 = false; bCondition3 = false; bCondition4 = false;
if (data[i*step+j] == 0) //若图像的当前点为白色,则跳过 continue; for (int k = 0; k < 5; k++) { //取以当前点为中心的5X5块 for (int l = 0; l < 5; l++) { //1代表黑色, 0代表白色 //neighbour[k, l] = bw[i + k - 2, j + l - 2]; neighbour[k, l] = data[(i + k - 2) * step + (j + l - 2)]; } }
//(1)判断条件2<=n(p)<=6 nCount = neighbour[1, 1] + neighbour[1, 2] + neighbour[1, 3] + neighbour[2, 1] + neighbour[2, 3] + neighbour[3, 1] + neighbour[3, 2] + neighbour[3, 3]; if (nCount >= 2 && nCount <= 6) bCondition1 = true; else { data1[i * step1 + j] = 1; continue; //跳过, 加快速度 }
//(2)判断s(p)=1 nCount = 0; if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1) nCount++; if (neighbour[1, 3] == 0 && neighbour[1, 2] == 1) nCount++; if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1) nCount++; if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1) nCount++; if (neighbour[2, 1] == 0 && neighbour[3, 1] == 1) nCount++; if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1) nCount++; if (neighbour[3, 2] == 0 && neighbour[3, 3] == 1) nCount++; if (neighbour[3, 3] == 0 && neighbour[2, 3] == 1) nCount++; if (nCount == 1) bCondition2 = true; else { data1[i * step1 + j] = 1; continue; }
//(3)判断p0*p2*p4=0 or s(p2)!=1 if (neighbour[2, 3] * neighbour[1, 2] * neighbour[2, 1] == 0) bCondition3 = true; else { nCount = 0; if (neighbour[0, 2] == 0 && neighbour[0, 1] == 1) nCount++; if (neighbour[0, 1] == 0 && neighbour[1, 1] == 1) nCount++; if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1) nCount++; if (neighbour[2, 1] == 0 && neighbour[2, 2] == 1) nCount++; if (neighbour[2, 2] == 0 && neighbour[2, 3] == 1) nCount++; if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1) nCount++; if (neighbour[1, 3] == 0 && neighbour[0, 3] == 1) nCount++; if (neighbour[0, 3] == 0 && neighbour[0, 2] == 1) nCount++; if (nCount != 1) //s(p2)!=1 bCondition3 = true; else { data1[i * step1 + j] = 1; continue; } }
//(4)判断p2*p4*p6=0 or s(p4)!=1 if (neighbour[1, 2] * neighbour[2, 1] * neighbour[3, 2] == 0) bCondition4 = true; else { nCount = 0; if (neighbour[1, 1] == 0 && neighbour[1, 0] == 1) nCount++; if (neighbour[1, 0] == 0 && neighbour[2, 0] == 1) nCount++; if (neighbour[2, 0] == 0 && neighbour[3, 0] == 1) nCount++; if (neighbour[3, 0] == 0 && neighbour[3, 1] == 1) nCount++; if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1) nCount++; if (neighbour[3, 2] == 0 && neighbour[2, 2] == 1) nCount++; if (neighbour[2, 2] == 0 && neighbour[1, 2] == 1) nCount++; if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1) nCount++; if (nCount != 1)//s(p4)!=1 bCondition4 = true;
} if (bCondition1 && bCondition2 && bCondition3 && bCondition4) { data1[i * step1 + j] = 0; bModified = true; } else { data1[i * step1 + j] = 1; } } }
//将细化了的临时图像bw_tem[w,h]copy到bw[w,h],完成一次细化 for (int i = 2; i < ih - 2; i++) for (int j = 2; j < iw - 2; j++) data[i * step + j] = data1[i * step1 + j]; }
for (int i = 2; i < ih - 2; i++) { for (int j = 2; j < iw - 2; j++) { if (data[i * step + j] == 1) data[i * step + j] = 0; else data[i * step + j] = 255; } } srcImg.UnlockBits(dstData); NImg.UnlockBits(dstData1); return (srcImg); }
注意:ToThinner(Bitmap srcImg)输入参数srcImg为Bitmap格式的,灰度值为0和255的二值图像。细化算法适用于想细化的线条是黑色,背景是白色的情况,如下面这种图;