C / C ++旋转BMP图像

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

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

编辑(sin,cos和旋转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; } 

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 = 0 && xx = 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度。

这是我的原始图像 ,这是我的结果

请你们其中一个人让我不知道我在这里做错了什么? 我真的需要这个function让它工作。 并且请不要向我建议一些可以帮助我这样做的库,因为我需要让它能够从代码中运行,而不需要任何特殊的库来完成这项工作。

同时请不要发表评论,比如“去看看BMP标题”,因为我已经知道了这几个

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

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

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

 BMP newImage = image; 

newImage设置为image 。 BMP结构是:

  unsigned char *pixels; 

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

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

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

要正确执行此操作,您的BMP类应符合Rule of Three标准 。

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

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,比如intlong而不是floatdouble ,这会使你的代码变得复杂而无益

    Interesting Posts