在数字图像处理领域,对图像进行各种变换和增强是常见的需求。本文将介绍如何在Silverlight中通过操作图像的每个像素点来实现一些基本的图像处理功能,如调整亮度、改变对比度、应用Gamma校正以及着色等。
在深入探讨代码实现之前,读者需要对Silverlight及其相关控件有一定的了解。Silverlight是一个由微软开发的富互联网应用程序(RIA)技术,它允许开发者创建具有丰富用户界面的网络应用程序。
本应用由一个主页面组成,每个图像处理功能都有一个与之对应的滑块。当用户点击鼠标左键时,会触发相应的功能。代码是用C#语言在Visual Studio 2010 Express Edition中开发的。
要获取图像的单个像素,首先需要支持Silverlight图像控件,其源设置为相对路径(Images/2.jpg)。图像加载后,会创建一个WriteableBitmap对象,如下所示:
wbOriginal = new WriteableBitmap((UIElement)sender, null);
其中,sender是一个图像控件。WriteableBitmap对象也可以从BitmapImage对象构造,代码中就是这样做的。将图像加载到BitmapImage对象非常简单,只需将Silverlight图像控件的源属性设置为此BitmapImage对象即可。当图像控件的源发生变化时,相关的WriteableBitmap对象会自动更新为新的图像。
调整亮度就是给图像的每个像素添加一个固定数值(小于255)。首先,创建一个与WriteableBitmap对象相关的临时副本,并提取每个像素的红色、绿色和蓝色,如下所示:
int pixel = wb.Pixel[i];
int B = (int)(pixel & 0xFF); pixel >>= 8;
int G = (int)(pixel & 0xFF); pixel >>= 8;
int R = (int)(pixel & 0xFF); pixel >>= 8;
int A = (int)(pixel);
每个像素由一个32位整数表示,其中蓝色、绿色、红色分别占据像素的前三个位置。红色、绿色和蓝色每个都可以从0到255的值,即在int像素变量中的一个字节值。
亮度的量由滑块从其先前位置移动的距离决定。该值被添加到每个像素的R、G、B上,并归一化到255,如下所示:
B += (int)sliderBrightness.Value;
R += (int)sliderBrightness.Value;
G += (int)sliderBrightness.Value;
if (R > 255) R = 255;
if (G > 255) G = 255;
if (B > 255) B = 255;
if (R < 0) R = 0;
if (G < 0) G = 0;
if (B < 0) B = 0;
完成这些操作后,将这些值首先放回wb(新的WriteableBitmap对象),然后放回Silverlight图像控件。
wb.Pixels[i] = B | (G << 8) | (R << 16) | (A << 24);
wb.Invalidate();
image1.Source = wb;
获取单个像素的基本方法保持不变。幂律实际上使图像的暗区域变暗,亮区域变亮。为此,幂律首先定义了一个double数组:
double[] dPowerLawFactorArray = {0.6, 1.7, 1.8, 1.9, 2.02, 2.03, 2.05, 2.07, 2.09, 2.1};
根据幂律滑块的移动,从这个数组中选择一个值并应用到每个像素的R、G和B值,如下所示:
double dPowerlawfactor = dPowerLawFactorArray[nIndex];
R = (int)Math.Pow(R, dPowerlawfactor);
G = (int)Math.Pow(G, dPowerlawfactor);
B = (int)Math.Pow(B, dPowerlawfactor);
获取单个像素的基本方法保持不变。对比度调整涉及根据滑块的位置选择一个值,并将其应用到每个像素的R、G和B值,如下所示:
double[] contrastArray = {1, 1.2, 1.3, 1.6, 1.7, 1.9, 2.1, 2.4, 2.6, 2.9};
double CFactor = contrastArray[nIndex];
R = (int)Math.Max(0, Math.Min(255, (((R - 128) * CFactor) + 128)));
G = (int)Math.Max(0, Math.Min(255, (((G - 128) * CFactor) + 128)));
B = (int)Math.Max(0, Math.Min(255, (((B - 128) * CFactor) + 128)));
Gamma校正涉及根据滑块的位置选择一个值,并将其应用到每个像素的R、G和B值,如下所示:
double[] dGammaArray = new double[19];
// 初始化数组...
double dGamma = dGammaArray[nIndex];
double dDinvgamma = 1.0 / dGamma;
double dMax = Math.Pow(255.0, dDinvgamma) / 255.0;
R = (int)Math.Max(0, Math.Min(255, (Math.Pow(R, dDinvgamma) / dMax)));
G = (int)Math.Max(0, Math.Min(255, (Math.Pow(G, dDinvgamma) / dMax)));
B = (int)Math.Max(0, Math.Min(255, (Math.Pow(B, dDinvgamma) / dMax)));
在这个功能中,用户首先通过滑块设置要应用于所选图像的蓝色、红色、绿色的量。一旦做出选择,可以点击“着色图像”按钮。这个功能将所选颜色应用到图像上,如下所示:
R += (int)sliderRedNess.Value;
G += (int)sliderGreenNess.Value;
B += (int)sliderBlueNess.Value;
灰度图像处理就是将每个像素的R、G、B值取平均值,如下所示:
R = G = B = (R + G + B) / 3;