大律法

应用大律法对图像进行二值化处理

作者: yym439 时间: 2019-10-25

图像二值化

24位真彩图(1像素3字节)进行二值化为单色图(1像素1位),需要进行如下处理:

  1. 灰度化处理
  2. 选取合适的阈值,二值化处理

灰度化处理算法

灰度图:每个像素占一个字节,即RGB转换为单色的[0 ~256]之间的灰度,常用的转换公式如下:

Gray = 0.299 * R + 0.587 * G + 0.114 * B;

大律法,取自适应阈值

大津法是一种图像灰度自适应的阈值分割算法。实现思路:

  1. 计算0~255各灰阶对应的像素个数,保存至一个数组中,该数组下标是灰度值,保存内容是当前灰度值对应像素数

  2. 计算背景图像的平均灰度、背景图像像素数所占比例

  3. 计算前景图像的平均灰度、前景图像像素数所占比例

  4. 遍历0~255各灰阶,计算并寻找类间方差极大值

什么是类间方差

  1. ω0:前景的像素点数占整幅图像的比例
  2. μ0:前景平均灰度
  3. ω1:背景像素点数占整幅图像的比例
  4. μ1:背景平均灰度
  5. μ:图像的总平均灰度
  6. g:类间方差
  7. N: 图像总像素数(灰度图的宽*高)
  8. N0:图像中像素的灰度值小于阈值T的像素个数
  9. N1:图像中像素的灰度值大于阈值T的像素个数
  10. T:阈值

则有如下公式:

ω0=N0/ N —-1

ω1=N1/ N —-2

N0+N1=N —-3

ω0+ω1=1 —-4

μ=ω0μ0+ω1μ1 —-5

g=ω0(μ0-μ)^2 + ω1(μ1-μ)^2 —-6

将式(5)代入式(6),得到等价公式:

 g=ω0ω1(μ0-μ1)^2 —-7 这个就是类间方差的公式表述

采用遍历的方法得到使类间方差g最大的阈值T,即为所求。

C代码实现

/**
* 二值化算法
*参数:
    width 像素宽度
    height 像素高度
    *data8  灰度图数据
*返回:二值图数据
*/
unsigned char* otsu(int width,int height,unsigned char *data8,int nThreshold)
{

    int N = height*width;           //总像素数
    //计算自适应阈值
    if(nThreshold<0 || nThreshold>255)
    {
        double nHistogram[256];         //灰度直方图
        double dVariance[256];          //类间方差
        for(int i=0; i<256; i++)
        {
            nHistogram[i] = 0.0;
            dVariance[i] = 0.0;
        }
        //获取灰度图,每一个像素点数据,计算出灰度直方图
        for(int i=0; i<N; i++)
        {
            unsigned char nData = data8[i];
            nHistogram[nData]++;     //建立直方图
        }
        double Pa=0.0;      //背景出现概率
        double Pb=0.0;      //目标出现概率
        double Wa=0.0;      //背景平均灰度值
        double Wb=0.0;      //目标平均灰度值
        double W0=0.0;      //全局平均灰度值
        double dData1=0.0,  dData2=0.0;
        for(int i=0; i<256; i++)     //计算全局平均灰度
        {
            nHistogram[i] /= N;
            W0 += i*nHistogram[i];
        }
        for(int i=0; i<256; i++)     //对每个灰度值计算类间方差
        {
            Pa += nHistogram[i];
            Pb = 1-Pa;
            dData1 += i*nHistogram[i];
            dData2 = W0-dData1;
            Wa = dData1/Pa;
            Wb = dData2/Pb;
            dVariance[i] = (Pa*Pb* pow((Wb-Wa), 2));
        }
        //遍历每个方差,求取类间最大方差所对应的灰度值
        double temp=0.0;
        for(int i=0; i<256; i++)
        {
            if(dVariance[i]>temp)
            {
                temp = dVariance[i];
                nThreshold = i;
            }
        }
    }
    printf("阈值为:%d\n",nThreshold);
    int g_size = N/8;
    unsigned char *data1 = (unsigned char *)malloc(g_size);
    unsigned char piexBit = 0;
    int index = 0;
    for(int i=0; i<N; i=i+8)
    {
        for(int j=0; j<8; j++)
        {
            if(data8[i+j] < nThreshold)
            {
                piexBit |= (1<<(7-j));//将piexBit的第(7-j)位, 置1
            }
            else
            {
                piexBit &= ~(1<<(7-j)); //将piexBit的第(7-j)位,置0
        }
        data1[index++] = piexBit;
    }
    return data1;
}