2016-11-18 168 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