C / C ++ повернуть изображение BMP

Я пытаюсь повернуть изображение BMP с помощью C / C ++, но это не работает.

Я сделал некоторые функции для чтения, записи и поворота, чтения и записи работает отлично, но не работает и вращается по какой-то причине.

РЕДАКТИРОВАТЬ (функция sin, cos и rotate)

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 градусов.

Вот мой исходное изображение и вот это момент мой результат в

Не могли бы вы, ребята, заставить меня понять, что я здесь делаю не так? Мне действительно нужна эта функция, чтобы она работала. И, пожалуйста, не предлагайте мне некоторые библиотеки, которые могли бы помочь мне сделать это, потому что мне нужно, чтобы это работало из кода без каких-либо библиотек, специально предназначенных для этой работы.

И в то же время, пожалуйста, не позволяйте комментарию типа «иди и читай заголовок BMP», потому что я уже сделал это несколько

Надеюсь, вы поможете мне с этим … Мне это действительно нужно.

1

Решение

Он должен обрабатывать поворот в том же формате пикселей, который использует 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? Сплавить это с б. Сделайте то же самое для х0.

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

Обратите внимание, что -b также стоит? Отрицание б.

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

Видишь, что мы там сделали? Далее: избавиться от двойников. Используйте фиксированную точку. Преобразования с плавающей точкой в ​​целое могут быть дорогостоящими. В лучшем случае они здесь бесполезны.

И последнее, но не менее важное: вы пишете в память вертикально. Это очень, очень плохо для комбайна записи и резко снизит производительность. Подумайте об изменении порядка петель, чтобы х-петля была самой внутренней.

Дополнительно: используйте мозаичное расположение памяти для изображения, чтобы улучшить локальность памяти при чтении. Кеш будет работать более эффективно. Это не супер важно, так как вы обрабатываете изображение только один раз, а укладка плитки будет стоить дороже, чем ускорение. Но если вы хотите анимировать вращение, тогда черепица должна вам помочь. Кроме того, при использовании мозаики производительность не меняется в зависимости от угла поворота, поэтому анимация будет более последовательной (и более быстрой).

РЕДАКТИРОВАТЬ: добавить объяснение, как поддерживать больше байтов на пиксель:

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

Другие решения

BMP newImage = image;

Это устанавливает newImage в image, Структура BMP:

     unsigned char *pixels;

Итак, оба newImage а также image имеют те же pixels указатель.

К сожалению, логика в вашем коде ротации предполагает, что newImage а также image разные, независимые буферы.

Вам нужно будет сделать больше работы, чтобы создать свой newImage объект. Вам нужно будет выделить свой собственный буфер изображений, очистить память для пустого изображения и установить его pixels указать на это.

Чтобы правильно сделать это, ваш BMP класс должен быть сделан Соответствует правилу трех.

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 для циклов, но dups добавляет malloc

и «newImage.pixels = пикселей;» не будет работать, вы должны пройти через оба массива и скопировать значения одно за другим, как в «writeBMP»

ну и по

Он должен обрабатывать поворот в том же формате пикселей, который использует bmp.

я думаю, что он имел в виду использовать INTEGERS, как ИНТ или же долго и не поплавок или же двойной что усложняет ваш код без всяких льгот

0