C/C ++旋转BMP图像 [英] C/C++ rotate an BMP image

查看:72
本文介绍了C/C ++旋转BMP图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to rotate an BMP image using C/C++ but it's not working.

我已经做了一些读取,写入和旋转的功能.读取和写入功能运行正常,但由于某种原因不会旋转.

I've made some functions for read, write and rotation. The read and write functions are working perfectly fine but not rotate from some reason.

编辑(正弦,余弦和旋转功能)

EDIT(sin, cos and rotate function)

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度.

That sin=0.8939966636(in radians) and cos=-0.44807361612(in radians) means this image should be rotated by 90 degree.

这是我的原始图片:

现在是我的结果:

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

Could someone help me understand what I'm doing wrong here? I really need this function to work.

我不能将任何第三方库用于此代码.

I cannot use any third party libraries for this code.

推荐答案

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

It must handle the rotation in the same pixel format the bmp uses. You are only transforming one byte for each pixel. The pixels look to be wider. This should be easy to fix now that the problem has been identified.

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

If you need more speed, notice that you have invariants (x and y) that are incremented for each iteration:

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移到循环外,并将乘法更改为加法:

Move the b outside of the loop and change the multiplication to addition:

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做同样的事情.

Notice that the a * cos is a constant for the whole y-loop? Fuse it to the b. Do the same for x0.

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

注意-b也要花费吗?取反b.

Notice that the -b costs as well? Negate b.

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

看看我们在那里做了什么?下一步:摆脱双打.使用定点.从浮点数到整数的转换可能会很昂贵.充其量,它们在这里没用.

See what we did there? Next: get rid of the doubles. Use fixed-point. Float-to-integer conversions can be costly. At best, they are useless here.

最后但并非最不重要的一点是,您正在垂直写入内存.这对于写入合并非常非常有害,并且将大大降低性能.考虑更改循环顺序,以使x循环成为最内层的循环.

Last but not least, you are writing into memory vertically. This is very, very bad for the write combine and will dramatically reduce the performance. Consider changing the loop order so that x-loop is the innermost one.

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

Extra: use tiled memory layout for the image to improve memory locality when reading. Cache will work more efficiently. Not super important here as you only process the image once and tiling would be more expensive than the speed up. But if you want to animate the rotation then tiling should benefit you. Also, with tiling the performance does not fluctuate depending on the rotation angle so the animation will be more consistent (and faster).

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

add explanation how to support more bytes per pixel:

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];

这开始有点难以理解,但是您确实看到我们在做什么吗?

This is starting to be a bit hard to read, but you do see what we are doing there?

这篇关于C/C ++旋转BMP图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