Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Развернуть 8-битный bmp на 90 градусов


Автор: kurtis 25.9.2011, 22:30
Пытаюсь развернуть картинку на 90 градусов, в итоге, вместо картинки, получаю непонятный мусор. Исходное изображение 8-ми битное, разрешение 600 на 800 пикселей.
Вот моя функция разворота (пожалуйста, не обращайте внимание на оптимальность алгоритма, код сырой)
Код

static int rotate_image()
{
    int x_size = info.width; //600
    int y_size = info.height; //800
    int x, y;
    unsigned char dest_img[y_size][x_size];//rotated image
    unsigned char src_img[x_size][y_size];//source image

    memcpy(src_img, image, img_sz);

    for (x = 0; x < x_size; x++)
        for (y = 0; y < y_size; y++)
            dest_img[y][x_size - 1 -x] = src_img[x][y];

    memcpy(image, dest_img, img_sz);
}

В приложении исходник полностью, но не уверен что соберется не под Линукс.

Тестовое изображение можно взять http://dl.dropbox.com/u/2632562/my_logo.bmp (Дропбокс, 500 кб)
То что получается лежит http://dl.dropbox.com/u/2632562/my_logo_new.png (Дропбок, 20кб)
Нужно чтоб получилось изображение повернутое на 90 градусов.

Общий смысл действий
Есть последовательность байт, которая в зависимости от заголовка, интерпретируется особым образом. В моем случае, имеется изображение, размером 600 на 800 пикселей, 8 бит на цвет. Программа пытается сделать поворот, т.е. "певращение" столбцов в исходном изображении, в строки в перевернутом (или наоборот).

Посмотрите пожалуйста на код, может увидите откровенные ляпы, а то у меня уже от этой задачи немного крыша едет, не могу понять где я не правильно делают.

Спасибо.

P.S. Исходник не получилось прикрепить, закинул его на http://dl.dropbox.com/u/2632562/read_bmp.c

Автор: Estranged 25.9.2011, 22:59
Функция правильная. Картинка точно на 8 бит?

Автор: kurtis 26.9.2011, 08:06
точно
размер 480000 байт, это 1 байт (8 бит) * 600 * 800. Именно с этой областью я и работаю.

Автор: math64 26.9.2011, 09:52
Код использует возможности C, которых нет в C++ (динамические массивы), поэтому не будет компилироаваться в C++ или компиляторами С, не поддерживающими динамические массивы.
Можно переписать так:
Код

static int rotate_image()
{
    int x_size = info.width; //600
    int y_size = info.height; //800
    int img_sz = x_size*y_size;
    int x, y;
    unsigned char* dest_img = (unsigned char*)malloc(img_sz);
    unsigned char* src_img = (unsigned char*)image;
    for (x = 0; x < x_size; x++)
        for (y = 0; y < y_size; y++)
            dest_img[y * x_size + x_size - 1 - x] = src_img[x  * y_size + y];
    memcpy(image, dest_img, img_sz);
    free(dest_img);
}

Автор: kurtis 26.9.2011, 11:37
Спасибо за предложенный вариант алгоритма, но результат его работы аналогичен приведенному мной. 

Видимо проблема где-то в интерпретации данных bmp файла.

Автор: borisbn 26.9.2011, 13:02
Цитата(kurtis @  26.9.2011,  11:37 Найти цитируемый пост)
Видимо проблема где-то в интерпретации данных bmp файла.

Может быть... Попробуй сохранить BMP без поворота. Т.е. считать, разобрать по структурам и сохранить. Получаешь исходную картинку ?

Добавлено через 1 минуту и 28 секунд
Может у тебя установлено выравнивание структур на 4 (или 8) байт ? Тогда понятно. Нужно делать на 1 байт

Автор: math64 26.9.2011, 13:09
Мой вариант делает ровно то же, что и Ваш, но будет компилироваться под C++. Возможно, Вы не оттуда выбираете данные из bmp, В начале идёт заголовок, за ним (при 8-битном изображении) - палитра, и только потом данные, причем сначала нижние строчки. Если строка нечётной длины (не Ваш случай) - добавляется лишний байт для выравнивания.

Автор: kurtis 26.9.2011, 13:46
Цитата(borisbn @ 26.9.2011,  13:02)
Может быть... Попробуй сохранить BMP без поворота. Т.е. считать, разобрать по структурам и сохранить. Получаешь исходную картинку ?

Добавлено @ 13:03
Может у тебя установлено выравнивание структур на 4 (или 8) байт ? Тогда понятно. Нужно делать на 1 байт

md5 хэш полученного изображения полностью совпадает с исходным.

