2015-04-12 4 views
0

Я создал хорошую функцию для вращения растровых изображений в градусах. Проблема, возникшая после некоторых оптимизаций, заключается в том, что выходное изображение становится слегка перепозиционированным во время вращения.Функция поворота растрового изображения в градусах работает довольно быстро, но репозиции выводят изображение

Я записал 360 ° вращающийся video, чтобы вы могли видеть, что я хочу сказать. А код следующим образом:

#define OFFSET_OF_ID  (0x0) 
#define OFFSET_OF_SIZE  (0x2) 
#define OFFSET_OF_PIXELS (0xA) 
#define OFFSET_OF_NDIB  (0xE) 
#define OFFSET_OF_WIDTH  (0x12) 
#define OFFSET_OF_HEIGHT (0x16) 
#define OFFSET_OF_BPP  (0x1C) 
#define OFFSET_OF_NRAW  (0x22) 

typedef unsigned char byte, pixel[3]; 
typedef unsigned short word; 
typedef unsigned long dword; 
typedef unsigned long long ddword; 

byte* 
bmp_rotate 
(byte *buffer, float angle) 
{ 
    const dword src_width = *((dword*)&buffer[OFFSET_OF_WIDTH]); 
    const dword src_height = *((dword*)&buffer[OFFSET_OF_HEIGHT]); 
    const dword src_nraw = *((dword*)&buffer[OFFSET_OF_NRAW]); 
    const dword src_pixels = *((dword*)&buffer[OFFSET_OF_PIXELS]); 
    const dword src_bpp = *((dword*)&buffer[OFFSET_OF_BPP]); 

    const dword single = src_bpp/8; 
    const dword row = src_width * single; 
    dword rowsize = (row % 4) ? (row + 4 - row % 4) : (row); 
    byte *dest = calloc(src_pixels + src_nraw, sizeof(byte)); 

    double midX, midY; 
    int i, j; 
    double sin_angle = sin(angle); 
    double cos_angle = cos(angle); 

    midX = src_width/2.0f; 
    midY = src_height/2.0f; 
    memcpy(dest, buffer, src_pixels); 

    for(j = 0; j < src_height; j++) 
    { 
     dword dest_offset = src_pixels + j * rowsize; 
     double deltaY = j - midY; 
     double deltaX = 0 - midX; 
     double x_computation, y_computation; 

     x_computation = midX + deltaX * cos_angle + deltaY * sin_angle + 0.5f; 
     y_computation = midY - deltaX * sin_angle + deltaY * cos_angle + 0.5f; 


     for(i = 0; i < src_width; i++) 
     { 
      ddword rotX = x_computation; 
      ddword rotY = y_computation; 

      if(rotX >= 0 && rotX < src_width && rotY >= 0 && rotY < src_height) 
      { 
       ddword src_offset = src_pixels + rotY * rowsize + rotX * single; 

       memcpy(&dest[dest_offset], &buffer[src_offset], sizeof(pixel)); 

      } 
      x_computation += cos_angle; 
      y_computation -= sin_angle; 
      dest_offset += single; 
     } 
    } 
    return dest; 
} 

Что вызывает это непристойное поведение?

+0

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

+0

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

+0

Вы центр растрового изображения - это центр вращения, ширина и высота нечетны? Можете ли вы попробовать с крестом, чтобы выделить глюк? –

ответ

1

Я не могу видеть вашу проблему в видео, но я предполагаю, что полное вращение на 360 ° достигается при различных частичных вращениях.

Если посмотреть на повороте на 180 °, смещение становится ясно: Синус равно 0 и косинус − 1. повернуты координаты левого верхнего угла (0,0) затем:

x' = xm + (x - xm) * cosa + (y - ym) * sina = xm + xm = w 
y' = ym - (x - xm) * sina + (y - ym) * cosa = ym + ym = h 

Координаты (w, h) являются исключительными правыми и нижними границами.

Ваши рабочие координаты являются действительными числами. Целочисленные значения описывают левую и верхнюю координаты. Преобразование (положительных) реальных коордов в целые числа приведет к усечению дробной части и получению индексов пикселей на основе нуля.

Вы добавляете 0.5 к своим рабочим координатам в целевом пространстве один раз, чтобы обеспечить правильный расчет индекса. Вместо этого, вы должны рассматривать реальные координаты всех точек в середине этого пикселя:

x(i) = i + 0.5 
y(j) = j + 0.5 

Все ваши расчеты остаются правильными, за исключением:

double deltaY = j + 0.5 - midY; 
double deltaX = 0 + 0.5 - midX; 

x_computation = midX + deltaX * cos_angle + deltaY * sin_angle; 
y_computation = midY - deltaX * sin_angle + deltaY * cos_angle; 

Идея заключается в том, чтобы рассматривать пиксель координаты в пиксельных центров как в исходном, так и в целевом пространстве. Правильное представление в целевом пространстве достигается автоматически путем округления к нулю при преобразовании в целое.

+0

Это исправило это. Также мне, возможно, пришлось загрузить правильную версию для сравнения ... потому что смещение в реальной жизни практически не заметно. Я не уверен, что мой английский слишком плохой, или я действительно не знаю, как его более правильно описать. – Malina

0

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

 Смежные вопросы

  • Нет связанных вопросов^_^