图像的处理(一)----灰度图像像素颜色亮度处理

以前看了一些有关图像处理的书,对我起到了很大的帮助。所以,今天我就将我学过的知识整理出来,一方面可以给人学习,另一方面也可以请各位高手指点指点。

我要说的图像处理是针对程序方面的。所以,先做一个程序来放置图形。在这里,我使用了Delphi作为工具。因为,在我使用过的众多编译器当中,Delphi对图形的支持最好。还有,这里我并不是讲语法。所以,有些代码我就不详细说明。不便之处,敬请原谅。

注意:本文章的示例程序所用的东西不超过GDI的范围。

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

在图像处理中,速度是很重要的。因此,我们得重新处理一下TBitmap,得到TVczhBitmap。这只是因为GetPixelsSetPixels的速度太慢,换一个方法而已。

unit untBitmapProc;

interface

uses Graphics, SysUtils;

type

TVczhBitmap=class(TBitmap)

private

Data:PByteArray;

Line:Integer;

procedure SetFormat;

function GetBytePointer(X,Y:Integer):PByte;

procedure SetBytes(X,Y:Integer;Value:Byte);

function GetBytes(X,Y:Integer):Byte;

protected

published

constructor Create;

public

property Bytes[X,Y:Integer]:Byte read GetBytes write SetBytes;

procedure LoadFromFile(FileName:String);

procedure ToGray;

end;

implementation

procedure TVczhBitmap.SetFormat;

begin

HandleType:=bmDIB;

PixelFormat:=pf24bit;

end;

function TVczhBitmap.GetBytePointer(X,Y:Integer):PByte;

begin

if Line<>Y then

begin

Line:=Y;

Data:=ScanLine[Y];

end;

Longint(result):=Longint(Data)+X;

end;

procedure TVczhBitmap.SetBytes(X,Y:Integer;Value:Byte);

begin

GetBytePointer(X,Y)^:=Value;

end;

function TVczhBitmap.GetBytes(X,Y:Integer):Byte;

begin

result:=GetBytePointer(X,Y)^;

end;

constructor TVczhBitmap.Create;

begin

inherited Create;

SetFormat;

Line:=-1;

end;

procedure TVczhBitmap.LoadFromFile(FileName:String);

begin

inherited LoadFromFile(FileName);

SetFormat;

Line:=-1;

end;

procedure TVczhBitmap.ToGray;

var X,Y,R:Integer;

B:Byte;

begin

for Y:=0 to Height-1 do

for X:=0 to Width-1 do

begin

R:=0;

for B:=0 to 2 do

R:=R+GetBytes(X*3+B,Y);

for B:=0 to 2 do

SetBytes(X*3+B,Y,R div 3);

end;

end;

end.

此后,我们需要建立几个窗体。第一个用来显示图片,第二个用来处理图片,其他的窗体都继承自第二个窗体,包含实际的处理方法。

先看第二个窗口:

unit untProc;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, ExtCtrls, untBitmapProc, StdCtrls, ComCtrls;

type

TfrmProcessor = class(TForm)

pbBar: TPaintBox;

gpProc: TGroupBox;

Button1: TButton;

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

procedure FormShow(Sender: TObject);

procedure pbBarPaint(Sender: TObject);