А можно про установку выравнивания немного по подробнее? Из того что я читал, то нужно делать строки кратными 4-м, но в моем случае, это не должно играть особой роли т.к. оба разрешения (исходного и перевернутое) кратны 4-м.


Автор: borisbn 26.9.2011, 13:49
Цитата(kurtis @  26.9.2011,  13:46 Найти цитируемый пост)
А можно про установку выравнивания немного по подробнее? Из того что я читал, то нужно делать строки кратными 4-м, но в моем случае, это не должно играть особой роли т.к. оба разрешения (исходного и перевернутое) кратны 4-м.

имеется в виду не выравнивание строк изображения, а выравнивание структур в исходном коде.
Не знаю, как в линуксе, а в MSVC это делается так
Код

#pragma pack ( push, 1 )
struct some_struct {
    char x;
    int y;
};
#pragma pack ( pop )

Попробуй, может и для gcc прокатит 

Автор: kurtis 26.9.2011, 13:51
Цитата(math64 @ 26.9.2011,  13:09)
Мой вариант делает ровно то же, что и Ваш, но будет компилироваться под C++. Возможно, Вы не оттуда выбираете данные из bmp, В начале идёт заголовок, за ним (при 8-битном изображении) - палитра, и только потом данные, причем сначала нижние строчки. Если строка нечётной длины (не Ваш случай) - добавляется лишний байт для выравнивания.

На первый взгляд все правильно, т.е. получается получить изображение идентичное исходному. Проблема именно в преобразовании (по крайне мере, мне так кажется).

Добавлено через 6 минут и 26 секунд
Цитата(borisbn @ 26.9.2011,  13:49)
Цитата(kurtis @  26.9.2011,  13:46 Найти цитируемый пост)
А можно про установку выравнивания немного по подробнее? Из того что я читал, то нужно делать строки кратными 4-м, но в моем случае, это не должно играть особой роли т.к. оба разрешения (исходного и перевернутое) кратны 4-м.

имеется в виду не выравнивание строк изображения, а выравнивание структур в исходном коде.
Не знаю, как в линуксе, а в MSVC это делается так
Код

#pragma pack ( push, 1 )
struct some_struct {
    char x;
    int y;
};
#pragma pack ( pop )

Попробуй, может и для gcc прокатит

А, я понял. В GCC есть 
Код

__attribute__ (packed)
 и 
Код

__attribute__ ((aligned(4)))

Спасибо, попробую, хотя не совсем понимаю как это может влиять.

Автор: xvr 26.9.2011, 14:13
Цитата(kurtis @  25.9.2011,  22:30 Найти цитируемый пост)
   memcpy(src_img, image, img_sz);
...
    memcpy(image, dest_img, img_sz);

А ваш image в курсе, что у него поменялась геометрия после вызова rotate_image()? Было 600х800, а стало 800х600.


Автор: kurtis 26.9.2011, 14:21
image это двоичные данные, которые интерпретируются в зависимости от заголовка, а в заголовке разрешение я меняю.

Автор: math64 26.9.2011, 14:36
Можете попробовать для начала более простые преобразования - например инверсию цвета пикселей. Для проверки, что Вы правильно его находите в bmp.

Автор: borisbn 26.9.2011, 14:41
Цитата(kurtis @  26.9.2011,  13:51 Найти цитируемый пост)
Спасибо, попробую, хотя не совсем понимаю как это может влиять.

sizeof( ваша_структура_заголовка_BMP ) будет отличаться от той, которая записана в файле из-за выравнивания, поэтому структуры должны быть packed

Цитата(math64 @  26.9.2011,  14:36 Найти цитируемый пост)
более простые преобразования - например инверсию цвета пикселей

инверсия цвета в 8-битном BMP - это не совсем простое преобразование. вернее, это не касается самого изображения, а меняется только таблица цветов

Автор: kurtis 26.9.2011, 14:42
Фух. Получилось.  smile 
Правда переделал через одномерный массив. Осталось только понять где накосячил с двухмерными массивами.

Код

unsigned char dest_img[img_sz];//rotated image
unsigned char src_img[img_sz];//source image

for (x = 0; x < x_size; x++)
    for (y = 0; y < y_size; y++)
        dest_img[y + x * y_size] = src_img[(x_size - x - 1)  + y * x_size];


Всем спасибо за помощь и моральную поддержку!

Автор: borisbn 26.9.2011, 17:13
Проблема была в этом
Цитата(kurtis @  25.9.2011,  22:30 Найти цитируемый пост)
 unsigned char src_img[x_size][y_size];//source image

Ты считал, что у исходного изображения x_size строк и y_size столбцов, а это правда не для исходного, а для повёрнутого изображения.
http://liveworkspace.org/code/aec2e27ad13a24de42d67b7cbc80b80a

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)