关于一些智能车的全局阈值算法

这里写自定义目录标题

,里面借鉴了一下龙邱的二值化还有我根据一些博客改的历程,有的博客网址忘了在哪里看的,引用时候加不上网址了,有作者看到可以告诉我,我会加上网址
*

  • 函数名称:void BinaryImage(uint8_t tmImage[IMAGEH][IMAGEW])
  • 功能说明:图像数据二值化
  • 参数说明:
  • 函数返回:void
  • 修改时间:2018年3月27日
  • 备 注:
    /
    void BinaryImage(uint8_t tmImage[IMAGEH][IMAGEW],uint8_t ThresholdV)
    {
    int i = 0, j = 0;
    for(i = 0;i < IMAGEH;i++)
    {
    for(j = 0; j< IMAGEW;j++)
    {
    if(tmImage[i][j] >= ThresholdV)
    {
    tmImage[i][j] = 0xFE;
    }
    else
    {
    tmImage[i][j] = 0X00;
    }
    }
    }
    }
    /
  • 函数名称:uint8_t GetOSTU(uint8_t tmImage[IMAGEH][IMAGEW])
  • 功能说明:求阈值大小
  • 参数说明:
  • 函数返回:阈值大小
  • 修改时间:2018年3月27日
  • 备 注:
    参考:https://blog.csdn.net/zyzhangyue/article/details/45841255
    https://www.cnblogs.com/moon1992/p/5092726.html
    https://www.cnblogs.com/zhonghuasong/p/7250540.html
    Ostu方法又名最大类间差方法,通过统计整个图像的直方图特性来实现全局阈值T的自动选取,其算法步骤为:
  1. 先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量
  2. 归一化直方图,也即将每个bin中像素点数量除以总的像素点
  3. i表示分类的阈值,也即一个灰度级,从0开始迭代
  4. 通过归一化的直方图,统计0~i 灰度级的像素(假设像素值在此范围的像素叫做前景像素) 所占整幅图像的比例w0,并统计前景像素的平均灰度u0;统计i~255灰度级的像素(假设像素值在此范围的像素叫做背景像素) 所占整幅图像的比例w1,并统计背景像素的平均灰度u1;
  5. 计算前景像素和背景像素的方差 g = w0w1(u0-u1) (u0-u1)
  6. i++;转到4),直到i为256时结束迭代
    7)将最大g相应的i值作为图像的全局阈值
    缺陷:OSTU算法在处理光照不均匀的图像的时候,效果会明显不好,因为利用的是全局像素信息。
    ***************************************************************/
    uint8_t GetOSTU(uint8_t tmImage[IMAGEH][IMAGEW])
    {
    int16_t i,j;
    uint32_t Amount = 0; //像素总数
    uint32_t PixelBack = 0; 前景像素点数
    uint32_t PixelIntegralBack = 0;//前景灰度值
    uint32_t PixelIntegral = 0; //灰度值
    int32_t PixelIntegralFore = 0; //背景灰度值
    int32_t PixelFore = 0; //背景像素点数
    double OmegaBack, OmegaFore, MicroBack, MicroFore, SigmaB, Sigma; // 像素百分比;灰度百分比;类间方差;
    int16_t MinValue, MaxValue;//最小值最大值
    uint8_t Threshold = 0;
    uint8_t HistoGram[256]; // 先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量

for (j = 0; j < 256; j++) HistoGram[j] = 0; //初始化灰度直方图 ,使其为0

for (j = 0; j < IMAGEH; j++)
{
for (i = 0; i < IMAGEW; i++)
{
HistoGram[tmImage[j][i]]++; //统计灰度级中256个小长方形中每个长方形像素的个数
}
}
//灰度值就是0~255,598行我改了,我认为他代码错了
for (MinValue = 0; MinValue < 256 && HistoGram[MinValue] == 0; MinValue++) ; //获取最小灰度的值
for (MaxValue = 255; MaxValue > MinValue && HistoGram[MaxValue] == 0; MaxValue–) ; //获取最大灰度的值

if (MaxValue == MinValue) return MaxValue; // 图像中只有一个颜色
if (MinValue+1 == MaxValue) return MinValue; // 图像中只有二个颜色

//for (j = MinValue; j <= MaxValue; j++) Amount += HistoGram[j]; // 像素总数

PixelIntegral = 0;
for (j = MinValue; j <= MaxValue; j++)
{
Amount += HistoGram[j]; // 像素总数
PixelIntegral += HistoGram[j] * j;//灰度值总数
}
SigmaB = -1;
for (j = MinValue; j < MaxValue; j++)//这里需要设定前景与后景比较值
{
PixelBack = PixelBack + HistoGram[j]; //前景像素点数
PixelFore = Amount - PixelBack; //背景像素点数
OmegaBack = (double)PixelBack / Amount;//前景像素百分比
OmegaFore = (double)PixelFore / Amount;//背景像素百分比
PixelIntegralBack += HistoGram[j] * j; //前景灰度值
PixelIntegralFore = PixelIntegral - PixelIntegralBack;//背景灰度值
MicroBack = (double)PixelIntegralBack / PixelBack; //前景灰度百分比
MicroFore = (double)PixelIntegralFore / PixelFore; //背景灰度百分比
Sigma = OmegaBack * OmegaFore * (MicroBack - MicroFore) * (MicroBack - MicroFore);//计算类间方差
if (Sigma > SigmaB) //遍历最大的类间方差g //找出最大类间方差以及对应的阈值
{
SigmaB = Sigma;
Threshold = j; //返回最佳阈值,找最大方差选阈值
}
}
return Threshold; //返回最佳阈值,找最大方差选阈值
}

