2016-11-15 130 views
0

我想使用C/C++旋轉BMP圖像,但它不工作。C/C++旋轉BMP圖像

我已經做了一些讀,寫和旋轉的功能,讀寫工作完美,但沒有,並且由於某種原因旋轉。

EDIT(正弦,餘弦和旋轉功能)

BMP的結構:

struct BMP { 
    int width; 
    int height; 
    unsigned char header[54]; 
    unsigned char *pixels; 
    int size; 
}; 

WRITE:

void writeBMP(string filename, BMP image) { 
    string fileName = "Output Files/" + filename; 
    FILE *out = fopen(fileName.c_str(), "wb"); 
    fwrite(image.header, sizeof(unsigned char), 54, out); 
    int i; 
    unsigned char tmp; 
    for (i = 0; i < image.size; i += 3) { 
     tmp = image.pixels[i]; 
     image.pixels[i] = image.pixels[i + 2]; 
     image.pixels[i + 2] = tmp; 
    } 
    fwrite(image.pixels, sizeof(unsigned char), image.size, out); // read the rest of the data at once 
    fclose(out); 
} 

READ:

BMP readBMP(string filename) { 
    BMP image; 
    int i; 
    string fileName = "Input Files/" + filename; 
    FILE *f = fopen(fileName.c_str(), "rb"); 
    fread(image.header, sizeof(unsigned char), 54, f); // read the 54-byte header 

    // extract image height and width from header 
    image.width = *(int *) &image.header[18]; 
    image.height = *(int *) &image.header[22]; 

    image.size = 3 * image.width * image.height; 
    image.pixels = new unsigned char[image.size]; // allocate 3 bytes per pixel 
    fread(image.pixels, sizeof(unsigned char), image.size, f); // read the rest of the data at once 
    fclose(f); 

    for (i = 0; i < image.size; i += 3) { 
     unsigned char tmp = image.pixels[i]; 
     image.pixels[i] = image.pixels[i + 2]; 
     image.pixels[i + 2] = tmp; 
    } 
    return image; 
} 

ROTATE:

BMP rotate(BMP image, double degree) { 
    BMP newImage = image; 
    unsigned char *pixels = new unsigned char[image.size]; 

    double radians = (degree * M_PI)/180; 
    int sinf = (int) sin(radians); 
    int cosf = (int) cos(radians); 

    double x0 = 0.5 * (image.width - 1);  // point to rotate about 
    double y0 = 0.5 * (image.height - 1);  // center of image 

    // rotation 
    for (int x = 0; x < image.width; x++) { 
     for (int y = 0; y < image.height; y++) { 
      long double a = x - x0; 
      long double b = y - y0; 
      int xx = (int) (+a * cosf - b * sinf + x0); 
      int yy = (int) (+a * sinf + b * cosf + y0); 

      if (xx >= 0 && xx < image.width && yy >= 0 && yy < image.height) { 
       pixels[(y * image.height + x) * 3 + 0] = image.pixels[(yy * image.height + xx) * 3 + 0]; 
       pixels[(y * image.height + x) * 3 + 1] = image.pixels[(yy * image.height + xx) * 3 + 1]; 
       pixels[(y * image.height + x) * 3 + 2] = image.pixels[(yy * image.height + xx) * 3 + 2]; 
      } 
     } 
    } 
    newImage.pixels = pixels; 
    return newImage; 
} 

MAIN:

int main() { 
    BMP image = readBMP("InImage_2.bmp"); 
    image = rotate(image,180); 
    writeBMP("Output-11.bmp", image); 
    return 0; 
} 

sin=0.8939966636(弧度)和cos=-0.44807361612(以弧度爲單位)指該圖像應該由90度旋轉。

這是我的original image,在這裏它的那一刻my result in

請你能球員之一,讓我已瞭解我在做什麼錯在這裏?我真的需要這個功能讓它工作。並且請不要向我建議一些可以幫助我這樣做的庫,因爲我需要使用代碼來完成這項工作特有的任何庫。

而在同一時間,請不要讓類似「去閱讀BMP頭」,因爲我alread這樣做幾

我希望你能幫助我這個...評論我真的需要它。

+1

在旋轉中,newImage = image。因此,您在旋轉時覆蓋圖像像素。 – stark

+1

假設光柵順序 – samgak

+0

@samgak應該對旋轉方向產生一些影響,我認爲PIxel尋址應該是'[y * image.width + x]'。但無論如何它不能正常工作......我編輯了我的**旋轉功能**添加了新的結果以及您說了些什麼。而在這一刻......我之前有一個更奇怪的結果。 – Mircea

回答

0
BMP newImage = image; 

這臺newImageimage。該BMP結構爲:

 unsigned char *pixels; 

所以,無論newImageimage具有相同的pixels指針。

不幸的是,您的循環代碼中的邏輯假定newImageimage是不同的獨立緩衝區。

您將需要做更多的工作來創建您的newImage對象。您將需要分配自己的圖像緩衝區,將內存清空爲空白圖像,並將其設置爲指向它的pixels

要正確地做到這一點,你的BMP類應該被製作Rule Of Three compliant

+0

好吧,如果你說什麼是真的,那麼我只需要創建一組像素像'unsigned char * pixels = new unsigned char [image.size]; '並與它一起工作。最後我需要做一些像'newImage.pixels = pixels;'的事情。所以我做了這個,我得到了一個更奇怪的結果...我通過添加細節和新結果來編輯我的**旋轉函數**,可以再次檢查它嗎? – Mircea

