王真明
摘要:目前,數(shù)字圖像處理民已廣泛應(yīng)用于工業(yè)、醫(yī)療保健、航空航天、軍事等領(lǐng)域。隨著信息高速公路、數(shù)字地球概念的提出以及Intemet的飛速發(fā)展,數(shù)字圖像處理由于具有信息量大、傳輸速度快、作用距離遠(yuǎn)等一系列優(yōu)點(diǎn),必將成為人類獲取信息的重要來源和利用信息的重要手段。該文介紹了數(shù)字圖像的基本知識,數(shù)字圖像的幾何運(yùn)算系統(tǒng)的開發(fā)原理,主要實(shí)現(xiàn)功能、子模塊設(shè)計(jì)及實(shí)現(xiàn)技術(shù)。其中,重點(diǎn)介紹了通過對像素的幾何運(yùn)算實(shí)現(xiàn)圖像的各種幾何變換的原理和算法實(shí)現(xiàn)。
關(guān)鍵詞:數(shù)字圖像;像素;幾何運(yùn)算
中圖分類號:TP391 文獻(xiàn)標(biāo)識碼:A
文章編號:1009-3044(2020)03-0209-04
數(shù)字圖像處理技術(shù)與理論是計(jì)算機(jī)應(yīng)用的一個(gè)重要領(lǐng)域,數(shù)字圖像的幾何運(yùn)算是數(shù)字圖像處理的一個(gè)重要組成部分。人類感知圖像是通過視覺系統(tǒng)接收物體透射光或反射光在大腦中形成的印象或認(rèn)識。人類獲取外界信息約80%左右是來自視覺所接收的圖像信息。圖像的幾何運(yùn)算就是對其進(jìn)行平移、縮放、鏡像、旋轉(zhuǎn)、轉(zhuǎn)置等處理,用于滿足實(shí)際需要。用計(jì)算機(jī)對圖像進(jìn)行各種處理我們稱之為數(shù)字圖像處理。本文就是討論如何利用微軟的Visual C++開發(fā)工具來實(shí)現(xiàn)一些常用的數(shù)字圖像處理算法——數(shù)字圖像的幾何運(yùn)算。
圖像分為黑白圖像和彩色圖像,其中黑白圖像又包括單色圖像和灰度圖像,灰度圖像是用0表示黑,255表示白,中間值表示灰色,用該字節(jié)的數(shù)值表示對應(yīng)像素的灰度值或亮度值。彩色圖像一般使用RGB模式,其中R表示紅色,G表示綠色,B表示藍(lán)色,統(tǒng)稱為“三基色”,用這三種色彩的不同搭配,就可以形成各種不同的色彩。形成的圖像文件一般用BMP、JPEG、GIF等格式表示。
本系統(tǒng)的開發(fā)以圖像像素的幾何運(yùn)算為原理,綜合了各學(xué)科(如數(shù)學(xué)、物理學(xué)、計(jì)算機(jī)學(xué)、系統(tǒng)工程等)較先進(jìn)的成果形成的計(jì)算機(jī)圖像處理主要防采用兩大類方法:一類是在圖像空間中對圖像進(jìn)行各種處理;另一類方法是把圖像進(jìn)行變換,經(jīng)過傅立葉變換或小波變換,變換到頻率域,在頻率域中進(jìn)行各種處理,然后再變換回圖像的空間域,形成處理后的圖像。
圖像的幾何運(yùn)算也稱為空間變換,是建立一幅圖像與其變換后的圖像中所有各點(diǎn)之間映射關(guān)系的函數(shù)。這些函數(shù)能唯一確定輸入圖像和輸出圖像中所有像素點(diǎn)之間的幾何對應(yīng)關(guān)系。即:[x,y]-[X(u,v),Y(u,v)] 或[u,v]-[U(x,y),V(x,y)]
其中,[u,v]表示輸入圖像的像素坐標(biāo),[x,y]表示輸出圖像的像素坐標(biāo)。X、Y、U、V表示空間幾何變換的映射函數(shù),該函數(shù)唯一定義了輸入和輸出圖像中所有點(diǎn)之間的幾何對應(yīng)關(guān)系。X、Y將輸入映射到輸出,稱為前向映射(Forward Mapping);U、V將輸出映射到輸入,稱為逆向映射(Inverse Mapping)。圖像的幾何運(yùn)算應(yīng)用得非常普遍,已廣泛應(yīng)用于醫(yī)學(xué)成像、遙感圖像處理、計(jì)算機(jī)視覺以及電視、電影、多媒體廣告等影像處理中。本文介紹一些常用的圖像變換技術(shù),包括圖像的平移、鏡像、轉(zhuǎn)置、旋轉(zhuǎn)、縮放等。
1)判斷并打開一幅256色BMP位圖顯示出來;
2)圖像平移:通過所給X、Y方向平移參數(shù)進(jìn)行相應(yīng)位移量的平行移動;
3)圖像縮放:通過所給X、Y方向的縮放參數(shù)進(jìn)行相應(yīng)倍數(shù)的縮小或放大;
4)圖像旋轉(zhuǎn):通過所給旋轉(zhuǎn)度數(shù)進(jìn)行順時(shí)針方向的旋轉(zhuǎn);
5)圖像鏡像:實(shí)現(xiàn)對數(shù)字圖像的垂直鏡像或水平鏡像;
6)圖像轉(zhuǎn)置:通過把圖像的x坐標(biāo)與y坐標(biāo)互換實(shí)現(xiàn)圖像的轉(zhuǎn)置。
利用數(shù)學(xué)公式對圖像像素進(jìn)行幾何運(yùn)算和VC++的數(shù)字圖像處理技術(shù)為理論基礎(chǔ),完成對圖像進(jìn)行平移、鏡像、縮放、旋轉(zhuǎn)、轉(zhuǎn)置等幾何變換的算法實(shí)現(xiàn),并實(shí)際設(shè)計(jì)實(shí)現(xiàn)上述功能。
1 打開位圖模塊
因灰度圖像每個(gè)像素位數(shù)正好是8位(1個(gè)字節(jié)),因此在進(jìn)行圖像處理時(shí)不用考慮拼湊字節(jié)的問題。而且由于灰度圖調(diào)色板的特殊性,進(jìn)行灰度圖像處理時(shí)不必考慮調(diào)色板的問題。這樣在介紹圖像處理時(shí),一般采用灰度圖,為的是將重點(diǎn)放在算法本身。
系統(tǒng)調(diào)用Ondraw0函數(shù),用GetDocument0獲取文檔,然后調(diào)用GetHDIBO獲取DIB,該函數(shù)主要用來繪制DIB對象。其中調(diào)用了StretchDIBits0或者SetDIBitsToDevice0來繪制DIB對象。輸出的設(shè)備由參數(shù)hDC指定;繪制的矩形區(qū)域由參數(shù)lpDCRect指定;輸出DIB的區(qū)域由參數(shù)lpDIBRect指定。再調(diào)用Paint-DIBO函數(shù),在PaintDIBO中先鎖定DIB找到DIB圖像象素起始位置,獲取DIB調(diào)色板,并選中它,設(shè)置好顯示模式,最后判斷是原始大小,不用拉伸調(diào)用StretchDIBits0若不是原始大小,則調(diào)用SetDIBitsToDevice0來繪制DIB對象。
2 圖像平移
2.1 基本原理
所有的點(diǎn)都按照指定的平移量水平、垂直移動。如圖所示,設(shè)(x0,y0)為原圖像上的一點(diǎn),圖像水平平移量為x,垂直平移量為v,則平移后點(diǎn)(x0,y0)坐標(biāo)將變?yōu)椋▁l,yl)。
平移后圖像的每一個(gè)點(diǎn)都可以在原圖像中找到相對應(yīng)的點(diǎn)。例如,對于新圖中的(0,0)像素,代人上面的方程組,可以求出對應(yīng)原圖中的像素(-x,-y)。如果x大于0,則點(diǎn)(-x,-y)不在原圖中。對于不在原圖中的點(diǎn),可以直接將它的像素值統(tǒng)一設(shè)置為255。同樣,若有點(diǎn)不在原圖中,也就說明原圖中有點(diǎn)被移出顯示區(qū)域。如果不想丟失被移出的部分圖像,可以將新生成的圖像寬度擴(kuò)大lxl.高度擴(kuò)大lyl。
2.2 平移模塊實(shí)現(xiàn)
首先取得原圖的數(shù)據(jù)區(qū)指針.通過對話框輸入偏移量x,y,開辟一個(gè)同樣大小的緩沖區(qū),再對原圖依次循環(huán)每個(gè)像素,每讀入一個(gè)像素點(diǎn)(x0,y0),根據(jù)它的坐標(biāo)(x0,y0)找到目標(biāo)圖像的位置(xl=xO+x,yl=yO+y),將像素(x0,y0)處的顏色值賦給新圖中的(xl,yl)。
for(i=0;i
{
for(j=0;j
{
//指向新DIB第i行,第j個(gè)象素的指針
//由于DIB中圖像第一行其實(shí)保存在最后一行的位置,因此lpDst
//值不是(char *)lpNewDIBBits+ lLineBytes{i+j,而是
//(char *)lpNewDIBBits+ lLineBytes*(lHeight -1 -i)+j
lpDst= (char *)lpNewDIBBits+ ILineBytes半(IHeight -1 -i)+j;
//計(jì)算該象素在源DIB中的坐標(biāo)
i0=i- lYOffset;
j0=j- lXOffset;
//判斷是否在源圖范圍內(nèi)
if(00>=0)&&(j0< IWidth)&&(i0>=0)&&(i0< IHeight》
{
//指向源DIB第i0行,第j0個(gè)象素的指針
//同樣要注意DIB上下倒置的問題
lpSrc=(char *)lpDIBBits+lLineBytes*(lHeight -1- i0)+j0;
*lpDst= *lpSrc; //復(fù)制象素
)
elsef
*《unsigned char*)lpDst)= 255; 11源圖中沒有的象素,直接賦值255
)))
3 圖像縮放模塊
3.1 基本原理
圖像x軸方向縮放比率nx,y軸方向縮放比率是ny,那么原圖中點(diǎn)(x0,y0)對應(yīng)與新圖中的點(diǎn)(xl,v1)的轉(zhuǎn)換矩陣為:
例如當(dāng)nx=ny=0.5時(shí),圖像被縮到原圖一半大小,此時(shí)縮小后圖像中的(0,0)像素對應(yīng)于原圖中的(0,0)像素;(0,1)像素對應(yīng)于原圖中的(0,2)像素,(1,0)像素對應(yīng)于原圖中的(2,o)像素,以此類推。在原圖基礎(chǔ)上,每行隔一個(gè)像素取一點(diǎn),每隔一行進(jìn)行操作。同理,當(dāng)nx=ny=2時(shí),圖像就會放大2倍,放大后圖像中的(0,0)對應(yīng)于原圖中的(0,0);(0,1)對應(yīng)于原圖中的(0,0.5),該像素不存在,可以近似為(0,0)也可以近似為(0,1);(0,2)對應(yīng)于原圖中的(0,1);(1,0)對應(yīng)于原圖中的(0.5,0)-(0,0)或(1,0);(2,0)對應(yīng)于原圖中的(1,0)。其實(shí)就是將原圖每行中的像素重復(fù)取值一遍,然后每行重復(fù)一次。
如圖3、圖4分別是放大前和放大后的圖像。
3.2 縮放模塊實(shí)現(xiàn)
先取得原圖的數(shù)據(jù)區(qū)指針,通過對話框獲得放大整數(shù)比例:nx,ny,更改圖像的寬度和高度,每個(gè)像素依次循環(huán)。計(jì)算該像素在原圖中的坐標(biāo),將原圖的像素值賦給目標(biāo)像素相應(yīng)位置nxXny個(gè)值。
for(i=0;i
{
//針對圖像每列進(jìn)行操作
for(j=0;j
{
,/指向新DIB第i行,第j個(gè)象素的指針
//此處寬度和高度是新DIB的寬度和高度
lpDst=(char *)lpNewDIBBits+lNewLineBytes* (lNe-wHeight -1 -i)+j;
//計(jì)算該象素在源DIB中的坐標(biāo)
i0= (LONG)(i/fYZoomRatio+ 0.5);
j0= (LONG)(j /fXZoomRatio+ 0.5)
//判斷是否在源圖范圍內(nèi)
if( (j0>=o)&&(j0< IWidth)&&(i0>=0)&&(i0< lHeight》
{
//指向源DIB第i0行,第j0個(gè)象素的指針
lpSrc=(char *)lpDIBBits+lLineBytes木(lHeight -1-i0)+j0;
*lpDst= *lpSrc; //復(fù)制象素
1else
{
*《unsigned char*)lpDst)= 255; 11對源圖中沒有的象素,直接賦值255
)))
4 圖像鏡像模塊
4.1 基本原理
設(shè)圖像高度為IHeight,寬度為IWidth,原圖中(x0,y0)經(jīng)過水平鏡像后坐標(biāo)將變?yōu)椋╨Width-x0,y0),其矩陣表達(dá)式為:
4.2 鏡像模塊實(shí)現(xiàn)
首先取得原圖的數(shù)據(jù)區(qū)指針,開辟一個(gè)同樣大小的緩沖區(qū),每個(gè)像素依次循環(huán)。在水平鏡像中,將原圖中的像素點(diǎn)的水平坐標(biāo)變成鏡像后的坐標(biāo)(用圖像的寬度減去坐標(biāo)值)再顯示到圖像上。垂直鏡像中,則對垂直坐標(biāo)做相應(yīng)的處理。
按照上面的變換公式,實(shí)現(xiàn)水平和垂直鏡像的算法,bdi-rection真時(shí)表示水平鏡像,否則為垂直鏡像:
//判斷鏡像方式
if (bDirection)
{
//水平鏡像
//針對圖像每行進(jìn)行操作
for(i=0;i
{
//針對每行圖像左半部分進(jìn)行操作
for(j=0;j
{
//指向倒數(shù)第i行,第j個(gè)象素的指針
lpSrc= (char *)lpDIBBits+ lLineBytes*i+j;
//指向倒數(shù)第i行,倒數(shù)第j個(gè)象素的指針
lpDst= (char *)lpDIBBits+ lLineBytes*(i+1)-j;
//|備份—個(gè)象素
*lpBits= *lpDst;
//將倒數(shù)第i行第j個(gè)象素復(fù)制到倒數(shù)第i行倒數(shù)第j個(gè)象素
*lpDst= *lpSrc;
//將倒數(shù)第i行倒數(shù)第j個(gè)象素復(fù)制到倒數(shù)第i行第j個(gè)象素
*lpSrc= *lpBits;
)})
else//垂直鏡像
{//針對上半圖像進(jìn)行操作
for(i=0;i
{//指向倒數(shù)第i行象素起點(diǎn)的指針
lpSrc= (char *)lpDIBBits+ ILineBytes*i;
//指向第i行象素起點(diǎn)的指針
lpDst= (char *)lpDIBBits+ lLineBytes*(lHeight -i -1);
//備份一行,寬度為lWidth
memcpy(lpBits, lpDst, lLineBytes);
//將倒數(shù)第i行象素復(fù)制到第i行
memcpy(lpDst, lpSrc, lLineBytes);
//將第i行象素復(fù)制到倒數(shù)第i行
memcpy(lpSrc, lpBits, lLineBytes);
}}
5 圖像旋轉(zhuǎn)模塊
5.1 旋轉(zhuǎn)基本原理
圖像的旋轉(zhuǎn)是以圖像的中心為原點(diǎn),旋轉(zhuǎn)一定的角度。旋轉(zhuǎn)后,圖像的大小一般會改變我們可以把轉(zhuǎn)出顯示區(qū)的圖像截去,也可以擴(kuò)大圖像范圍以顯示所有的圖像,這里我們實(shí)現(xiàn)后者。如圖5所示,點(diǎn)(x0,y0)經(jīng)過旋轉(zhuǎn)0度后坐標(biāo)變成(xl,yl)。
上述旋轉(zhuǎn)是繞坐標(biāo)軸原點(diǎn)(0,0)進(jìn)行的,如果是繞一個(gè)指定點(diǎn)(a,b)旋轉(zhuǎn),則先要將坐標(biāo)系平移到該點(diǎn),再進(jìn)行旋轉(zhuǎn),然后平移回新的坐標(biāo)原點(diǎn),在此不再詳述。
5.2 旋轉(zhuǎn)模塊實(shí)現(xiàn)
//針對圖像每行進(jìn)行操作
for(i=0;i
{
//針對圖像每列進(jìn)行操作
for(j=0;j
{//指向新DIB第i行,第j個(gè)象素的指針,此處寬度和高度是新DIB的寬度和高度
lpDst=(char *)lpNewDIBBits+lNewLineBytes* (lNe-wHeight -l -i) +j;
//計(jì)算該象素在源DIB中的坐標(biāo)
i0= (LONG) (-《float)j)4f'Sina+《float)i)4fCosa+ f2+ 0.5);
j0= (LONG)(《float)j)4 fCosa+《float)i)4 fSina +fl+ 0.5);
//判斷是否在源圖范圍內(nèi)
if((j0>=0)&&(j0< IWidth)&&(i0>=0)&&(i0< IHeight》
{
//指向源DIB第i0行,第j0個(gè)象素的指針
lpSrc=(char *)lpDIBBits+lLineBytes*(IHeight -1-i0)+j0;
//復(fù)制象素
*lpDst= *lpSrc;
1else
{
//對于源圖中沒有的象素,直接賦值為255
*《unsigned char*)lpDst)= 255;
}}}
6 圖像轉(zhuǎn)置模塊
6.1 轉(zhuǎn)置基本原理
圖像的轉(zhuǎn)置(transpose)操作是將圖像像素的x坐標(biāo)和y坐標(biāo)互換。該操作將改變圖像的高度和寬度,轉(zhuǎn)置后圖像的高度和寬度將互換。即:
x0= yl
yo= xl
6.2 轉(zhuǎn)置模塊實(shí)現(xiàn)
圖像的轉(zhuǎn)置的實(shí)現(xiàn)和圖像鏡像變換類似,不同之處在于圖像轉(zhuǎn)置后DIB的頭文件也要進(jìn)行相應(yīng)的改變,主要是將頭文件中圖像高度和寬度信息更新。因此傳遞給圖像轉(zhuǎn)置函數(shù)的參數(shù)是直接指向DIB的指針,而不是直接指向DIB像素的指針。下面給出圖像轉(zhuǎn)置函數(shù)的算法。
//針對圖像每行進(jìn)行操作
for(i=0;i
{for(j=0;j
{//指向源DIB第i行,第j個(gè)象素的指針
lpSrc= (char *)lpDIBBits+ lLineBytes*(lHeight -1 -i)+j;
//指向轉(zhuǎn)置DIB第j行,第i個(gè)象素的指針
//注意此處lWidth和lHeight是源DIB的寬度和高度,應(yīng)該互換
lpDst= (char *)lpNewDIBBits+ lNewLineBytes*(IWidth -1一j)+i;
//復(fù)制象素
*lpDst= *lpSrc;
}}
數(shù)字圖像處理技術(shù)博大精深,不但需要熟練掌握一門程序開發(fā)語言,還需要深厚的數(shù)學(xué)功底,自20世紀(jì)60年代第三代數(shù)字計(jì)算機(jī)問世以后,數(shù)字圖像處理技術(shù)出現(xiàn)了空前的發(fā)展,在諸如航空航天、生物醫(yī)學(xué)工程、通信工程、文化藝術(shù)、電子商務(wù)等等領(lǐng)域都有廣泛應(yīng)用。本文利用Visual C++這個(gè)開發(fā)平臺只是拋磚引玉,希望和廣大讀者共同交流學(xué)習(xí)。
參考文獻(xiàn):
[1]楊淑瑩,邊奠英.VC++圖像處理程序設(shè)計(jì)[M].北京:清華大學(xué)出版社,2003.
[2]歐珊瑚,王倩麗,朱哲瑜.Visual C++.NET數(shù)字圖像處理技術(shù)與應(yīng)用[M].北京:清華大學(xué)出版社,2004.
[3]陳兵旗,孫明.Visual C++實(shí)用圖像處理[M].北京:清華大學(xué)出版社,2004.
[4]鐘志光,盧君,劉偉榮.Visual C++.NET數(shù)字圖像處理實(shí)例與解析[M].北京:清華大學(xué)出版社,2003.
[5]何斌,馬天予,王運(yùn)堅(jiān),等.Visual C++數(shù)字圖像處理[M].北京:人民郵電出版社,2002.
[6]譚浩強(qiáng).Visual C++ 6.0實(shí)用教程[M].北京:電子工業(yè)出版社。2001.
[7]朱志剛,林學(xué)訚,石定機(jī),等,數(shù)字圖像處理[M].北京:電子工業(yè)出版社。2002.
[8]譚浩強(qiáng).Visual C++ 6.0實(shí)用教程[M].北京:電子工業(yè)出版社,2001.
[9]鄭阿奇.Visual C++實(shí)用教程[M].2版.北京:電子工業(yè)出版社,2003.