/****************************************************
注意
1. 求出图象的最大灰度值和最小灰度值,分别记为Pmax和Pmin,令初始阈值T0=(Pmax+Pmin)/2;

2. 根据阈值T(k)(k=0,1,2…,k)将图象分割为前景和背景,分别求出两者的平均灰度值H1和H2;

3. 求出新阈值T(k+1)=(H1+H2)/2;

4. 若 T(k)-T(k+1)=X (一个预定义的参数范围内,自己设定),则所得即为阈值;否则转2,迭代计算
4。或者是新阈值等于旧的阈值,;否则转2,迭代计算

  • 函数名:Itera_Threshold

  • 功 能:迭代阈值法,能够找到灰度图的最佳二值化点
    ****************************************************/
    uint8 Itera_Threshold(uint8_t tmImage[IMAGEH][IMAGEW])
    {
    u16 i=0,j=0,k=0,cnt=0,mux=0,Camera_Data=0;
    u8 newthreshold=0;
    u16 Pmax=0,Pmin=0;
    u32 sum_h1=0,sum_h2=0;
    u32 foresum=0,backsum=0;

    //数据清空
    for( i=0; i<256; i++ )
    {
    gray_test_value[i] = 0;//灰度值数据清空
    }

    for( i=0; i<IMAGEH; i++ )
    {
    for( j=0; j<IMAGEW; j++ )
    {
    mux = tmImage[i][j]; //获取灰度图的数据,这个pixel数组用来像素点灰度的;

    //像素点数自增       
     gray_itera_threshold[mux]++; //不同灰度值对应的像素点数
    }
    

    }

    for (Pmin = 0; Pmin < 256 && gray_itera_threshold[Pmin] == 0; Pmin++) ; //获取最小灰度的值
    for (Pmax = 255; Pmax > Pmin && gray_itera_threshold[Pmax] == 0; Pmax–) ; //获取最大灰度的值

    if (Pmax == Pmin) return Pmax; // 图像中只有一个颜色
    if (Pmin+1 == Pmax) return Pmin; // 图像中只有二个颜色

    printf(“the Pmax is %d\n”,Pmax);
    printf(“the Pmin is %d\n”,Pmin);

    //初始阈值
    threshold_h[0] = ( Pmax + Pmin ) / 2;

    //寻找最佳阈值
    for( k=0; k<256; k++ )
    {
    //分割前景和背景
    for( cnt=0; cnt<threshold_h[k]; cnt++ )
    {
    foresum+=gray_itera_threshold[cnt];
    sum_h1 += gray_itera_threshold[cnt]*cnt;
    }
    for( cnt=threshold_h[k]; cnt<256; cnt++ )
    {
    backsum+=gray_itera_threshold[cnt];
    sum_h2 += gray_itera_threshold[cnt]*cnt;
    }
    sum_h1 /= foresum;//前景求平均值阈值
    sum_h2 /= backsum;//背景求平均值阈值

    //计算出新的阈值
      threshold_h[k+1] = ( sum_h1 + sum_h2 ) / 2; 
    
      if( fabs(threshold_h[k]-threshold_h[k+1]) <= 10 )//这里的数是用来定义阈值范围,需要自己改
      {
        newthreshold = threshold_h[k+1];
         break;
      }
    
      sum_h1 = 0;
      sum_h2 = 0;
    

    }
    return newthreshold;

}