+0

「我得到一個更奇怪的結果」不是一個有效的問題描述。 –

+0

我的意思是,我沒有得到我期待的結果。我已更新我的問題,以便您可以查看我嘗試過的內容,但這不起作用,您會看到新的結果。 – Mircea

0

你可以再旋轉使用這樣的事情是您的像素(緩衝區)複製到一個新的,獨立的和同類型/大小的一個,(如前說的):

http://www.sourcetricks.com/2012/07/rotate-matrix-by-90-degrees.html

然後你可以重新複製新的緩衝區返回到您的原始像素緩衝區,清理(免費)它(編輯:它意味着副本),並最終重新繪製所有。

編輯:

I was thinking in pseudo code: 
    rotate image 
    { 
    imagecopy = duplicate (image) 
    (do the rotation on imagecopy) 
    copypixels (imagecopy (to), image) 
    free imagecopy 
    } 

拷貝和DUP是for循環,但增加的DUP一個malloc

和 「newImage.pixels =像素;」將無法正常工作,您必須通過兩個陣列環和一個複製一個值就像「writeBMP」

OH中,

它必須處理在BMP使用相同的像素格式的旋轉。

我想他的意思是使用整數,像INT,而不是浮動你的代碼複雜化毫無benifit

+0

那麼如果你再次檢查我的旋轉函數..你會看到我已經爲像素添加了一個新的緩衝區,這裏是'unsigned char * pixels = new unsigned char [image.size];'並且在這個函數的結尾處我會做'newImage.pixels =像素;'所以我不再有這個問題了 – Mircea

+0

我在考慮僞代碼: – kiwe

+0

image image = copy(image) (在imagecopy上做旋轉) – kiwe

0

它必須在相同的像素處理旋轉格式化bmp使用。您只是爲每個像素轉換一個字節。像素看起來更寬。現在應該很容易解決這個問題。

如果需要更快的速度,注意,你有不變量(x和y)被增加爲每次迭代:

for (int y = 0; y < image.height; y++) { 
     double a = x - x0; 
     double b = y - y0; 
     int xx = (int) (+a * cos - b * sin + x0); 

將b的循環之外,改變乘法加法:

double b = -y0; 
for (int y = 0; y < image.height; ++y) { 
    int xx = (int) (a * cos - b + x0); 
    b += sin; 

請注意,a * cos是整個y循環的常量?將它保存到b。對x0做同樣的事情。

double b = a * cos - y0 + x0; 
for (int y = 0; y < image.height; ++y) { 
    int xx = (int) (- b); 
    b += sin; 

請注意,-b成本以及?否定b。

double b = -(a * cos - y0 + x0); 
for (int y = 0; y < image.height; ++y) { 
    int xx = (int) b; 
    b -= sin; 

看看我們在那兒做了什麼?下一步:擺脫雙打。使用固定點。浮點到整數的轉換可能會很昂貴。充其量,他們在這裏是無用的。

最後但並非最不重要的是,您正在垂直寫入內存。這對寫入組合非常非常不利,並且會顯着降低性能。考慮改變循環順序,使x循環是最內層的循環。

附加:爲圖像使用平鋪內存佈局以提高讀取時的內存局部性。緩存將更有效地工作。這裏不是非常重要,因爲您只處理圖像一次,平鋪會比加速更昂貴。但如果你想旋轉動畫,那麼平鋪應該會讓你受益。此外,平鋪時,性能不會因旋轉角度而波動,因此動畫會更加一致(並且速度更快)。

編輯:添加說明如何支持每像素多個字節:

pixels[(y * image.height + x) * 3 + 0] = image.pixels[(yy * image.height + xx) * 3 + 0]; 
pixels[(y * image.height + x) * 3 + 1] = image.pixels[(yy * image.height + xx) * 3 + 1]; 
pixels[(y * image.height + x) * 3 + 2] = image.pixels[(yy * image.height + xx) * 3 + 2]; 

這是開始有點難以閱讀,但你看看我們在做什麼呢?

+0

好吧所以...如果你談論速度,那麼我會在將來改變它,首先我需要讓我的輪換工作。 '它必須以bmp使用的相同像素格式處理旋轉。',呃...我不知道該怎麼做。我的意思是我以爲我已經這麼做了。你能爲我寫這段代碼嗎?因爲我不知道如何做到這一點,而且我正在嘗試幾個小時,而且我什麼也沒有得到......如果你能爲我做到這一點,這將非常有幫助。 – Mircea

+0

我添加了一些代碼來演示如何處理更寬的像素。我注意到你快樂地寫了一箇舊的圖像指針而不是釋放內存。您可能也想修復內存泄漏。如果你喜歡這樣的錯誤(std :: vector,std :: array,std :: unique_ptr或類似),我建議你使用一些RAII友好類型的存儲。 – SnappleLVR

+0

我會在完成這個問題後看到我會做什麼內存泄漏。在這一刻,我們可以說......我的問題已經完成了50%。這一刻我只有2個問題,** 1。我不知道爲什麼,但它沒有在中心旋轉的圖像,它在中心旁邊(你可以看到我的新結果,因爲我已經更新了我的問題)**和第二個,** 2。我不知道爲什麼,但是我因爲某種原因調用了旋轉函數後,我失去了圖像的顏色屬性,所有的圖像都只是黑色和白色。**你能幫我解決這2個問題嗎? – Mircea