我尝试使用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;因为我已经做了这几个
我希望你能帮助我......我真的需要它。
答案 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;
因此,newImage
和image
都有相同的pixels
指针。
不幸的是,轮换代码中的逻辑假定newImage
和image
是不同的独立缓冲区。
您需要做更多工作才能创建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 会让你感到困惑没有利益的代码