今天终于完成了基于索引的二值图像…

1。没有相关的图像处理理论基础,在网上搜索学习。

最简单的是基于字典索引的3*3 模板细化,由于网上的都是C语言的,在转换代码是,忽略了应该多次循环直到没有点可以删除,所以效果一直不理想。

2。虽然这个方法有些毛刺,但是作为数字验证码识别基本上完成了(vb2008代码如下)

 Function ThiningDIB(ByVal sImage(,) As Boolean)

        '基于索引表的细化细化算法
        '功能:对图象进行细化
        '参数:sImage(,) :代表图象的二维数组
        返回值:细化处理后的二值二维数组

        Dim Image_W As Int16 = UBound(sImage, 1)   '图像宽       

       Dim Image_H As Int16 = UBound(sImage, 2)   '图像高
        Dim finished1, finished2 As Int16
        Dim x, y As Int16
        Dim nw, n, ne, w, e, sw, s, se As Boolean
        Dim sum As Integer
        Dim deletemark() As Boolean = { _
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 _
}

        '索引表
        '去除边缘,应为边缘无法计算3*3邻居
        For y = 0 To Image_H
            sImage(0, y) = 0
            sImage(Image_W, y) = 0
        Next

        For x = 0 To Image_W
            sImage(x, 0) = 0
            sImage(x, Image_H) = 0
        Next
        '开始细化

        finished1 = False
        finished2 = False
        '水平扫描
        Try
            Do
                finished1 = 0

                For y = 1 To Image_H - 1
                    For x = 1 To Image_W - 1
                        If sImage(x, y) = True Then
                            w = sImage(x - 1, y)
                            e = sImage(x + 1, y)
                            '判断当前点是否边界点
                            If (w = True Or e = True) Then
                                nw = sImage(x - 1, y - 1)
                                n = sImage(x, y - 1)
                                ne = sImage(x + 1, y - 1)
                                sw = sImage(x - 1, y + 1)
                                s = sImage(x, y + 1)
                                se = sImage(x + 1, y + 1)
                                sum = Int(nw) + Int(n) * 2 + Int(ne) * 4 + Int(w) * 8 + Int(e) * 16 + Int(sw) * 32 + Int(s) * 64 + Int(se) * 128
                                If deletemark(sum) = True Then
                                    sImage(x, y) = False
                                    x += 1  '横向跳过下个邻点
                                    finished1 += 1
                                End If
                            End If
                        End If
                    Next
                Next
            Loop While finished1 > 0
            Do
                '垂直扫描
                finished2 = 0
                For x = 1 To Image_W - 1
                    For y = 1 To Image_H - 1
                        If sImage(x, y) = True Then
                            n = sImage(x, y - 1)
                            s = sImage(x, y + 1)
                            '判断当前点是否边界点
                            If (n = True Or s = True) Then
                                w = sImage(x - 1, y)
                                e = sImage(x + 1, y)
                                nw = sImage(x - 1, y - 1)
                                ne = sImage(x + 1, y - 1)
                                sw = sImage(x - 1, y + 1)
                                se = sImage(x + 1, y + 1)
                                sum = Int(nw) + Int(n) * 2 + Int(ne) * 4 + Int(w) * 8 + Int(e) * 16 + Int(sw) * 32 + Int(s) * 64 + Int(se) * 128
                                If deletemark(sum) = True Then
                                    sImage(x, y) = False
                                    y += 1   '纵向跳过下个邻点
                                    finished2 += 1
                                End If
                            End If
                        End If
                    Next
                Next
            Loop While finished2 > 0

              '删除孤立点,如果前期二值化做的好,就忽略下面这些           

            For x = 1 To Image_W - 1
                For y = 30 To Image_H - 1
                    If sImage(x, y) = True Then
                        n = sImage(x, y - 1)
                        s = sImage(x, y + 1)
                        w = sImage(x - 1, y)
                        e = sImage(x + 1, y)
                        nw = sImage(x - 1, y - 1)
                        ne = sImage(x + 1, y - 1)
                        sw = sImage(x - 1, y + 1)
                        se = sImage(x + 1, y + 1)
                  sum = Int(nw) + Int(n) + Int(ne) + Int(w) + Int(e) + Int(sw) + Int(s) + Int(se)
                        If sum = 0 Then
                            sImage(x, y) = False '删除孤立点
                        End If
                    End If
                Next
            Next
        Catch ex As Exception
            Exit Try
        End Try
        Return sImage
    End Function
End Module

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
// 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 <stdlib.h> #include <string.h> //基于索引表的细化细化算法 //功能:对图象进行细化 //参数: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; y<src->height; y++) { /* widthStep表示存储一行像素需要的字节数 偏移到第y行 */ unsigned char* ptr = (unsigned char*)(src->imageData + y*src->widthStep); for (x = 0; x<src->width; 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; y<src->height; y++) { /* widthStep表示存储一行像素需要的字节数 偏移到第y行 */ unsigned char* ptr = (unsigned char*)(src->imageData + y*src->widthStep); for (x = 0; x<src->width; 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; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值