2016-11-18 6 views
0

Хорошо, ребята, я третий раз отправляю тот же вопрос (предыдущие и here).C++: BMP вращать изображение

Теперь в это время я попытаюсь объяснить, что это моя проблема:

  1. Так первый их все, мне нужно повернуть .bmp изображение и оно не вращается правильно. Но мне не нужно поворачивать случайное изображение с расширением .bmp, мне нужно повернуть this one. Я пробовал со многими другими изображениями, и все они были повернуты правильно, кроме моего.
  2. В этот момент мой код работает только для 180-градусный, как он мог работать на любой степени, которая кратная 90-градусной (мне нужно повернуть свое изображение только с 90, 180 или 270 градусов, не более).
  3. мне не нужен какой-либо внешней библиотеки для этого кода, как CImage, OpenCV, ImageMagik и так далее ... Мне нужно, чтобы сделать этот код работать.

Итак, да, это все. И здесь вы можете найти мои фактические result.

КОД:

#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), width & height = 2650 оба из них, Windows 10, и что вы означает битконтировать? – 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. Во всяком случае, проблемы с этим типом производительности библиотек. Я имею в виду, если я делаю так, это будет намного быстрее, чем я использую библиотеку, я думаю. Вот почему мне действительно нужна помощь. Вы знаете, как я могу разрешить чтение/запись без использования библиотек? – Mircea

Смежные вопросы