C/C 旋转 BMP 图像

新手上路,请多包涵

我正在尝试使用 C/C++ 旋转 BMP 图像,但它不起作用。

我制作了一些用于读取、写入和旋转的功能。读取和写入功能工作正常,但由于某种原因不能旋转。

编辑(正弦、余弦和旋转函数)

BMP结构:

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

写:

 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);
    int i;
    unsigned char tmp;
    for (i = 0; i < image.size; i += 3) {
        tmp = image.pixels[i];
        image.pixels[i] = image.pixels[i + 2];
        image.pixels[i + 2] = tmp;
    }
    fwrite(image.pixels, sizeof(unsigned char), image.size, out); // read the rest of the data at once
    fclose(out);
}

读:

 BMP readBMP(string filename) {
    BMP image;
    int i;
    string fileName = "Input Files/" + filename;
    FILE *f = fopen(fileName.c_str(), "rb");
    fread(image.header, sizeof(unsigned char), 54, f); // 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.size = 3 * image.width * image.height;
    image.pixels = new unsigned char[image.size]; // allocate 3 bytes per pixel
    fread(image.pixels, sizeof(unsigned char), image.size, f); // read the rest of the data at once
    fclose(f);

    for (i = 0; i < image.size; i += 3) {
        unsigned char tmp = image.pixels[i];
        image.pixels[i] = image.pixels[i + 2];
        image.pixels[i + 2] = tmp;
    }
    return image;
}

旋转:

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

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

主要的:

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

sin=0.8939966636 (弧度)和 cos=-0.44807361612 (弧度)意味着这个图像应该旋转90度。

这是我的原始图像:

原来的

这是我的结果的时刻:

结果

有人可以帮我理解我在这里做错了什么吗?我真的需要这个功能才能工作。

我不能为此代码使用任何第三方库。

原文由 Mircea 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 704
1 个回答

它必须以 bmp 使用的相同像素格式处理旋转。您只为每个像素转换一个字节。像素看起来更宽。既然问题已经确定,这应该很容易解决。

如果您需要更快的速度,请注意您有不变量(x 和 y),每次迭代都会增加:

 for (int y = 0; y < image.height; y++) {
        double a = x - x0;
        double b = y - y0;
        int xx = (int) (+a * cos - b * sin + x0);

将 b 移出循环并将乘法更改为加法:

 double b = -y0;
for (int y = 0; y < image.height; ++y) {
    int xx = (int) (a * cos - b + x0);
    b += sin;

注意 a * cos 是整个 y 循环的常数吗?将其融合到 b。对 x0 做同样的事情。

 double b = a * cos - y0 + x0;
for (int y = 0; y < image.height; ++y) {
    int xx = (int) (- b);
    b += sin;

请注意 -b 也有成本?否定 B.

 double b = -(a * cos - y0 + x0);
for (int y = 0; y < image.height; ++y) {
    int xx = (int) b;
    b -= sin;

看看我们在那里做了什么?下一步:摆脱双打。使用定点。浮点到整数的转换可能代价高昂。充其量,它们在这里毫无用处。

最后但并非最不重要的一点是,您正在垂直写入内存。这对写入组合非常非常不利,并且会大大降低性能。考虑更改循环顺序,使 x-loop 位于最里面。

额外:对图像使用平铺内存布局,以提高读取时的内存局部性。缓存将更有效地工作。在这里不是很重要,因为您只处理一次图像并且平铺会比加速更昂贵。但是,如果您想为旋转设置动画,那么平铺应该会让您受益。此外,通过平铺,性能不会因旋转角度而波动,因此动画将更加一致(并且更快)。

编辑:添加说明如何支持每个像素更多的字节数:

 pixels[(y * image.height + x) * 3 + 0] = image.pixels[(yy * image.height + xx) * 3 + 0];
pixels[(y * image.height + x) * 3 + 1] = image.pixels[(yy * image.height + xx) * 3 + 1];
pixels[(y * image.height + x) * 3 + 2] = image.pixels[(yy * image.height + xx) * 3 + 2];

这开始有点难以阅读,但你确实看到我们在那里做了什么?

原文由 t0rakka 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题