2016-11-18 117 views
0

好吧,這是我第三次發佈相同的問題(以前是herehere)。C++:BMP旋轉圖像

現在,在這個時候,我會盡量解釋什麼是我的問題:

  1. 所以第一他們,我需要旋轉.BMP圖像,它不是正常旋轉。但我不需要旋轉隨機圖像,擴展名爲.bmp,我需要旋轉this one。我嘗試了很多其他圖像,並且所有這些圖像都正確旋轉,除了我的圖像。
  2. 在這一刻,我的代碼只適用於180度,如何使它在90度倍數的任何程度上工作(我需要旋轉我的圖像只需90,180或270度,不是更多)。
  3. 我不需要任何外部庫的這種類似的代碼的CImageOpenCV的ImageMagik等等...我需要這個代碼工作。

所以,就是這樣。在這裏你可以找到我的實際result

CODE:

#include <array> 

using namespace std; 

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

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); 

    unsigned char tmp; 
    for (int i = 0; i < image.height; i++) { 
     for (int j = 0; j < image.width * 3; j += 3) { 
      //Convert(B, G, R) to(R, G, B) 
      tmp = image.pixels[j]; 
      image.pixels[j] = image.pixels[j + 2]; 
      image.pixels[j + 2] = tmp; 
     } 
    } 
    fwrite(image.pixels, sizeof(unsigned char), image.size_padded, out); 
    fclose(out); 
} 

BMP readBMP(string filename) { 
    BMP image; 
    string fileName = "Input Files\\" + filename; 
    FILE *in = fopen(fileName.c_str(), "rb"); 

    fread(image.header, sizeof(unsigned char), 54, in); // 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.row_padded = (image.width * 3 + 3) & (~3);  // ok size of a single row rounded up to multiple of 4 
    image.size_padded = image.row_padded * image.height; // padded full size 
    image.pixels = new unsigned char[image.size_padded]; // yeah ! 

    if (fread(image.pixels, sizeof(unsigned char), image.size_padded, in) == image.size_padded) { 
     unsigned char tmp; 
     for (int i = 0; i < image.height; i++) { 
      for (int j = 0; j < image.width * 3; j += 3) { 
       //Convert (B, G, R) to (R, G, B) 
       tmp = image.pixels[j]; 
       image.pixels[j] = image.pixels[j + 2]; 
       image.pixels[j + 2] = tmp; 
      } 
     } 
    } 
    fclose(in); 
    return image; 
} 

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

     int height = image.height; 
     int width = image.width; 
     for (int x = 0; x < height; x++) { 
      for (int y = 0; y < width; y++) { 
       pixels[(x * width + y) * 3 + 0] = image.pixels[((height - 1 - x) * width + (width - 1 - y)) * 3 + 0]; 
       pixels[(x * width + y) * 3 + 1] = image.pixels[((height - 1 - x) * width + (width - 1 - y)) * 3 + 1]; 
       pixels[(x * width + y) * 3 + 2] = image.pixels[((height - 1 - x) * width + (width - 1 - y)) * 3 + 2]; 
      } 
     } 
     newImage.pixels = pixels; 
    return newImage; 
} 

int main() { 

    BMP image = readBMP("Input-1.bmp"); 
    image = rotate(image, 180); 
    writeBMP("Output.bmp", image); 

    return 0; 
} 
+0

你會使用OpenCV的 – RyanP

回答

0

您的內存泄漏嚴重。 pixels = new unsigned char[size];必須被釋放,否則每次旋轉都會有數兆字節的泄漏。您必須重寫該函數以跟蹤內存分配。

當您通過圖像的90或270旋轉圖像時,圖像的寬度/高度會發生變化。由於填充,大小可能也會改變。新維度必須記錄在頭文件中。

在C++中,您可以使用fopen,但首選std::fstream

這是一個在Windows中僅適用於24位圖像的例子。在Big-endian系統中,您不能使用memcpy以下我使用它的方式。

注意,這是僅用於練習。正如@datenwolf解釋說你應該使用一個庫來進行真正的應用程序。大多數標準庫如Windows GDI庫(基本繪圖函數)爲這些常見任務提供解決方案。

#include <iostream> 
#include <fstream> 
#include <string> 
#include <Windows.h> 

