分享

视频处理算法——Dither

 汉无为 2020-12-25

Dither 算法来源

最早源自二战,当时的轰炸机飞行员使用了一个机械计算机来进行导航和 bomb 轨道计算。奇怪的是,这些计算机(由上百机械零件组成)在飞机甲板上要比在地面上工作地更为准确。工程师们意识到飞机的震动降低了它的一些活动部件所导致的错误。为了让它们更好的工作,工程师为这种计算机安装了震动马达,他们把这些马达的震动成为 dither 。

Dither 算法应用

音频领域

Dither是数字音乐处理上非常神奇的技巧,目的是通过用少数的 Bit 达到与较多 Bit 同样的听觉效果,方法是在最后一个 Bit (LSB)上动“手脚”。例如用 16Bit 记录听起来好似 20Bit 的信息,听到原先 16Bit 无法记录的微小信息。举例来说,现在我有个 20Bit 的采样信息,现在想将其存为 16Bit 的信息格式,最简单的转换方式就是直接把后面 4 个 Bit 去掉,但是这样就失去用 20Bit 录音/混音的意义。比较技巧性的方法是在第 17~20Bit 中加入一些噪音,这段噪音就叫做 Dither。这些噪音加入后,可能会进位而改变第16个Bit的信息,然后我们再把最后4个Bit删掉,这个过程我们称为redithering,用意是让后面4个Bit的数据线性地反映在第16个Bit上。由于人耳具有轻易将噪音与乐音分离的能力,所以虽然我们加入了噪音,实际上我们却听到了更多音乐的细节。 

视频图像领域

Floyd-Steinberg扩散抖动算法,用在图像处理中该算法利用误差扩散实现抖动,从左到右、由上至下扫描图像的像素并将其逐个标准化(或二值化),把像素标准化后产生的误差叠加到相邻像素上,不影响已经处理过的像素。这样实现的效果是,如果某些像素向下取整,则下一个像素向上取整的可能性更大,这样使得平均量化误差最小。

后台回复[Floyd-Steinberg]可领取该算法PDF资料。

基于图像处理的抖动规则

假定在2×2 像素块中每一个像素对应一个8bit 的数据,但输出设备只能使用高6位,因此如果没有抖动过程的支持,低两位将会被丢失。考虑任意的8bit 像素值A8h(1010_1000),其高6 位用16 进制数“2A”表示,如果不用抖动,像素值A9h(1010_1001)、AAh(1010_1010)、ABh(1010_1011)将显示和A8h 同样的像素值“2Ah”。而像素值ACh(1010_1100)有不同的高六位,所以ACh 比A8h 有更高的亮度。因此如果不加抖动处理,仅能精确显示A8h 和ACh。移除低两位,这些值将分别为“2Ah”或“2Bh”。

抖动处理为“丢失”的像素值A9h、AAh、ABh 提供了显示的方法,通过显示合并的2×2 的像素块的值来加以实现,该像素块内的平均强度就是“丢失”的值,如上图所示。为了给最大强度值留有余地,ABh 不作任何变换,A8h、A9h、AAh 则通过抖动算法进行修改。

低 2 位的抖动只有四种矩阵供选择,如图上图的“情况 1”至“情况4”。抖动矩阵中“0”表示对应位置的输入值不作任何改变,“1”表示对应位置的输入值将减弱到下一个可以显示的值。可将上述四种情况综合为下图 中“2bit 抖动矩阵”的抖动矩阵,其中像素位置的数字表示低 2 位:00 = blank,01 =“1”,10 =“2”,11 =“3”。

如果输入像素值低 2 位为“00”,只有与抖动矩阵中空白处对应的像素强度值不变,其余 3 个都减弱到下一个可显示的像素值;

若输入像素值低 2 位为“01”,与抖动矩阵中空白及标有“1”的位置的像素点值保持不变,其余 1 个都减弱到下一个可显示的像素值;

若输入像素值低 2 位为“10”,与抖动矩阵中空白及标有“1”的位置的像素点值保持不变,其余 2 个都减弱到下一个可显示的像素值;

若输入像素值低 2 位为“11”,四个像素点都保持输入值不变。以上过程是 2bit 抖动的算法,对于 1bit,3bit,4bit 抖动的抖动矩阵见其他,其算法与2bit 抖动算法类似。

dither 算法实现

matlab 3bit-dither程序

clear;
clc;
I = imread(‘0001.jpg’);
img = double(I);%转换图片
[h w] = size(img(:,:,1));%取得图片的大小


