Qt產生灰階圖

來源:互聯網
上載者:User
 

 項目中用到大量基礎影像處理知識,其中灰階圖的產生是很重要的一環。

    先補充一些基礎知識:

----------------------------------------------------------------------------------------------------------------------------

一:灰階圖

       灰階圖就是黑白圖,整幅圖片只有不同程度的黑白兩色。灰階也可認為是亮度,簡單的說就是色彩的深淺程度 !

 

       1:如果我們用八位來儲存灰階圖。則共有256種組合。那相當於:我們把從:純黑 到 純白 之間區分成了256種灰階。從而對應256種灰階值! 而如果用一個數字來表示的話:則0-255每個數字對應一種灰階!

 

      2:灰階就是沒有色彩,它的RGB色彩分量全部相等。 比如 rgb(20,20,20)。  既然這樣:我們完全可以用rgb中的某一個分量的值 來代替這個實際的灰階值! 比如上邊這個例子:我們完全可以用20來代替這個灰階! 這是一個一一映射關係!

--------------------------------------------------------------------------------------------------------------

二:色彩表

 

 

    色彩表就是表示當前所有顏色的一張表。 而我們知道任何一種顏色都可以用rgb值來表示。如此我們完全可以設計一張表,裡邊每個元素都是一個rgb值,從而將所有的顏色都用rgb值表示出來!

--------------------------------------------------------------------------------------------------------------

三:色彩索引模式

 

 

    在一張圖片的每個像素中可以直接存放其rgb值!當然:我們也可以存放一個索引值,通過這個索引值去其對應的顏色表中去尋找對應的顏色的rgb值來進行繪製。這種像素中存放索引值而不是實際rgb值的模式在Qt中有:QImage::Format_Indexed8,亦即:用8位來存放一個索引值。

--------------------------------------------------------------------------------------------------------------

四:灰階索引圖:

 

    對於8階灰階圖而言:由於其一共有256種灰階,所以我們可以設計一個顏色表:裡邊存放256個rgb值!每個rgb值的三個分量都是相等的。這樣:這張表就可以用來表示所有的灰階!

    灰階索引圖中存放的是各個整數索引值,這些圖片資料本身是無法顯示的,因為其沒有實際的rgb值。當實際構圖時:是用該索引值在上邊建立的顏色表中進行尋找,找到對應的灰階rgb值,而後才能進行實際的繪圖等操作。

    有了上兩步基礎,問題的關鍵就在於:這個灰階索引值是如何獲得的?

 

==================================================================================================================

 

  有了上述基礎知識,下一步可以來看一下如何從彩色圖轉為灰階圖了。

一:整體流程:

   1:依據某一個演算法:將rgb32彩色映像的每個像素中的rgb值轉為一個整數灰階值。

   2:用這個計算獲得的值來替代原圖中的每個rgb。

   這樣就可以將一張彩色圖轉為灰階圖了。


   但是這個過程中存在以下問題:

   1:如何從彩色圖原本的rgb值計算出灰階值?

   2:因為每個像素的rgb都被灰階值取代,其都是一樣的,這完全可以用一個灰階值取代,而不是用三個。用三個有點浪費空間。

--------------------------------------------------------------------------------------------------------------

   對於問題1:灰階值的計算方法有以下幾種:

   

              1.浮點演算法:Gray=R*0.3+G*0.59+B*0.11 

              2.整數方法:Gray=(R*30+G*59++B*11)/100 

              3.移位方法:Gray =(R*28+G*151+B*77)>>8; 

              4.平均值法:Gray=(R+G+B)/3; 

              5.僅取綠色:Gray=G;

              

 

    而各種方法之間的區別在於:精確度! 亦即:得到的灰階圖的效果不同!浮點數運算得到的效果最好,而僅僅取綠色得到的效果最差。至於取哪一種,則取決於實際需要!

 

--------------------------------------------------------------------------------------------------------------

   對於問題2:我們可以每個像素中只存唯一一個灰階值,而後設計一個色彩表,通過這個灰階值去對應尋找其真實的顏色。那這樣就可以                 用到上邊所的灰階索引圖了。亦即:此時圖中存放的不是真實的rgb值,而是一個灰階所以值;而後設計一張其對應的顏色      表。這樣二者便可以完全代表整張灰階圖了。而且二者加起來的空間也比非索引模式要小的多,而且尋找速度會更快。

 

    所以:最好是將灰階圖用索引模式進行儲存,這在Qt中是指定QImage格式為Index8實現。亦即:有8位索引,可以指定256種灰階值。

那麼:我們從彩色圖轉為灰階索引圖的整體流程為:

 

    (以rgb32轉為index8為例)

    1:首先我們要建立一張空的index8映像。

    2:依據某一個演算法:將rgb32彩色映像的每個像素中的rgb值轉為一個整數值,儲存在index8灰階圖的每個像素中。

    3:構建顏色表。

    4:依據儲存在index映像中的整數值,去灰階表中尋找對應的灰階來進行實際的構圖!

 

==================================================================================================================

 

    OK,現在方法有了,下邊我們可以來實現了。

 

    1:最簡單的方法:


