<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    圖像編程學習筆記2――bmp位圖平移

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    以下文字內容copy于<<數字圖像處理編程入門>>,code為自己實現,是win32控制臺程序。

    2.1 平移

    平移(translation)變換大概是幾何變換中最簡單的一種了。

    如圖2.1所示,初始坐標為(x0,y0)的點經過平移(tx,ty)(以向右,向下為正方向)后,坐標變為(x1,y1)。這兩點之間的關系是x1=x0+tx,y1=y0+ty

    RFID設備管理軟件

     

    圖2.1    平移的示意圖

    以矩陣的形式表示為

    RFID設備管理軟件(2.1)

     

           

    我們更關心的是它的逆變換:

    RFID設備管理軟件(2.2)

    這是因為:我們想知道的是平移后的圖象中每個象素的顏色。例如我們想知道,新圖中左上角點的RGB值是多少?很顯然,該點是原圖的某點經過平移后得到的,這兩點的顏色肯定是一樣的,所以只要知道了原圖那點的RGB值即可。那么到底新圖中的左上角點對應原圖中的哪一點呢?將左上角點的坐標(0,0)入公式(2.2),得到x0=-tx,y0=-ty;所以新圖中的(0,0)點的顏色和原圖中(-tx, -ty)的一樣。

    這樣就存在一個問題:如果新圖中有一點(x1,y1),按照公式(2.2)得到的(x0,y0)不在原圖中該怎么辦?通常的做法是,把該點的RGB值統一設成(0,0,0)或者(255,255,255)。

    另一個問題是:平移后的圖象是否要放大?一種做法是不放大,移出的部分被截斷。例如,圖2.2為原圖,圖2.3為移動后的圖。這種處理,文件大小不會改變。

    RFID設備管理軟件

     

    圖2.2     移動前的圖

    RFID設備管理軟件

     

    圖2.3     移動后的圖

    還有一種做法是:將圖象放大,使得能夠顯示下所有部分,如圖2.4所示。

     

    RFID設備管理軟件

    圖2.4    移動后圖象被放大

    這種處理,文件大小要改變。設原圖的寬和高分別是w1,h1則新圖的寬和高變為w1+|tx|和h1+|ty|,加絕對值符號是因為tx,ty有可能為負(即向左,向上移動)。

    下面的函數Translation采用的是第一種做法,即移出的部分被截斷。在給出源代碼之前,先說明一個問題。

    如果你用過Photoshop,CorelPhotoPaint等圖象處理軟件,可能聽說過“灰度圖”(grayscale)這個詞。灰度圖是指只含亮度信息,不含色彩信息的圖象,就象我們平時看到的黑白照片:亮度由暗到明,變化是連續的。因此,要表示灰度圖,就需要把亮度值進行量化。通常劃分成0到255共256個級別,其中0最暗(全黑),255最亮(全白)。.bmp格式的文件中,并沒有灰度圖這個概念,但是,我們可以很容易在.bmp文件中表示灰度圖。方法是用256色的調色板,只不過這個調色板有點特殊,每一項的RGB值都是相同的。也就是說RGB值從(0,0,0),(1,1,1)一直到(255,255,255)。(0,0,0)是全黑色,(255,255,255)是全白色,中間的是灰色。這樣,灰度圖就可以用256色圖來表示了。為什么會這樣呢?難道是一種巧合?其實并不是。

    在表示顏色的方法中,除了RGB外,還有一種叫YUV的表示方法,應用也很多。電視信號中用的就是一種類似于YUV的顏色表示方法。

    在這種表示方法中,Y分量的物理含義就是亮度,U和V分量代表了色差信號(你不必了解什么是色差,只要知道有這么一個概念就可以了)。使用這種表示方法有很多好處,最主要的有兩點:

    (1)    因為Y代表了亮度,所以Y分量包含了灰度圖的所有信息,只用Y分量就能完全能夠表示出一幅灰度圖來。當同時考慮U,V分量時,就能夠表示出彩色信息來。這樣,用同一種表示方法可以很方便的在灰度和彩色圖之間切換,而RGB表示方法就做不到這一點了。

    (2)    人眼對于亮度信號非常敏感,而對色差信號的敏感程度相對較弱。也就是說,圖象的主要信息包含在Y分量中。這就提示我們:如果在對YUV信號進行量化時,可以“偏心”一點,讓Y的量化級別多一些(誰讓它重要呢?)而讓UV的量化級別少一些,就可以實現圖象信息的壓縮。這一點將在第9章介紹圖象壓縮時仔細研究,這里就不深入討論了。而RGB的表示方法就做不到這一點,因為RGB三個分量同等重要,缺了誰也不行。YUV和RGB之間有著如下的對應關系

     

    RFID設備管理軟件(2.3)

    RFID設備管理軟件(2.4)

    當RGB三個分量的大小一樣時,假設都是a,代入公式(2.3),得到Y=a,U=0,V=0 。你現在該明白我前面所說不是巧合的原因了吧。

    使用灰度圖有一個好處,那就是方便。首先RGB的值都一樣;其次,圖象數據即調色板索引值,也就是實際的RGB值,也就是亮度值;另外,因為是256色調色板,所以圖象數據中一個字節代表一個象素,很整齊。如果是2色圖或16色圖,還要拼湊字節,很麻煩。如果是彩色的256色圖,由于圖象處理后有可能會產生不屬于這256種顏色的新顏色,就更麻煩了;這一點,今后你就會有深刻體會的。所以,做圖象處理時,一般采用灰度圖。為了將重點放在算法本身上,今后給出的程序如不做特殊說明,都是針對256級灰度圖的。其它顏色的情況,你可以自己想一想,把算法補全。

    如果想得到一幅灰度圖,可以使用Sea或者PhotoShop等軟件提供的顏色轉換功能將彩色圖轉換成灰度圖。

    好了,言歸正傳,下面給出Translation的源代碼。算法的思想是先將所有區域填成白色,然后找平移后顯示區域的左上角點(x0,y0)和右下角點(x1,y1) ,分幾種情況進行處理。

    先看x方向(width指圖象的寬度)

    (1)    tx≤-width:很顯然,圖象完全移出了屏幕,不用做任何處理;

    (2)    -width<tx≤0:如圖2.5所示。容易看出,圖象區域的x范圍從0到width-|tx|,對應原圖的范圍從|tx|到width;

    RFID設備管理軟件

     

    圖2.5     tx≤0,ty≤0的情況

    (3)    0< tx<width:如圖2.6所示。容易看出,圖象區域的x范圍從tx到width,對應原圖的范圍從0到width - tx

    RFID設備管理軟件

     

    圖2.6     0< tx<width,0<ty<height的情況

    (4)    tx≥width:很顯然,圖象完全移出了屏幕,不用做任何處理。

    y方向是對應的(height表示圖象的高度):

    (1)    ty≤-height,圖象完全移出了屏幕,不用做任何處理;

    (2)    -height<ty≤0,圖象區域的y范圍從0到height-|ty|,對應原圖的范圍從|ty|到height;

    (3)    0<ty<height,圖象區域的y范圍從ty到height,對應原圖的范圍從0到height-ty

    (4)    ty≥height,圖象完全移出了屏幕,不用做任何處理。

    這種做法利用了位圖存儲的連續性,即同一行的象素在內存中是相鄰的。利用memcpy函數,從(x0,y0)點開始,一次可以拷貝一整行(寬度為x1-x0),然后將內存指針移到(x0,y0+1)處,拷貝下一行。這樣拷貝(y1-y0)行就完成了全部操作,避免了一個一個象素的計算,提高了效率。

    CODE:(注:該程序需要一副bmp格式的灰度圖像,并放到工程目錄下,文件名為nv1.bmp)

     

    [cpp] view plaincopy  
      1. /** 
      2. * 程序名: Translation.cpp 
      3. * 功  能: 實現bmp格式灰度圖片的平移,移出部分用白色填充 
      4. */  
      5. #include <iostream>  
      6. #include <cstdio>  
      7. #include <fstream>  
      8. #include <cstring>  
      9. #include <windows.h>  
      10. using namespace std;  
      11. BITMAPFILEHEADER bmpFileHeader;      //位圖文件頭  
      12. BITMAPINFOHEADER bmpInfoHeader;      //位圖信息頭  
      13. RGBQUAD *pColorTable = new RGBQUAD[256];  //顏色表指針  
      14. unsigned char *pBmpData;             //圖像數據指針  
      15. unsigned char *pBmpData1;            //平移后圖像數據指針  
      16. unsigned char *pTemp,*pTemp1;        //臨時指針   
      17. int width,height,imgSize;            //圖像寬,高,實際大小,imgSize必須為4的倍數,bmp格式文件結構規定  
      18. int srcX[2],srcY[2],dstX[2],dstY[2]; //平移前后位置  
      19. /** 
      20. * 函數名: readBmp 
      21. * 參  數: bmpFileName--指向讀入bmp文件的文件名指針 
      22. * 功  能: 讀入一個bmp文件,獲得相應數據 
      23. */   
      24. bool readBmp(char *bmpFileName)  
      25. {  
      26.     FILE *fp = fopen(bmpFileName,"rb");    //以二進制讀方式打開指定的圖像文件  
      27.     if(NULL == fp)  
      28.     {  
      29.         printf("%s is not exist!",bmpFileName);  
      30.         return FALSE;  
      31.     }  
      32.     fread(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);   //讀取位圖頭信息放入bmpFileHeader,注:指針也相應移動  
      33.     fread(&bmpInfoHeader,sizeof(BITMAPINFOHEADER),1,fp);   //讀取位圖信息頭放入bmpInfoHeader  
      34.     width = bmpInfoHeader.biWidth;                          //寬  
      35.     height = bmpInfoHeader.biHeight;                        //高  
      36.     fread(pColorTable,sizeof(RGBQUAD),256,fp);              //讀取顏色表放入pColorTable  
      37.     //  int bytePerLine = (bmpInfoHeader.biWidth * bmpInfoHeader.biBitCount + 31) / 32 * 4;  
      38.     pBmpData = new unsigned char [imgSize = bmpInfoHeader.biSizeImage];   
      39.     pBmpData1 = new unsigned char [imgSize];  
      40.     memset(pBmpData1,(BYTE)255,sizeof(char)*imgSize);       //把新的圖像信息用255(白色)填充,平移后沒有圖像的區域就是白色了  
      41.     fread(pBmpData,sizeof(char),bmpInfoHeader.biSizeImage,fp);  //讀取圖像信息放入pBmpData  
      42.     fclose(fp);                //記住要關閉文件  
      43.     return TRUE;  
      44.       
      45. }  
      46. /** 
      47. * 函數名: translation 
      48. * 參  數: tx--平移的x距離,ty--平移的y距離 
      49. * 功  能: 實現平移,并把平移后圖像信息寫入pBmpData1 
      50. */   
      51. void translation(int tx,int ty)  
      52. {  
      53.     bool xVisible = TRUE,yVisible = TRUE;  
      54.     //xVisible為FALSE時,表示x方向已經移出了可顯示的范圍  
      55.     if(tx <= -width)  
      56.     {  
      57.         xVisible = FALSE;  
      58.     }  
      59.     else if(tx <= 0)  
      60.     {  
      61.         dstX[0] = 0;    //表示移動后,有圖區域的左上角點的x坐標  
      62.         dstX[1] = width + tx;   //表示移動后,有圖區域的右下角點的x坐標  
      63.     }  
      64.     else if(tx < width)  
      65.     {  
      66.         dstX[0] = tx;  
      67.         dstX[1] = width;  
      68.     }  
      69.     else  
      70.         xVisible = FALSE;  
      71.     srcX[0] = dstX[0] - tx;      //對應DstX0在原圖中的x坐標  
      72.     srcX[1] = dstX[1] - tx;     //對應DstX1在原圖中的x坐標  
      73.     int rectWidth = srcX[1] - srcX[0];  //有圖區域的寬度  
      74.     //y的和x類似,就不加注釋了  
      75.     if(ty <= -height)  
      76.         yVisible = FALSE;  
      77.     else if(ty <= 0)  
      78.     {  
      79.         dstY[0] = 0;  
      80.         dstY[1] = height + ty;  
      81.     }  
      82.     else if(ty < height)  
      83.     {  
      84.         dstY[0] = ty;  
      85.         dstY[1] = height;  
      86.     }  
      87.     else   
      88.         yVisible = FALSE;  
      89.     srcY[0] = dstY[0] - ty;  
      90.     srcY[1] = dstY[1] - ty;  
      91.     int rectHeight = srcY[1] - srcY[0];  
      92.   
      93.     int lineBytes = (width * bmpInfoHeader.biBitCount + 31) / 32 * 4;   //每行所占的字節數,必須為4的倍數  
      94.     if(xVisible && yVisible)  
      95.     {  
      96.         for(int i = 0; i < rectHeight; i++ )  
      97.         {  
      98.             //pTemp指向要拷貝的那一行的最左邊的象素對應在原圖中的位  
      99.             //置。特別要注意的是,由于.bmp是上下顛倒的,  
      100.             pTemp = pBmpData + (height - 1 - (srcY[0] + i)) * lineBytes + srcX[0];    
      101.             //pTemp1指向要拷貝的那一行的最左邊的象素對應在新圖中的位置。同樣要注意上面的問題。  
      102.             pTemp1 = pBmpData1 + (height - 1 - (dstY[0] + i)) * lineBytes + dstX[0];  
      103.             memcpy(pTemp1,pTemp,rectWidth);   //從pTemp中復制大小為rectWidth的數據到pTemp1,這里就是copy圖像的一行數據  
      104.         }  
      105.     }  
      106. }  
      107. /** 
      108. * 函數名: writeBmp 
      109. * 功  能: 新建一個bmp文件,把平移后的圖像信息寫入,生成一個新的bmp 
      110. */   
      111. void writeBmp()  
      112. {  
      113.     char writeBmpName[] = "new.bmp";  
      114.     FILE *fp = fopen(writeBmpName,"wb");   //以二進制寫方式打開指定的圖像文件  
      115.     if(NULL == fp)        
      116.     {  
      117.         cout<<"file not exist!";  
      118.         return ;  
      119.     }  
      120.     //寫入BMP文件數據  
      121.     fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);  
      122.     fwrite(&bmpInfoHeader,sizeof(BITMAPINFOHEADER),1,fp);  
      123.     fwrite(pColorTable,sizeof(RGBQUAD),256,fp);  
      124.     fwrite(pBmpData1,sizeof(char),imgSize,fp);  
      125.     fclose(fp);  
      126.     //釋放內存  
      127.     delete []pColorTable;  
      128.     delete []pBmpData1;  
      129.     delete []pBmpData;  
      130.   
      131.       
      132. }  
      133. /** 
      134. * 函數名: work 
      135. * 功  能: 處理 
      136. */   
      137. void work()  
      138. {  
      139.     int x,y;  
      140.     char readBmpName[] = "nv1.bmp";  
      141.     if ( !readBmp(readBmpName) )  
      142.         printf("Bmp file reads faliure");  
      143.     printf("the distance of translation,cx,cy:");  //讀入平移的x和y  
      144.     scanf("%d %d",&x,&y);  
      145.     translation(x,y);  
      146.     writeBmp();  
      147. }  
      148. int main()  
      149. {  
      150.     work();   
      151.     return 0;  
      152. }  
      153.                                  from:http://blog.csdn.net/sun1956/article/details/8646800
    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全