2013-08-03 35 views
1

大家向各位致以問候:)如何加快我的.bmp類?

幾天前我終於設法創建了一個功能C++類來製作.bmp圖像。儘管它是功能性的(沒有錯誤),但它在速度方面效率並不高(在我看來)。做了幾個測試,看看它多少時間走上寫圖像的不同尺寸的我結束了這些結果:

Image Dimensions Time taken(in seconds)  Comparison to the 1000x1000 image 
10x100    0.0491      x 1000 = 49.1 seconds 
100x100   0.2471      x 100 = 24.7 seconds 
100x1000   2.3276      x 10 = 23.3 seconds 
1000x1000   22.515      x 1 = 22.5 seconds 
1000x10000   224.76      \ 10 = 22.4 seconds 

例如在10x100圖像具有1000個像素(每一個與具有ARGB通道[32個比特或4個字節])加上頭部的54個字節,則需要0.05秒來寫入4054個字節(char)。

我覺得這太慢了,因爲我的電腦可以像一兩秒鐘那樣拷貝一個〜85MB的文件。我正在使用fstream來寫入磁盤,並感謝所有幫助我們加快課程速度的幫助。謝謝!!!

我的類,它被稱爲SimpleBMP的,就是這樣(我只把revelent功能):

#include <fstream> 


class SimpleBMP{ 
    struct PIXEL{ 
     unsigned char A, R, G, B; 
    }*PixelArray; 
    unsigned char *BMPHEADER, *BMPINFOHEADER; 
    std::string DATA; 
    unsigned int Size_Of_BMP, Size_Of_PixelArray; 
    int BMP_Width, BMP_Height; 

public: 

void SetPixel(int Column, int Row, unsigned char A, unsigned char R, unsigned char G, unsigned char B){ 
    PixelArray[(Row*BMP_Width)+Column].A = A; 
    PixelArray[(Row*BMP_Width)+Column].R = R; 
    PixelArray[(Row*BMP_Width)+Column].G = G; 
    PixelArray[(Row*BMP_Width)+Column].B = B; 
}; 

bool MakeImage(std::string Name){ 
    Name.append(".bmp"); 
    std::ofstream OffFile(Name, std::ios::out|std::ios::binary); 
    if(OffFile.is_open()){ 
     DATA.clear(); 
     for(int temp = 0; temp < 14; temp++){ 
      BMPHEADER[temp] = 0x00; 
     }; 
     BMPHEADER[0] = 'B'; 
     BMPHEADER[1] = 'M'; 
     BMPHEADER[2] = Size_Of_BMP; 
     BMPHEADER[3] = (Size_Of_BMP >> 8); 
     BMPHEADER[4] = (Size_Of_BMP >> 16); 
     BMPHEADER[5] = (Size_Of_BMP >> 24); 
     BMPHEADER[10] = 0x36; 



     for(int temp = 0; temp < 40; temp++){ 
      BMPINFOHEADER[temp] = 0x00; 
     }; 
     BMPINFOHEADER[0] = 0x28; 

     for(int temp = 0; temp < 4; temp++){ 
      BMPINFOHEADER[temp+4] = (BMP_Width >> (temp*8)); 
     }; 
     for(int temp = 0; temp < 4; temp++){ 
      BMPINFOHEADER[temp+8] = (BMP_Height >> (temp*8)); 
     }; 
     BMPINFOHEADER[12] = 0x01; 
     BMPINFOHEADER[14] = 0x20; 

     for(int temp = 0; temp < 4; temp++){ 
      BMPINFOHEADER[temp+20] = (Size_Of_PixelArray >> (temp*8)); 
     }; 
     BMPINFOHEADER[24] = 0x13; 
     BMPINFOHEADER[25] = 0x0b; 
     BMPINFOHEADER[28] = 0x13; 
     BMPINFOHEADER[29] = 0x0b; 



     for(int temp = 0; temp < 14; temp++){ 
      DATA.push_back(BMPHEADER[temp]); 
     }; 
     for(int temp = 0; temp < 40; temp++){ 
      DATA.push_back(BMPINFOHEADER[temp]); 
     }; 
     for(int temp = 0; temp < (Size_Of_PixelArray/4); temp++){ 
      DATA.push_back(PixelArray[temp].B); 
      DATA.push_back(PixelArray[temp].G); 
      DATA.push_back(PixelArray[temp].R); 
      DATA.push_back(PixelArray[temp].A); 
     }; 
     OffFile.write(DATA.c_str(), Size_Of_BMP); 
     OffFile.close(); 
     return true; 
    } 
    else 
     return false; 
}; 

};

+2

有一件事是調用DATA.reserve()爲數據預先分配正確的空間量。這將消除大量不必要的複製。還要確保你在發佈模式下編譯而不是調試。 –

+0

您確定時間在秒,而您只能描述寫入功能。我不認爲需要22秒才能將1000x1000 RGBA8映像複製到磁盤上。你的代碼沒有那麼糟糕,優化不必要的緩衝區副本並不能解決22秒的問題。 –

+0

這在所有情況下都不是必需的,但您應該更喜歡'++ temp'而不是'temp ++'。 – Jiwan

回答

0

當運行測試,你應該編譯項目發佈模式。調試模式在大多數環境中引入了額外的檢查和鏈接的debug庫還可以包含其他檢查,例如邊界檢查和迭代器驗證,這些迭代器不存在於版本模式。所有這些都可以引入在發佈模式中不存在的性能點擊。

您還可以應用其他優化方法,例如在加載數據之前在DATA中預留內存。這將減少緩衝區擴展時需要進行的副本數量。雖然性能提升可能並不顯着,但它絕對有幫助。我建議通過分析器運行你的代碼,看看所有的瓶頸在哪裏,並相應地進行優化。

0

如果你知道你是在一個little-endian機器上,你可以完全忽略重新打包的數據,並直接存儲pixelarray數據。

OffFile.Write((char *)&PixelArray, Size_Of_BMP); 

它可能不是很便攜,但它肯定會加速文件的保存。

(你可以在聲明中有一個

#ifdef LITTLE_ENDIAN 
struct PIXEL{ 
    unsigned char A, R, G, B; 
}; 
#else 
struct PIXEL{ 
    unsigned char B, G, R, A; 
}; 
#endif  

PIXEL *PixelArray; 

+0

的確如此,但我打算將它與一個噪聲函數結合起來,並且它必須使它能夠隨着一臺大型機器的終端用戶移植,儘管知道這是可能的。 –