【问题标题】:C++: rotate image BMPC++:旋转图像 BMP
【发布时间】:2017-04-01 19:17:43
【问题描述】:

我对 BMP 图像的这种愚蠢的旋转功能有一些严重的问题......我已经在 2 天前发布了同样的问题,我知道......但是没有人能让我理解这里发生了什么,并且我该如何解决这个问题。

编辑:该图像将仅旋转 90 度倍数。

此刻我正试图将此图像旋转 180 度

这是我的结果直到这一刻

这是我的代码:

#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;
}

所以请大家,我求求你们...你们中的哪一个可以帮我解决这个愚蠢的问题,它几乎没有杀死我 2 天:/

谢谢

【问题讨论】:

  • 嗯,你比以前走得更远了。在你得到彻底的垃圾之前。现在你有一些类似的东西。颜色偏移和错位的一个很可能的原因是在旋转函数中y 应该乘以row_padded,而不是height。想想看。但是像素地址的重复计算是重复的代码,给代码增加了很多混乱,使整体算法变得混乱,更容易隐藏错误。将其分解为一个独立的函数:给定 y 和 x 以及 BMP,返回一个指向像素的指针。
  • @SamVarshavchik 我不知道我在这里做错了什么,因为此代码在其他图像上具有功能,除了我需要...Here 你可以找到我需要的原始图像。你能帮我让这段代码工作吗?

标签: c++ image image-processing bitmap bitmapimage


【解决方案1】:

EDIT_2:

查看完整代码:

#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:

如果只旋转0,90,180,270度,这里是旋转180度的例子,如果你想用0,90,270(图像宽度和高度更改 当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;
}

另一种解决方案:我们可以使用atlimage.h中的CImage

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

结果:

【讨论】:

  • 对不起..但我需要使用这种代码,因为我需要我能获得的最佳性能......你能帮我让我的代码工作吗?
  • 您似乎包含了一个未提供的额外头文件(“operation_parser.h”)。
  • 这只是为了让我解析一个文本文件,因为稍后我需要它来旋转图像。在那个文本文件里面是我的函数应该使用多少度
  • 请为您的问题提供 reproducible 示例,原因在上面的代码中,特别是在函数 rotate():unsigned char *pixels = new unsigned char[image.size]; 中,其中未设置 image.size,这可以通过替换为image.size_padded 可以轻松修复。但是谁知道还有哪里出错了?
  • 另外,如果您想将图像旋转 any 度,我认为您需要做的第一件事就是测试您是否正确结果通过旋转 0/360 度,然后 180,然后 90, 270,最后尝试度数,如 23/45/78 ...但是到目前为止你还没有0工作,对吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
  • 2017-06-22
  • 2013-10-29
  • 2019-12-03
  • 2019-10-18
  • 2022-07-11
  • 2015-07-20
相关资源
最近更新 更多