灰度图像抖动简介

来源:互联网 发布:足球运动员学历 知乎 编辑:程序博客网 时间:2024/05/17 02:15

灰度图像抖动简介

  • 图像抖动背景
  • 图像抖动算法简介
    • 抖动原理
    • 抖动算法
    • 实验中遇到的问题

图像抖动的背景

图像在计算机中是用像素点来表示的,越高的像素表明图像越接近于现实的图片,在打印的时候如何将一个图片打印出来呢?以经典的针式打印机为例,将色带商店的墨粉打到图片上通过黑白记录图片信息,最后达到打印图片的效果。假如图像中的某一点的像素值为50,那么简单的黑白点怎么来表示这一灰度级?在打印的时候,打印的某一像素中有很多黑白点,如果有256针孔敲击的点,那么如果全是黑色的点,则代表灰度值位0,仅有一个黑点,表示灰度值位1,以此类推,没有黑点则表示灰度值为256,以此用来表示灰度图像。假如一个图像灰度级很高,但是空间有限,根本不可能完整的表达图像的信息,在这种状况之下引入了图像抖动技术。
除了灰度图像的表示和打印等问题促进图像抖动技术的出现之外,彩色图像的表示也需要使用到图像抖动技术,因为在计算机中我们广泛的使用的是红,绿,蓝各8位的24位真彩色图像,但是要将这样的图像在色彩空间有限的计算机屏幕上显示出来时就涉及到半色调技术,半色调技术广泛的应用于报刊出版等领域,它通过色点大小或者密度的变化造成总体强度的变化,从而表现出较多的对比度,也就达到了用较少的色彩模拟表达较多的色调的目的。

图像抖动方法简介

抖动原理

使用抖动法不需要扩大图像的面积,就能很好的表现出图像灰度的变化,抖动法将一个矩阵依次应用于图像(如4*4的Bayer矩阵),它产生16级灰度,一个矩阵元素对应于一个输出象素,也对应于一个输入象素,原图象和目的图象分辨率相同。如果原图象素强度大于与之相联系的高频矩阵元素,则与该原图象象素相对应的输出象素被打开,否则被关闭,由于抖动矩阵的值并不恒定,而是在高频“抖动”,因此对于同一个象素值,由于他所对应的高频矩阵元素的不同,它被抖动的结果也在高频抖动,使人眼视觉在宏观上得到正确的亮度感。

抖动算法

1、误差扩散算法原理
误差扩散算法是一种比较流行的关于图像抖动处理的方法,下图1是一个误差扩散算法的流程图:
这里写图片描述