/*
此方法实用于具有明显双峰直方图的图像,其寻找双峰的谷底作为阈值,但是该方法不一定能获得阈值,对于那些具有平坦的直方图或单峰图像,该方法不合适。

2、实现过程:
该函数的实现是一个迭代的过程,每次处理前对直方图数据进行判断,看其是否已经是一个双峰的直方图,如果不是,则对直方图数据进行半径为1(窗口大小为3)的平滑,
如果迭代了一定的数量比如1000次后仍未获得一个双峰的直方图,则函数执行失败,如成功获得,则最终阈值取两个双峰之间的谷底值作为阈值。
注意在编码过程中,平滑的处理需要当前像素之前的信息,因此需要对平滑前的数据进行一个备份。另外,首数据类型精度限制,不应用整形的直方图数据,
必须转换为浮点类型数据来进行处理,否则得不到正确的结果。//

*/
//但是这里需要改动,因为得找一个峰值不能循环
uint8 GetMinimumThreshold(uint8_t tmImage[IMAGEH][IMAGEW])
{
double Peakfound = 0;
int i,j,Y, Iter = 0;
double gray_itera_thresholdC[256]; // 基于精度问题,一定要用浮点数来处理,否则得不到正确的结果
double gray_itera_thresholdCC[256]; // 求均值的过程会破坏前面的数据,因此需要两份数据
for( i=0; i<IMAGEH; i++ )
{
for( j=0; j<IMAGEW; j++ )
{
//像素点数自增
gray_itera_threshold[ tmImage[i][j]]++; //不同灰度值对应的像素点数
}
}
for (Y = 0; Y < 256; Y++)
{
gray_itera_thresholdC[Y] = gray_itera_threshold[Y];
gray_itera_thresholdCC[Y] = gray_itera_threshold[Y];
}

    // 通过三点求均值来平滑直方图
    while (IsDimodal(gray_itera_thresholdCC) == 0)                                        // 判断是否已经是双峰的图像了      
    {
        gray_itera_thresholdCC[0] = (gray_itera_thresholdC[0] + gray_itera_thresholdC[0] + gray_itera_thresholdC[1]) / 3;                 // 第一点
        for (Y = 1; Y < 255; Y++)
            gray_itera_thresholdCC[Y] = (gray_itera_thresholdC[Y - 1] + gray_itera_thresholdC[Y] + gray_itera_thresholdC[Y + 1]) / 3;     // 中间的点
        gray_itera_thresholdCC[255] = (gray_itera_thresholdC[254] + gray_itera_thresholdC[255] + gray_itera_thresholdC[255]) / 3;         // 最后一点
       
        Iter++;
        if (Iter >= 1000) return -1;                                                   // 直方图无法平滑为双峰的,返回错误代码
    }
   // 阈值极为两峰之间的最小值 

    for (Y = 1; Y < 255; Y++)
    {
        if (gray_itera_thresholdCC[Y - 1] < gray_itera_thresholdCC[Y] && gray_itera_thresholdCC[Y + 1] < gray_itera_thresholdCC[Y]) 
          Peakfound=1;
        if (Peakfound= 1 && gray_itera_thresholdCC[Y - 1] >= gray_itera_thresholdCC[Y] && gray_itera_thresholdCC[Y + 1] >= gray_itera_thresholdCC[Y])
            return Y - 1;
    }
    return -1;
}

//1是可以意思

uint8 IsDimodal(double gray_itera_threshold[256]) // 检测直方图是否为双峰的
{
// 对直方图的峰进行计数,只有峰数位2才为双峰
int Count = 0;
for (int Y = 1; Y < 255; Y++)
{
if (gray_itera_threshold[Y - 1] < gray_itera_threshold[Y] && gray_itera_threshold[Y + 1] < gray_itera_threshold[Y])
{
Count++;
if (Count > 2) return 0;
}
}
if (Count == 2)
return 1;
else
return 0;
}adrai.github.io/flowchart.js/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值