细化程序 实测能用

参考来自:http://www.csdn123.com/html/itweb/20130917/124285_124289_124308.htm

第一种算法描述

假设当前被处理的像素为p0,我们使用下图所示的8邻域表示方式。

image

     我们处理的为二值图像,背景为黑色,值为0,要细化的前景物体像素值为255。

     对于Hilditch算法来说,它并不是一个完全的并行算法,而是串行并行相结合。当前像素是否是能够删除的骨架点,不仅是由它周围的8邻域决定,而且和前面像素的判定结果有关。一个像素判定为可以删除,我们并不直接删除它,而是在目地图像中设置像素值为GRAY=128,这个信息可能会影响之后其它像素的判定。

      当图像一次扫描迭代完成后,我们把所有置为GRAY的像素设置为0,从而删除它。

 

算法的描述如下。

迭代扫描当前图像

    对于当前像素点,扫描它的8邻域,如果邻域的像素值为255,则b[i]=1(i=0…8),像素值为128(GRAY,表示该像素点在前面的循环中被标记为删除),b[i]=-1,如果像素值为0,则b[i]=0。

imageimage

下面会根据b[i]的值进行6个条件判断,如果条件满足,则会标记该像素值为GRAY(128)。

1. b[0]=1,即当前像素必须为前景点。

2. 1-abs(b1) + 1 – abs(b3) + 1 – abs(b5) + 1 – abs(b7) >= 1,该条件表示当前像素为边界点,即东西南北四个点至少有一个b[i]=0。

3. abs(b1)+…+abs(b8)>=2, 该条件表示不能删除端点,即p0点周围只有一个点为1或-1的情况。

4.  统计b1到b8等于1的数量,该数量值必须大于1,该条件表示不能删除端点。、

5.  连通性检测,使用下面的公式:首先根据当前像素周围3*3域的值,记录d[9]数组,如果b[i]等于0,则d[i]=0, 否则d[i]=1,最后计算 d1-d1*d2*d3+d3-d3*d4*d5+d5-d5*d6*d7+d7-d7*d8*d1是否为1,为1则满足连通性,可以删除。

image

6.最后一个条件保证当轮廓是2个像素宽时,只删除一边。统计sum的值,当值为8时候,可以删除。

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; 
    }

     当这6个条件都满足时候,标记当前像素值为GRAY(128),然后在判断别的像素。当所有像素都扫描一遍后,完成一次迭代。

此时我们会把刚才标记为GARY的像素,都设置为0,真正的删除它,如果上一次循环已经没有标记删除的像素,则退出迭代,否则进行下一次迭代。

算法代码:

/*细化部分*/
//cv::Mat image_gray_thin;
//gThin Thin;
//Thin.cvHilditchThin(image_gray,image_gray_thin);
//cv::namedWindow("image_gray_thin",0);
//cv::imshow("image_gray_thin",image_gray_thin);


#include "gThin.h"


#define WHITE 255
#define GRAY 128
#define BLACK 0
gThin::gThin(void)
{
}


gThin::~gThin(void)
{
}


int gThin::func_nc8(int *b)
    //端点的连通性检测
{
    int n_odd[4] = { 1, 3, 5, 7 };  //四邻域
    int i, j, sum, d[10];          


    for (i = 0; i <= 9; i++) {
        j = i;
        if (i == 9) j = 1;
        if (abs(*(b + j)) == 1)
        {
            d[i] = 1;
        } 
        else 
        {
            d[i] = 0;
        }
    }
    sum = 0;
    for (i = 0; i < 4; i++)
    {
        j = n_odd[i];
        sum = sum + d[j] - d[j] * d[j + 1] * d[j + 2];
    }
    return (sum);
}


void gThin::cvHilditchThin(cv::Mat& src, cv::Mat& dst)
{
    if(src.type()!=CV_8UC1)
    {
        printf("只能处理二值或灰度图像\n");
        return;
    }
    //非原地操作时候,copy src到dst
    if(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++) 
            {


                //前面标记为删除的像素,我们置其相应邻域值为-1
                for (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);


}



#include <opencv2\opencv.hpp>


#pragma once
class gThin
{
public:
gThin(void);
~gThin(void);
int gThin::func_nc8(int *b);
void gThin::cvHilditchThin(cv::Mat& src, cv::Mat& dst);
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值