依照中值滤波或双边滤波方式的图像去雾效果的钻研。

   
 3、计算图片 1,即对M(x)举办中值滤波。

 图片 2

 
 从成效上看,笔者所列举的那个事例都仍旧不错的,越发是率先幅图,用何凯明的暗通道笔者直接未有调出那种成效。

   
 不难的来说,算法的流水生产线可讲述如下:

   关于中值滤波或然两者滤波的急速算法,能够在自身博客中找到大批量的有关音讯。

     算法的最基础的原理依旧依据大气散射模型的,即:

  一、定义F(X)=A(一-t(x)),称之为大气光幕可能为雾浓度。

   
 5、计算图片 3,式中P为操纵去雾程度的因子,取值范围[0,1]。

 
 在大方光幕的公式中,大家来看有大局大气光A的震慑,不过上述总结F(X)的经过确未有涉嫌到A,非常无语啊。

   
 陆、通过式子图片 4获得去雾后的图像。

     图片 5

 
 那里的大批量光幕和何凯明的舆论中的透射率图不是同2个定义,由此不享有可比性。

  已知条件正是输入图像I(X),求J(x);

四、代码落成细节

 图片 6  图片 7  图片 8

2、算法的流水生产线

3、算法的职能

                   
 图片 9

一、前言  

           原图                          
   去雾图                          
 对应的多量光幕

  算法的原理笔者讲不清,反正看的越多越迷糊了。

   
 2、计算图片 10,并动用和何博士故事集中类似的点子测算全局大气光值A。

   
 在先后的耗费时间上,重要照旧1回中值处理上,借助于C++的片段优化(比如内嵌SSE代码,C#做不到)中值的进度也相当慢了,小编用10二四*76捌的灰度图测试耗费时间约为60ms(未挂念用八线程,因为13分程序用四线程编码上会复杂不少),对彩色图用那种艺术去雾,I3CPU上10二4*768的总耗费时间约为140ms,想要实时,换换I七的CPU试试啊(遗闻中作者的那篇实时去雾的篇章的算法在I三上20ms,I七上有测试申明只要三到四ms)。

     
算法的效果依旧多少突如其来,有个别图得到了极度不错的效应。

 图片 11  图片 12  图片 13

*********************************作者:
laviewpbt   时间: 201叁.1二.五   联系QQ:  3318477柒 转发请保留本行音信*************************

  实际上很久之前,当本身首先接触图像去雾技术时,初步实现的是基于中值滤波的图像去雾,并且也有肯定的作用,在本身的Imageshop的合1软件中的去雾方案便是其一的完成,可是那么些效果未有本文好。

   
 在代码完成上,个人感觉未有啥样难点,先求暗通道,然后就是多少个中值滤波或然是两者滤波,求全局大气光的经过还论及到细微值滤波,重要的代码如下:

   
 由于算法的终极一步的公式难点,在有些参数处境下图像会出现黑快大概白块,近年来该难题未有消除。
有趣味对改算法实行进一步测试的同班可协调查切磋究下。

   
 4、计算图片 14,注意式子中的相对值。

 图片 15  图片 16  图片 17

   
 上面包车型地铁多多算式是从分歧杂文里截图的,由此表达上多少前后不一样,但不影响高手精通其含义。

   
 在参考故事集壹种单幅图像去雾方法中是透过中值滤波的法子来去雾的,而舆论依据双方滤波的实时图像去雾技术商量采用了两岸滤波,假使您要达成代码,恐怕必要两篇杂谈结合起来看,因为在舆论第11中学的描述未有讲精通怎么通过得到的雾浓度数据来取得无雾的图像。

 图片 18  图片 19  图片 20

     相关测试代码下载:

 
 上述都以用中值滤波做的意义,在某个图像对应大气光幕图上能够看到,图像的边缘处有壹些小圆弧,这么些都以矩形半径中值滤波的显然划痕,而根据双方滤波的笔者也推行过,并从未像参考散文贰说的那样有些许立异,感觉相互相互,而且有个别图还会现出突变,由此作者认为写这个杂谈纯粹是为了发杂文。 

   
  http://files.cnblogs.com/Imageshop/HazeRemovalBasedOnMedianBlur.rar

 图片 21  图片 22  图片 23

   
 而据说双方滤波的方案,也是很已经据说过,前不久有朋友传给笔者1篇国内的互相滤波去雾的舆论,总体思路和依据中值的好像,想想干脆把那八个位于1块儿做个相比呢。

   
 要是是运用双边滤波算子,则步骤3和四中的median运算符需修改为bilaterfilter,别的的步子1样。

void _stdcall HazeRemovalBasedOnMedianBlur(unsigned char * Scan0, int Width,int Height,int Stride,int DarkRadius,int MedianRadius,int P)
{
    int  X, Y, Diff,Min,F;
    unsigned char* Pointer, *DarkP, *FilterP,* FilterPC;
    unsigned char * DarkChannel = (unsigned char*)malloc(Width * Height);
    unsigned char * Filter = (unsigned char*)malloc(Width * Height);
    unsigned char * FilterClone = (unsigned char*)malloc(Width * Height);

    for (Y = 0; Y < Height; Y++)
    {
        Pointer = Scan0 + Y * Stride;
        DarkP = DarkChannel + Y * Width;             // 由实际图像计算得到的图像暗通道     
        for (X = 0; X < Width; X++)
        {
            Min = *Pointer;
            if (Min > *(Pointer + 1)) Min = *(Pointer + 1);
            if (Min > *(Pointer + 2)) Min = *(Pointer + 2);
            *DarkP = (unsigned char)Min;
            DarkP++;
            Pointer += 3;
        }
    }
    memcpy(Filter, DarkChannel, Width * Height);                        // 求全局大气光A时会破坏DarkChannel中的数据

    MinValue(DarkChannel, Width, Height,Width,DarkRadius);                // 求取暗通道值

    // 利用暗通道来估算全局大气光值A
    int Sum, Value,Threshold = 0;
    int SumR = 0, SumG = 0, SumB = 0, AtomR, AtomB, AtomG, Amount = 0;
    int* Histgram = (int*)calloc(256 , sizeof(int));    
    for (Y = 0; Y < Width * Height; Y++) Histgram[DarkChannel[Y]]++;
    for (Y = 255, Sum = 0; Y >= 0; Y--)
    {
        Sum += Histgram[Y];
        if (Sum > Height * Width * 0.01)
        {
            Threshold = Y;                                        // 选取暗通道值中前1%最亮的像素区域为候选点
            break;
        }
    }
    AtomB = 0; AtomG = 0; AtomR = 0;
    for (Y = 0, DarkP = DarkChannel; Y < Height; Y++)
    {
        Pointer = Scan0 + Y * Stride;
        for (X = 0; X < Width; X++)
        {
            if (*DarkP >= Threshold)                            //    在原图中选择满足候选点的位置的像素作为计算全局大气光A的信息                        
            {
                SumB += *Pointer;
                SumG += *(Pointer + 1);
                SumR += *(Pointer + 2);
                Amount++;
            }
            Pointer += 3;
            DarkP++;
        }
    }
    AtomB = SumB / Amount;
    AtomG = SumG / Amount;
    AtomR = SumR / Amount;

    memcpy(DarkChannel,Filter, Width * Height);                        // 恢复DarkChannel中的数据
    MedianBlur(Filter,Width,Height,Width,MedianRadius,50);          // 步骤1:使用中值滤波平滑,这样处理的重要性是在平滑的同时保留了图像中的边界部分,但是实际这里用中值滤波和用高斯滤波效果感觉差不多
    memcpy(FilterClone, Filter, Width * Height);

    DarkP = DarkChannel;
    FilterP = Filter;
    for (Y = 0; Y < Height * Width; Y++)              //利用一重循环来计算提高速度
    {
        Diff = *DarkP - *FilterP;                    //通过对|DarkP -FilterP |执行中值滤波来估计的局部标准差,这样可以保证标准差估计的鲁棒性
        if (Diff < 0) Diff = -Diff;
        *FilterP = (unsigned char)Diff;
        DarkP++;
        FilterP++;
    }
    MedianBlur(Filter,Width,Height,Width,MedianRadius,50);

    FilterPC = FilterClone;
    FilterP = Filter;
    for (Y = 0; Y < Height * Width; Y++)
    {
        Diff = *FilterPC - *FilterP;                    // 步骤2:然后考虑到有较好对比度的纹理区域可能没有雾, 这部分区域就不需要做去雾处理
        if (Diff < 0) Diff = 0;                            // 这里可以这样做是因为在最后有个max(....,0)的过程,
        *FilterP = (unsigned char)Diff;
        FilterPC++;
        FilterP++;
    }

    DarkP = DarkChannel;
    FilterP = Filter;

    for (Y = 0; Y < Height * Width; Y++)
    {
        Min = *FilterP * P / 100;
        if (*DarkP > Min) 
            *FilterP = Min;                                // 获得满足约束条件的大气光幕
        else
            *FilterP = *DarkP;
        DarkP++;
        FilterP++;
    }

    FilterP = Filter;
    for (Y = 0;Y < Height; Y++)
    {
        Pointer = Scan0 + Y * Stride;
        for (X = 0; X < Width; X++)
        {
            F = *FilterP++;
            if (AtomB != F) 
                Value = AtomB *(*Pointer - F) /( AtomB - F);
            else
                Value=*Pointer;
            *Pointer++ = Clamp(Value);
            if (AtomG != F) 
                Value =  AtomG * (*Pointer - F) /( AtomG-F);
            else
                Value =  *Pointer;
            *Pointer++ = Clamp(Value);
            if (AtomR != F) 
                Value =  AtomR *(*Pointer - F) /( AtomR-F);
            else
                Value =  *Pointer;
            *Pointer++ = Clamp(Value);
        }
    }
    free(Histgram);
    free(Filter);
    free(DarkChannel);
    free(FilterClone);
}

 

 图片 24  图片 25  图片 26