Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
199 views
in Technique[技术] by (71.8m points)

C++: rotate image BMP

I have some serious problems with this stupid rotation function of a BMP image... I've already post the same question now 2 days ago, I know... But no one could make me to understand what's happening here and how can I solve this issue.

EDIT: that image will be rotated just with 90 degrees multipler.

In this moment I'm trying to rotate this image with an 180 degree

enter image description here

And here it's my result until this moment

enter image description here

Here it's my code:

#include <algorithm>
#include <fstream>
#include <math.h>
#include <vector>
#include <iostream>

using namespace std;

double PI = 3.141592653589793238462643383279;
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");

    if (in == NULL)
        throw "Argument Exception";

    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;
            }
        }
    } else {
        cout << "Error: all bytes couldn't be read" << endl;
    }

    fclose(in);
    return image;
}

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

    double radians = (degree * 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.height; x++) {
        for (int y = 0; y < image.width * 3; y += 3) {
            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.width + x) * 3 + 0] = image.pixels[(yy * image.width + xx) * 3 + 0];
                pixels[(y * image.width + x) * 3 + 1] = image.pixels[(yy * image.width + xx) * 3 + 1];
                pixels[(y * image.width + x) * 3 + 2] = image.pixels[(yy * image.width + xx) * 3 + 2];
            }
        }
    }
    newImage.pixels = pixels;
    return newImage;
}

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

So please guys, I beg you... Could one of you help me to solve this stupid problem who kill me 2 days for almost nothing :/

Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

EDIT_2:

Check full code:

#include <algorithm>
#include <fstream>
#include <math.h>
#include <vector>
#include <string>
#include <iostream>
#include <chrono>
//#include "operation_parser.h"

using namespace std;
using namespace std::chrono;

double PI = 3.141592653589793238462643383279;
struct BMP {
    int width;
    int height;
    unsigned char header[54];
    unsigned char *pixels;
    int size;
    int row_padded;
    long long int size_padded;
};

void writeBMP(string filename, BMP image) {
    string fileName = 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 = filename;
    FILE *in = fopen(fileName.c_str(), "rb");

    if (in == NULL)
        throw "Argument Exception";

    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;
            }
        }
    } else {
        cout << "Error: all bytes couldn't be read" << endl;
    }

    fclose(in);
    return image;
}

BMP rotate180Degree(BMP image, double degree) {
    _ASSERTE(degree == 180.0);

    BMP newImage = image;
    unsigned char *pixels = new unsigned char[image.size_padded];

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

    newImage.pixels = pixels;
    return newImage;
}

int main() {
    BMP image = readBMP("test.bmp");
    image = rotate180Degree(image, 180);
    writeBMP("Output.bmp", image);
    return 0;
}

EDIT_1:

If only 0,90,180,270 degrees to rotate, here is the example of rotate 180 degrees, modify it if you want to do it with 0,90,270(image width and height change when rotate_degree = 90 or 270):

BMP rotate180Degree(BMP image, double degree) {
    _ASSERTE(degree == 180.0);

    BMP newImage = image;
    unsigned char *pixels = new unsigned char[image.size_padded];

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

    newImage.pixels = pixels;
    return newImage;
}

Another solution : We can use CImage from atlimage.h:

std::shared_ptr<CImage> OriginalImg = std::make_shared<CImage>();
OriginalImg->Load("test.png");

int W = OriginalImg->GetWidth(), H = OriginalImg->GetHeight();

std::shared_ptr<CImage> RotatedImg = std::make_shared<CImage>();
RotatedImg->Create(W, H, OriginalImg->GetBPP());

for (unsigned int x = 0; x < W; ++x)
{
    for (unsigned int y = 0; y < H; ++y)
    {
        RotatedImg->SetPixel(x, y, OriginalImg->GetPixel(W - x - 1, H - y - 1));
    }
}

RotatedImg->Save("rotatedImage.png");

Result:

Rotated Image


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...