[cpp] view plaincopy

  1. for(int i =0;i<width;i++)  
  2. {  
  3.      for(int j=0;j<height;j++)  
  4.      {  
  5.       QRgb pixel=iImage->pixel(i,j);  
  6.       int r=qRed(pixel);  
  7.       int g=qGreen(pixel);  
  8.       int b=qBlue(pixel);  
  9.       iGray->setPixel(i,j,qGray(r,g,b));  
  10.      }  
  11. }  

 

 

 

  亦即:先用 pixel()擷取每個像素點的QRgb值。而後分別用qRed(),qGreen(),qBlue()來擷取rgb分量的值。而後進行上述灰階值的計算。之後再重新賦予給該像素點。

 

    但是實際運行一下你會發現:對於600*800大小的映像:這個函數要運行30s+,這顯然是不能容忍的。

 

--------------------------------------------------------------------------------------------------------------

    

    上邊這個方法很簡單直接,但是效率上太失敗,所以我們需要來最佳化效率,主要從以下兩個方面實現:

 

 

    1:要用pixel() ,qRed(),qGreen(),qBlue()來遍曆擷取每個像素的rgb分量。其函數實現時:肯定是一個尋找過程,尤其是依據像素位置來獲得rgb值的函數pixel()。每次都一個完整的尋找,這顯然效率較為低下,尤其是不斷的大量尋找! 由於資料都是連續存放在記憶體中的,我們完全可以通過移動指標的方式來擷取rgb分量。每次只移動一個指標位置就可以了。這種移動指標的方式顯然比全尋找要快!

 

 

 

    這塊代碼實現上:其是直接來取用green綠色分量值 來作為gray索引值!

    其比上一個方法的最佳化之處在於:它沒有使用系統函數,而是使用移動指標的方式來取得rgb分量。它把所有灰階索引值存放到index8灰階圖中。最後建立了8階灰階圖的顏色表並賦予給該灰階圖。這樣:系統會自動(不需要我們手動去尋找)依據儲存在映像中的灰階索引值去 顏色表中尋找對應灰階的rgb值來進行繪製!

 

--------------------------------------------------------------------------------------------------------------

 

 

    2:計算灰階索引值的函數qGray(),按照Qt文檔上所說:其計算過程為:(r*11+g*16+5*5)/32 .乘除法是一個很大的計算量,最好用移位操作來進行取代!

 

   (這就牽扯一個問題:原本我以為:乘除法在寄存器中就算轉為移位操作的,所以乘除法和移位操作在效率上應該沒什麼區別。但是實際不是這樣的,因為:如果你使用乘除法,則其在運行時:轉化成的乘法指令本身會消耗很多cpu周期,所以這無形中已經降低了效率!所以來說:在做高效能運算時:最好用移位操作來取代乘除法)

 

============================================================================================

    知道如何最佳化後,我們看下在Qt中如何?,這個在網上我找到了一個方法,摘錄如下

 

[cpp] view plaincopy

  1. QImage colourImg("colourImage.bmp");      
  2. QSize colourImgSize = colourImg.size();   
  3. int width = colourImgSize.rwidth();   
  4. int height = colourImgSize.rheight();     
  5. unsigned char *colourImgDataPtr = colourImg.bits();   
  6. QImage grayImg(colourImgSize, QImage::Format_Indexed8);  
  7. unsigned char *grayImgDataPtr = grayImg.bits();  
  8.   
  9. //下邊這個for迴圈是直接取用green綠色分量值 來作為gray索引值  
  10. for(int i = 0; i < height; i++)    
  11. {         
  12.    for(int j = 0; j < width; j++)          
  13.    {              
  14.         *grayImgDataPtr = *(colourImgDataPtr + 1);      colourImgDataPtr += 4;          grayImgDataPtr++;         
  15.    }      
  16. }  
  17.   
  18. QVector<QRgb> grayColourTable;      
  19. unsigned int rgb = 0;     
  20. for(int i = 0; i < 256; i++)   
  21. {         
  22.    grayColourTable.append(rgb);        
  23.    rgb += 0x00010101;     
  24. }     
  25.   
  26. grayImg.setColourTable(rayColourTable);   
  27. graImg.save("grayImage.bmp", "bmp");  

 

 

    

 

 

 

 

    這塊代碼實現上:其是直接來取用green綠色分量值 來作為gray索引值!

    其比上一個方法的最佳化之處在於:它沒有使用系統函數,而是使用移動指標的方式來取得rgb分量。它把所有灰階索引值存放到index8灰階圖中。最後建立了8階灰階圖的顏色表並賦予給該灰階圖。這樣:系統會自動(不需要我們手動去尋找)依據儲存在映像中的灰階索引值去 顏色表中尋找對應灰階的rgb值來進行繪製!

 

--------------------------------------------------------------------------------------------------------------

   在上述方法的基礎上,我們在使用時:需要注意的是效果能不能達到需求,從而可能要用精確度更高的灰階索引值計算方法。那這就牽扯大量運算,此時記得要用移位操作 來取代 乘除法運算

 

[cpp] view plaincopy

  1. QBYTE RGBtoGRAY(QBYTE r, QBYTE g, QBYTE b)  
  2. {  
  3.     return (QBYTE)((((QUINT32)((r << 5) + (r << 2) + (r << 1)))+ (QUINT32)((g << 6) + (g << 3) + (g << 1) + g)  
  4. + (QUINT32)((b << 4) - b)) >> 7);  
  5. }  

 

 

 

 這個是網上找到的最佳化的Realtime Compute灰階索引值演算法。沒有用到乘除法運算,轉而使用大量移位操作。

--------------------------------------------------------------------------------------------------------------

 

  暫且總結到這裡,上述代碼都實際測試過,沒有問題。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.