前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >视频处理算法——Dither

视频处理算法——Dither

作者头像
瓜大三哥
发布2020-11-26 11:09:36
4.3K0
发布2020-11-26 11:09:36
举报
文章被收录于专栏:瓜大三哥瓜大三哥

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程序

代码语言:javascript
复制
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 + 1, 1) = img(i, j + 1, 1) + re * 3 / 8;
                img(i, j + 1, 2) = img(i, j + 1, 2) + ge * 3 / 8;
                img(i, j + 1, 3) = img(i, j + 1, 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 && (j + 1) <= w)%计算误差对右下侧的像素传递
                img(i + 1, j + 1, 1) = img(i + 1, j + 1, 1) + re / 4;
                img(i + 1, j + 1, 2) = img(i + 1, j + 1, 2) + ge / 4;
                img(i + 1, j + 1, 3) = img(i + 1, j + 1, 3) + be / 4;
            end
        else
            val = rs * fix(img(i,w - j + 1,1) / rs);
            re = img(i, w - j + 1, 1) - val;
            img(i, w - j + 1, 1) = val;

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

            val = bs * fix(img(i,w - j + 1,3) / bs);
            be = img(i, w - j + 1, 3) - val;
            img(i, w - j + 1, 3) = 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.关键代码

代码语言:javascript
复制
计算误差:注意奇偶行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 ,显示结果如下图。

代码语言:javascript
复制
R={r_data[7:2],2'b00};
G={g_data[7:2],2'b00};
B={b_data[7:2],2'b00};

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

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

代码语言:javascript
复制
    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 抖动算法
代码语言:javascript
复制
https://blog.csdn.net/xxhi008/article/details/78077408
  1. 图像增强算法之去抖动算法
代码语言:javascript
复制
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 参考代码
代码语言:javascript
复制
https://github.com/freecores/video_dithering

源码参考获取

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 瓜大三哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Dither 算法来源
  • Dither 算法应用
    • 音频领域
      • 视频图像领域
      • 基于图像处理的抖动规则
      • dither 算法实现
        • matlab 3bit-dither程序
          • FPGA 2bit-dither程序实现
            • 1. 特点
            • 2.关键代码
            • 3.仿真结果
        • 参考链接
        • 源码参考获取
        相关产品与服务
        图像处理
        图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档