图1中的 p(i, j)表示连续色调的输入像素值, g(i, j)是误差扩散法处理后的二值输出 。d(i, j)是输入点的像素值与其他点扩散给该点的误差之和。误差扩散法包含两个主要的部分:阈值函数和误差滤波器。阈值函数决定当前处理像素的最后输出是1(白)还是0(黑), 这个过程可用式(1)表示。如果d(i, j)≥ Q(i, j) 则g(i, j)= 1,否则为0, 其他(1)阈值 Q(i, j)可以是动态的阈值函数, 也可以是常量的阈值, 我做的实验中使用的是静态的常量阈值,当然最好是使用动态的阈值,可以提高生成的半色调图像的质量。 误差扩散法的另外一个部分是误差滤波器 h, 它的功能是将误差 e(i, j)扩散给像素(i, j)邻域中其他未被处理的像素, e(i, j)在我所做的实验中在像素值大于127的时候是R G B值减去127减去对应的RGB值,但是当值小于127的时候就是数据本身。当 e(i, j)计算完之后, 误差滤波器h就将误差乘以预设的权重分配给邻域中未被处理的其他像素点。很多研究误差扩散法的文献都是研究如何设计误差滤波器h(即如何分配权重), 使得算法得出的二值图像在视觉质量上最好。 常见的误差滤波器有如下几种 : Floyd-Steinberg滤波器、Stucki滤波器、Jarvis滤波器、Sierra滤波器等(更多)。 但是无论使用哪种滤波器, 都要满足以下这些条件:
h(k, l)≥ 0
∑k, l h(k, l)=1 【(5)式】
式(5)表示滤波器的权重都是非负的, 而且所有的权重之和为 1。 本文中将使用 Floyd-Steinberg滤波器, 误差分散方法如下所示:
0 p 7
3 5 1
X周围的数字实际代表了X周围各像素分配到X处的点与阀值得差的比例,各个数字的和为16,则误差的7/16加到直接位于X的右边的象点上,误差的3/16加到X左边下一行的象点上,5/16加到X的下方象点,1/16加到X右下象点,抖动时此过程依次重复应用于所有象点。
2、误差扩散算法主要实现
在大二的时候实训学习过使用bitmap处理图像,因此这次的作业就是用了bitmap回顾 一下以前的知识,本次实验使用的是Java程序:
首先程序分成了三个子块来实现:
这里写图片描述
A、ImageIOI.java负责将图像从本地读取进来,并且将图像转化为所需要的24位位图的 形式;
B、Image_Process.java负责图像的抖动处理,并且将处理后的图片保存到本地;
C、ImageRuner.java则负责实现整个项目的调动。
下面来看看具体的实现细节:
(1)ImageIOI.java直接沿用了实训的程序,就没什么需要讲的了;
(2)先来看看数据结构:
这里写图片描述
使用了一个数组pixels[]来记录所有点的像素值,使用piexlrgb[]来记录所有的像素点的 RGB值。
(3)Image_Process.java在处理程序的时候首先需要将自己下载下来的图像转换为灰度 图,因为不确定网上下载的图像是不是灰度图:
这里写图片描述
这里解释一下将像素的R G B分离出来的目的,因为我在实现抖动误差扩散的时候是将 R G B分开来的,所以在将图像转化成灰度图之后还需要提取一下R G B。
(3)计算对应误差
这里写图片描述
由于三个颜色R G B是分开来得,所以这里需要三个针对不同颜色的误差,首先计算出 像素点的灰度值gray,将灰度值与阈值(127)作比较,如果阈值小于127,那么误差 就是R G B值本身,如果阈值大于127的话,那么误差就是本身的值减去255。在计算 好误差之后就需要将误差扩散到周围的四个点上了。
0 p 7
3 5 1
按照上面显示的这样,将误差的7/16扩散直接位于X的右边的象点上,误差的3/16扩 散到X左边下一行的象点上,5/16扩散到X的下方象点,1/16扩散到X右下象点,此 过程依次重复应用于所有象点。
这里写图片描述
上图是对扩散到右边的点的实现程序。
再看一个扩散到左下方的:
这里写图片描述
其余的方向上的扩散是类似的操作。
到此使用Floyd-Steinberg滤波器来实现图像抖动的算法的所有内容就介绍完了。

3、实验中遇到的问题

(1)刚开始的时候没有对图像的像素进行灰度转换,直接使用的getRGB()函数获取得到的像素值如下图1所示;所以处理之后的结果如下图2,真的丑到不能看:
这里写图片描述
图1
这里写图片描述
图2
(2)图像处理完成之后先试试结果如下左图所示,正确的如下右图所示:
这里写图片描述 这里写图片描述

可以看出来是图像的方向有些问题,只要是在实现的时候对图像的处理是这样写的:

不能这样写,因为在位图处理的时候图像的访问时从做左到右,从上到下,而我这样的实现方式就是从上到下,从左到右,方向不对应,所以最终图像的显示结果就会有一些问题。
这次实验从开始查阅资料到实现一共用了一天的时间,由于对位图和滤波器的理解不够,刚开始的时候走了很多弯路。详细代码请见Github
(https://github.com/mingyf2788/Image_Processing)

参考:
http://www.tannerhelland.com/4660/dithering-eleven-algorithms-source-code/
https://www.codeproject.com/articles/1001088/dithering-an-image-using-the-floyd-steinbe rg-algor
https://www.cyotek.com/blog/an-introduction-to-dithering-images
http://www.ctonote.com/java/10132/
(1)吴小天 1 , 孙 伟—— 基于误差扩散的图像分存方案 1.中山大学 信息 科学与技术学院, 广州 510006; 2.中山大学 软件学院, 广州 510006
(2)于晓庆——浅谈几种常用的数字半色调算法