bool rotate(char *src, char *dst, BITMAPINFOHEADER &bi, int angle) 
{ 
    //In 24bit image, the length of each row must be multiple of 4 
    int padw = 4 - ((bi.biWidth * 3) % 4); 
    if(padw == 4) padw = 0; 

    int padh = 4 - ((bi.biHeight * 3) % 4); 
    if(padh == 4) padh = 0; 

    int pad2 = 0; 
    if(padh == 1 || padh == 3) pad2 = 2; 

    bi.biHeight += padh; 

    int w = bi.biWidth; 
    int h = bi.biHeight; 
    if(angle == 90 || angle == 270) 
    { 
     std::swap(bi.biWidth, bi.biHeight); 
    } 
    else 
    { 
     bi.biHeight -= padh; 
    } 

    for(int row = 0; row < h; row++) 
    { 
     for(int col = 0; col < w; col++) 
     { 
      int n1 = 3 * (col + w * row) + padw * row; 
      int n2 = 0; 

      switch(angle) 
      { 
      case 0: n2 = 3 * (col + w * row) + padw * row; break; 
      case 90: n2 = 3 * ((h - row - 1) + h * col) + pad2 * col; break; 
      case 180: n2 = 3 * (col + w * (h - row - 1)) + padw * (h - row - 1); break; 
      case 270: n2 = 3 * (row + h * col) + pad2 * col; break; 
      } 

      dst[n2 + 0] = src[n1 + 0]; 
      dst[n2 + 1] = src[n1 + 1]; 
      dst[n2 + 2] = src[n1 + 2]; 
     } 
    } 

    for(int row = 0; row < bi.biHeight; row++) 
     for(int col = 0; col < padw; col++) 
      dst[bi.biWidth * 3 + col] = 0; 

    bi.biSizeImage = (bi.biWidth + padw) * bi.biHeight * 3; 

    return true; 
} 

int main() 
{ 
    std::string input = "input.bmp"; 
    std::string output = "output.bmp"; 

    BITMAPFILEHEADER bf = { 0 }; 
    BITMAPINFOHEADER bi = { sizeof(BITMAPINFOHEADER) }; 

    std::ifstream fin(input, std::ios::binary); 
    if(!fin) return 0; 

    fin.read((char*)&bf, sizeof(bf)); 
    fin.read((char*)&bi, sizeof(bi)); 

    int size = 3 * (bi.biWidth + 3) * (bi.biHeight + 3); 
    char *src = new char[size]; 
    char *dst = new char[size]; 

    fin.read(src, bi.biSizeImage); 

    //use 0, 90, 180, or 270 for the angle 
    if(rotate(src, dst, bi, 270)) 
    { 
     bf.bfSize = 54 + bi.biSizeImage; 
     std::ofstream fout(output, std::ios::binary); 
     fout.write((char*)&bf, 14); 
     fout.write((char*)&bi, 40); 
     fout.write((char*)dst, bi.biSizeImage); 
    } 

    delete[]src; 
    delete[]dst; 

    return 0; 
} 
+0

我已經感謝你的幫助,但是像其他人一樣這個功能...不工作...你是否在我的圖像上嘗試了這個功能?這裏是[結果](http://imgur.com/NAbqU2P)這段代碼與我的圖片一起執行。我知道這僅僅是爲了練習,這就是要點......這是我不想使用外部庫的原因,我需要完成它,並且我想通過出庫來理解它。但由於某種原因......不計算我試過的功能......沒有人會爲此工作:/ – Mircea

+0

我不知道你的原始圖像。什麼是您的圖像的寬度和高度?什麼是計數?你在做什麼操作系統? –

+0

原始圖像是[這裏](https://www.dropbox.com/s/aggfmos2umttac2/Input-1.bmp?dl=0),寬度和高度= 2650他們兩個,Windows 10,和你是什麼意味着與bitcount? – Mircea

1

的BMP文件格式是一種複雜的,令人費解的野獸,有一個「簡單」的BMP文件閱讀器沒有這樣的事情。你在那裏的代碼會對你試圖讀取的文件做出某些硬編碼的假設(24bpp真彩色,緊湊,沒有壓縮),當它遇到任何不是特定格式的東西時,它會平坦(在它的臉上) 。不幸的是,對你來說,大多數BMP文件並不是那種類型。爲了給你一個什麼樣的完全符合BMP閱讀器必須支持看看這個頁面的想法:

http://entropymine.com/jason/bmpsuite/bmpsuite/html/bmpsuite.html

和代碼,你必須在那裏甚至沒有檢查是否有一個有效的文件魔術字節的簽名和如果標題有效。所以這就是你的問題:你沒有BMP文件閱讀器。如果你足夠幸運的話,你有一些真正吐出像素的東西,偶然碰巧是正確的格式。

+0

問題的關鍵是有一個更容易的時間。我需要讓我的代碼爲這,只是這樣的我怎麼樣了後在我的問題影像工作。我假設我的所有圖像都是24bpp真彩色,緊湊,沒有壓縮。我所有的輸入都將採用這種格式。這假設很容易......但不是。所以,如果你能幫助旋轉這種形象,我會很高興。 – Mircea

+0

@Mircea:問題是沒有進行圖像旋轉。問題是正確讀取(也寫入)文件。最簡單的解決方案是使用現有的,經過良好測試的圖像文件讀取器/寫入器庫,而不是滾動您自己的。這樣做,你是金。 – datenwolf

+0

我不知道任何類型的庫只是爲了讀寫圖像。我發現的一切都是如何用相同的庫來讀取和處理圖像,例如CImage。無論如何,這種類型的庫性能的問題。我的意思是,如果我這樣做,將會快得多,然後我使用我認爲的圖書館。所以這就是我真正需要som幫助的原因。你有什麼想法,我怎麼能解決讀/寫部分沒有使用庫? – Mircea