d = 1;%为1时,误差从左传递到右侧,为-1时,误差从右传递到左
re = 0;
ge = 0;
be = 0;
rs = 8;%2^n, n = 3 表示将红色量化等级减少到2^5 = 32种。
gs = 8;%2^n, n = 3 表示将绿色量化等级减少到2^5 = 32种。
bs = 8;%2^n, n = 3 表示将蓝色量化等级减少到2^5 = 32种。
for i=1:h
    for j=1:w
        if (d == 1)
            val = rs * fix(img(i,j,1) / rs);
            re = img(i, j, 1) - val;
            img(i, j, 1) = val;

            val = gs * fix(img(i,j,2) / gs);
            ge = img(i, j, 2) - val;
            img(i, j, 2) = val;

            val = bs * fix(img(i,j,3) / bs);
            be = img(i, j, 3) - val;
            img(i, j, 3) = val;

            if ((j + 1) <= w)%计算误差对右侧的像素的传递
                img(i, j + 11) = img(i, j + 11) + re * 3 / 8;
                img(i, j + 12) = img(i, j + 12) + ge * 3 / 8;
                img(i, j + 13) = img(i, j + 13) + be * 3 / 8;
            end
            if ((i + 1) <= h)%计算误差对下侧的像素传递
                img(i + 1, j, 1) = img(i + 1, j, 1) + re * 3 / 8;
                img(i + 1, j, 2) = img(i + 1, j, 2) + ge * 3 / 8;
                img(i + 1, j, 3) = img(i + 1, j, 3) + be * 3 / 8;
            end
            if ((i + 1) <= h && (j + 1) <= w)%计算误差对右下侧的像素传递
                img(i + 1, j + 11) = img(i + 1, j + 11) + re / 4;
                img(i + 1, j + 12) = img(i + 1, j + 12) + ge / 4;
                img(i + 1, j + 13) = img(i + 1, j + 13) + be / 4;
            end
        else
            val = rs * fix(img(i,w - j + 1,1) / rs);
            re = img(i, w - j + 11) - val;
            img(i, w - j + 11) = val;

            val = gs * fix(img(i,w - j + 1,2) / gs);
            ge = img(i, w - j + 12) - val;
            img(i, w - j + 12) = val;

            val = bs * fix(img(i,w - j + 1,3) / bs);
            be = img(i, w - j + 13) - val;
            img(i, w - j + 13) = val;

            if ((w - j) > 0)%计算误差对左侧的误差传递
                img(i, w - j, 1) = img(i, w - j, 1) + re * 3 / 8;
                img(i, w - j, 2) = img(i, w - j, 2) + ge * 3 / 8;
                img(i, w - j, 3) = img(i, w - j, 3) + be * 3 / 8;
            end
            if (i + 1 <= h)%计算误差对下侧的像素误差传递
                img(i + 1, j, 1) = img(i + 1, j, 1) + re * 3 / 8;
                img(i + 1, j, 2) = img(i + 1, j, 2) + ge * 3 / 8;
                img(i + 1, j, 3) = img(i + 1, j, 3) + be * 3 / 8;
            end
            if ((i + 1) <= h && (w - j) > 0)%计算误差对左下侧的像素误差传递
                img(i + 1, w - j, 1) = img(i + 1, w - j, 1) + re / 4;
                img(i + 1, w - j, 2) = img(i + 1, w - j, 2) + ge / 4;
                img(i + 1, w - j, 3) = img(i + 1, w - j, 3) + be / 4;
            end
        end
    end
    d = -d;
end
out = uint8(img);
imshow(out)

FPGA 2bit-dither程序实现

1. 特点

  • 支持将 RGB888 的视频格式输入,也可以把 Bayer 格式的视频输入(使用 RGB 单通道即可)

  • 2 个 clock 延迟

  • 支持 VESA /AXI-Stream 等视频时序

  • 输出像素位宽可选择(默认 6bit )

2.关键代码

计算误差:注意奇偶行dither规则不同
2'b00  : threshold[1:0] <= 2'd0;//奇数行(左侧误差)
2'b01  : threshold[1:0] <= 2'd2;//偶数行(左侧误差)
2'b10  : threshold[1:0] <= 2'd3;//奇数行(右侧误差)
2'b11  : threshold[1:0] <= 2'd1;//偶数行(右侧误差)

//用 RGB 三通道中的 R 分量举例
//输出进行dither

if(&i_R[7:2])
    i_R[5:0] <= i_R[7:2];
else if(i_R[1:0] > threshold[1:0])
    i_R[5:0] <= i_R[7:2] + 1'b1;
else
    i_R[5:0] <= i_R[7:2];  

3.仿真结果

原图:随便截取了一张图,RGB888 格式,显示结果如下图。

原图

将原图RGB888 的每个分量的最低 2bit 置为 0 ,显示结果如下图。

R={r_data[7:2],2'b00};
G={g_data[7:2],2'b00};
B={b_data[7:2],2'b00};

可以看出很多区域都存在偏色。

将原图 RGB888 输入给 dither 模块,效果如下图所示。

    Dither  Dither_inst(
    .InClk  (dither_InClk  ) ,
    .InVs   (dither_InVs   ) ,
    .InHs   (dither_InHs   ) ,
    .InDe   (dither_InDe   ) ,
    .InData (dither_InData ) ,                                                
    .OutClk (dither_OutClk ) ,
    .OutVs  (dither_OutVs  ) ,
    .OutHs  (dither_OutHs  ) ,                     
    .OutDe  (dither_OutDe  ) ,
    .OutData(dither_OutData)
  );

可以看出比直接丢掉最低2bit效果好很多,虽然还会存在一些瑕疵。

Dither处理后结果

对比结果

参考链接

  1. DITHER 抖动算法

https://blog.csdn.net/xxhi008/article/details/78077408
  1. 图像增强算法之去抖动算法

https://blog.csdn.net/lz0499/article/details/101622016?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-3.compare&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-3.compare
  1. github 参考代码

https://github.com/freecores/video_dithering

源码参考获取

获取资料方法一:集赞

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多