C / C ++旋转BMP图像

时间:2016-11-15 22:55:40

标签: c++ c bitmap rotation bitmapimage

我尝试使用C / C ++旋转BMP图像,但它无效。

我已经为读取,写入和旋转做了一些功能,读取和写入工作完美正常,但不是因为某些原因而旋转。

编辑(sin,cos和旋转功能)

BMP结构:

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

WRITE:

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

READ:

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

ROTATE:

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

这是我的original image及其现在的my result in

请你们其中一个人让我不知道我在这里做错了什么?我真的需要这个功能让它工作。请不要向我建议一些可以帮助我这样做的库,因为我需要让它能够从代码中找到适合这项工作的任何类型的库。

在同一时间,请不要发表评论,例如&#34;去阅读BMP标题&#34;因为我已经做了这几个

我希望你能帮助我......我真的需要它。

3 个答案:

答案 0 :(得分:2)

它必须以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];

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

答案 1 :(得分:0)

BMP newImage = image;

这会将newImage设置为image。 BMP结构是:

     unsigned char *pixels;

因此,newImageimage都有相同的pixels指针。

不幸的是,轮换代码中的逻辑假定newImageimage是不同的独立缓冲区。

您需要做更多工作才能创建newImage对象。您需要分配自己的图像缓冲区,将内存清除为空图像,并将其pixels设置为指向它。

要正确执行此操作,您的BMP课程应为Rule Of Three compliant

答案 2 :(得分:0)

您可以将像素(缓冲区)复制到一个新的,单独的,相同类型/大小的像素(如前所述),然后使用以下内容旋转它:

http://www.sourcetricks.com/2012/07/rotate-matrix-by-90-degrees.html

然后你可以将新缓冲区重新复制回原始像素缓冲区,清理(自由)它(编辑:它表示副本),最后重绘所有。

编辑:

I was thinking in pseudo code: 
    rotate image 
    { 
    imagecopy = duplicate (image) 
    (do the rotation on imagecopy)  
    copypixels (imagecopy (to), image) 
    free imagecopy 
    } 

copy和dup是for循环但是dups添加了malloc

和“newImage.pixels = pixels;”无法工作,你必须遍历两个数组并像“writeBMP”一样逐个复制值

哦和

  

它必须以bmp使用的相同像素格式处理旋转。

我认为他的意思是使用INTEGERS,比如 int long 而不是 float double 会让你感到困惑没有利益的代码