procedure Button1Click(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

BarData:array[0..255]of Byte;

Bar:TVczhBitmap;

procedure DrawBar;

end;

var

frmProcessor: TfrmProcessor;

implementation

{$R *.dfm}

uses untViewer;

procedure TfrmProcessor.DrawBar;

var I:Integer;

begin

Bar.Canvas.FillRect(Bar.Canvas.ClipRect);

Bar.Canvas.MoveTo(0,255-BarData[0]);

for I:=1 to 255 do

Bar.Canvas.LineTo(I,255-BarData[I]);

end;

procedure TfrmProcessor.FormCreate(Sender: TObject);

begin

Bar:=TVczhBitmap.Create;

Bar.Width:=256;

Bar.Height:=256;

Bar.Canvas.Brush.Color:=clWhite;

Bar.Canvas.Brush.Style:=bsSolid;

end;

procedure TfrmProcessor.FormDestroy(Sender: TObject);

begin

Bar.Free;

end;

procedure TfrmProcessor.FormShow(Sender: TObject);

var I:Integer;

begin

for I:=0 to 255 do

BarData[I]:=I;

DrawBar;

end;

procedure TfrmProcessor.pbBarPaint(Sender: TObject);

begin

pbBar.Canvas.Draw(0,0,Bar);

end;

procedure TfrmProcessor.Button1Click(Sender: TObject);

var X,Y:Integer;

begin

for Y:=0 to Buffer.Height-1 do

for X:=0 to Buffer.Width*3-1 do

Played.Bytes[X,Y]:=BarData[Buffer.Bytes[X,Y]];

frmViewer.FormPaint(frmViewer);

end;

end.

之后,做一个窗口继承自它,则调整BarData[]后,按Apply即可看到结果。

现在开始将图像处理。具体效果见示例程序。

一、颜色反转。

灰度图像的颜色都是从0~255,所以,为了使颜色反转,我们可以用255减去该颜色值以得到反转后的颜色。

var I:Integer;

begin

inherited;

for I:=0 to 255 do

BarData[I]:=255-I;//255减去该颜色值

DrawBar;

pbBarPaint(pbBar);

end;

二、缩小颜色范围以增强或减弱亮度

颜色本来是从0~255的。如果调节它的范围,例如从0~16,则会是图像明显变暗。我们可以把起始值设为a,把终止值设为b,则新的颜色值New=a+(b-1)*Old/255。这样做的话可以改变亮度,并且不会破坏原先颜色的顺序。代码如下

var I:Integer;

begin

for I:=0 to 255 do

BarData[I]:=(255-sbMin.Position)+Round((sbMin.Position-sbMax.Position)/255*I);

DrawBar;

pbBarPaint(pbBar);

Button1Click(Button1);

end;

这里的sbMin.PositionsbMaxPosition都是反转过的。所以使用时要用255去减

三、增加某个范围内的颜色范围

如果图像本身的颜色范围很小的画,你可以通过这种方法来加大图像的对比度,有利于对图像的分析。具体做法:

选取一个值a做为起始值,选取一个值b做为终止值,然后按以下公式变形:

| 0 (X<=a)

f(X)= | 255/(b-a)*(X-a)

| 255(X>=b)

var I:Integer;

begin

for I:=0 to 255 do

begin

if I<=sbMin.Position then

BarData[I]:=0

else if I>=sbMax.Position then

BarData[I]:=255

else

BarData[I]:=Round(255/(sbMax.Position-sbMin.Position)*(I-sbMin.Position));

end;

DrawBar;

pbBarPaint(pbBar);

Button1Click(Button1);

end;

四、变为黑白图片

在使用第三个功能的时候,你会发现当b<=a时,图像上的颜色除了黑色就是白色。这样操作的好处是不能直接显示出来的。这只要到了比较高级的图像处理如边缘检测等,才有作用。本例可以拿第三种方法的公式再变形,因此不作详细阐述。

五、指数级亮度调整

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><group id="_x0000_s1026" style="MARGIN-TOP: 7.8pt; Z-INDEX: 1; LEFT: 0px; MARGIN-LEFT: 18pt; WIDTH: 180pt; POSITION: absolute; HEIGHT: 156pt; TEXT-ALIGN: left" wrapcoords="-180 208 -450 935 -180 21704 20520 22119 20970 22119 21510 21808 21870 21185 540 20146 990 18485 1350 16823 1800 15162 2970 11838 4500 8515 5490 6854 7020 5192 9360 3531 14220 1869 20790 1142 20520 935 180 208 -180 208" coordsize="3600,3120" coordorigin="2340,5652"><line id="_x0000_s1027" style="POSITION: absolute; flip: y; mso-wrap-edited: f" wrapcoords="0 0 0 19938 0 20458 0 21600 0 21600 0 21600 0 21185 0 20562 0 19938 0 0 0 0" to="2340,8772" from="2340,5652"><stroke endarrow="block"></stroke></line><line id="_x0000_s1028" style="POSITION: absolute; mso-wrap-edited: f" wrapcoords="20520 0 -90 0 -90 0 20520 0 20970 0 21690 0 21690 0 21060 0 20520 0" to="5940,8772" from="2340,8772"><stroke endarrow="block"></stroke></line><shape id="_x0000_s1029" style="LEFT: 2340px; WIDTH: 3420px; POSITION: absolute; TOP: 5808px; HEIGHT: 2964px; mso-wrap-edited: f" wrapcoords="3300 0 2805 30 1770 180 1770 240 1605 299 1245 464 960 719 885 808 765 958 600 1198 375 1677 60 2635 0 2874 -15 2964 1725 2964 1725 2874 30 2874 30 2635 1725 2635 195 2395 345 1916 675 1198 1035 719 1335 479 1845 240 3450 15 3450 0 3300 0" coordsize="3420,2964" filled="f" path="m,2964c255,2041,510,1118,1080,624,1650,130,2535,65,3420,e"><path arrowok="t"></path></shape><?xml:namespace prefix = w ns = "urn:schemas-microsoft-com:office:word" /><wrap type="tight"></wrap></group>

我们假设这个图的定义域是[0,1],值域也是[0,1]。那么,定义函数f(x)=x^c,则f(x)的图像有一段如上图。我们再用鼠标操作时,可以在上面取一点P(a,b),然后使f(x)通过点P,则c=ln(b)/ln(a)。有了c之后,我们就可以对颜色进行操作了:

New=(Old/255)^c*255=exp(ln(old/255)*c)*255

var ea,eb,ec:Extended;

I:Integer;

begin

ea:=A/255;

eb:=B/255;

ec:=Ln(eb)/Ln(ea);

for I:=1 to 255 do

BarData[I]:=Round(Exp(Ln((I/255))*ec)*255);

DrawBar;

pbBarPaint(pbBar);

Button1Click(Button1);

end;

这样做可以调节图像的亮度。

先到这里,在下一篇文章中,我会向大家整理出彩色图像亮度调整的方法。

示例程序:http://vczh.cstc.net.cn/vczh/Article/A_Files/Gray256.rar 打开后按右键弹菜单

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值