我正在尝试使用 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 许可协议
它必须以 bmp 使用的相同像素格式处理旋转。您只为每个像素转换一个字节。像素看起来更宽。既然问题已经确定,这应该很容易解决。
如果您需要更快的速度,请注意您有不变量(x 和 y),每次迭代都会增加:
将 b 移出循环并将乘法更改为加法:
注意 a * cos 是整个 y 循环的常数吗?将其融合到 b。对 x0 做同样的事情。
请注意 -b 也有成本?否定 B.
看看我们在那里做了什么?下一步:摆脱双打。使用定点。浮点到整数的转换可能代价高昂。充其量,它们在这里毫无用处。
最后但并非最不重要的一点是,您正在垂直写入内存。这对写入组合非常非常不利,并且会大大降低性能。考虑更改循环顺序,使 x-loop 位于最里面。
额外:对图像使用平铺内存布局,以提高读取时的内存局部性。缓存将更有效地工作。在这里不是很重要,因为您只处理一次图像并且平铺会比加速更昂贵。但是,如果您想为旋转设置动画,那么平铺应该会让您受益。此外,通过平铺,性能不会因旋转角度而波动,因此动画将更加一致(并且更快)。
编辑:添加说明如何支持每个像素更多的字节数:
这开始有点难以阅读,但你确实看到我们在那里做了什么?