赞
踩
一幅灰度图像的视觉效果取决于该图像中各个像素的灰度,灰度映射通过改变图像中所有或部分图像的灰度来达到改善图像视觉效果的目的!
“灰度”,顾名思义,即灰色的度数,或者灰色的等级。
在计算机领域中,灰度数字图像是每个像素只有一个采样颜色的图像,也就是单通道图像。这类图像通常显示为从最暗黑色到最亮 的白色的灰度。
一般,像素值量化后用一个字节(8位)来表示,如果把黑-灰-白连续变化的灰度值量化为 256 个灰度级,灰度值的范围为 0~255,表示亮度从深到浅,对应图像中的颜色从黑到白。
灰度映射是一种基于图像像素的点操作,通过对原始图像中每个像素点赋予一个新的灰度值来增强图像。实际应用中,会根据增强的目的,设计某种“映射规则”,并使用“映射函数”来表示,对原始图像中的每个像素都用这个映射函数将原始灰度值转换为新的灰度值。
这种“映射函数”,也称为“变换函数”。
由于具体图像增强的要求和目的不同,就需要设计出不同的映射函数,以下是几种典型的映射函数:
其中,原始灰度值为 s,取值范围为 0 ~ S;目标灰度值为 t,取值范围也为 0 ~ T; 灰度值的取值范围,可以根据实际需求调整。
图像求反,即将原图灰度值翻转,使黑变白,使白变黑。求反的映射函数,一般类似下图:
具体映射时,对图像中的每个像素,将其灰度值 s 根据映射函数映射为 t。假设,s 取值范围为 0 ~ 255, t 取值范围也为 0 ~ 255,那么映射函数:
t
=
255
−
s
t = 255 - s
t=255−s
代码:
@Before public void init() { Loader.load(org.bytedeco.opencv.opencv_java.class); } @Test public void test() { Mat img = Imgcodecs.imread("images/7.jpg", IMREAD_GRAYSCALE); Mat dst = new Mat(img.size(), img.type()); for (int i = 0; i < img.rows(); i++) { for (int j = 0; j < img.cols(); j++) { dst.put(i, j, 255 - img.get(i, j)[0]); // 单通道,只取第一个元素 } } HighGui.imshow("test", dst); HighGui.waitKey(); }
这里的映射时一对一的映射,每一种灰度都映射为另一种灰度。
下图所示的映射函数可以用来对图像灰度进行动态范围压缩,其目标与增强对比度相反。
实际应用中,有时原图的灰度范围太大,超出了某些设备的允许范围,这时如直接使用原图,因为原图的一些灰度级显示不出来,会导致该部分灰度细节丢失。
解决办法就是原图进行灰度压缩,常用的压缩方法是借助对数形式的映射函数。
t
=
C
l
o
g
(
1
+
∣
s
∣
)
t = Clog(1+|s|)
t=Clog(1+∣s∣)
其中,
C
C
C 为尺度比例常数,通过该函数,将原来动态范围很大的 s 转换为动态范围比较小的 t。
代码:
@Test public void test() { Mat img = Imgcodecs.imread("images/7.jpg", IMREAD_GRAYSCALE); Mat dst = new Mat(img.size(), img.type()); for (int i = 0; i < img.rows(); i++) { for (int j = 0; j < img.cols(); j++) { // dst.put(i, j, 10*Math.log(1 + img.get(i, j)[0])); // 压缩图 1 // dst.put(i, j, 10*Math.log(1 + img.get(i, j)[0]) + 100); // 压缩图 2 dst.put(i, j, 40*Math.log(1 + img.get(i, j)[0])); // 压缩图 3 } } HighGui.imshow("test", dst); HighGui.waitKey(); }
按上例中的代码,对原始图像进行压缩,通过常数 C 来控制压缩后的像素值区间,区间越大,图像对比度也越大。
阶梯量化,将图像灰度分阶段量化成较少的级数,这可以在保持原图动态范围的基础上,减少灰度级数,即减少表示灰度所需的比特数,从而获得数据量压缩的效果。
示例代码:
@Test public void test() { Mat img = new Mat(new Size(256,256), CV_8U); // 1 创建灰度连续变化的图像; for (int i = 0; i < img.rows(); i++) { for (int j = 0; j < img.cols(); j++) { img.put(i, j, (i+j)/2.0); } } Mat dst = new Mat(img.size(), img.type()); // 2. 对图像进行阶梯量化 for (int i = 0; i < img.rows(); i++) { for (int j = 0; j < img.cols(); j++) { dst.put(i, j, 20*Math.round(img.get(i,j)[0]/20)); // 量化为 12 个值 (256/20 = 12) } } HighGui.imshow("test1", img); HighGui.imshow("test2", dst); HighGui.waitKey(); }
从上图可以看到阶梯量化后的效果。
当然,实现级数量化的方式有很多种,比如,下面的例子,将图像级数量化为二值,0 和 255,也就是黑白图:
@Test
public void test() {
Mat img = Imgcodecs.imread("images/7.jpg", IMREAD_GRAYSCALE);
Mat dst = new Mat(img.size(), img.type());
for (int i = 0; i < img.rows(); i++) {
for (int j = 0; j < img.cols(); j++) {
dst.put(i, j, img.get(i, j)[0]>100?255:0 ); // 将灰度级数,量化为二值:0, 255
}
}
HighGui.imshow("img", img);
HighGui.imshow("dst", dst);
HighGui.waitKey();
}
由上例可知,尽管黑白图只使用了两级灰度,仍然能很好的表现出事物的特征。所以画素描的时候,如果总是找不准物体的明暗结构,本质上就是自己对灰度空间进行阶梯量化的能力还比较弱。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。