2013-08-16 3 views
1

Я делаю программу изменения размера изображения на C, и в настоящий момент у меня возникают проблемы с функцией Bilinear Interpolation (это один из многих, которые я использую). Эта проблема возникает только для 16-битных растровых изображений. Если я использую 24-разрядные версии, она идеально их изменяет.Bilinear Interpolation image resizing marks & 'splotches'

Вот мой код для билинейной интерполяции. n_w и n_h являются новые значения ширины и высоты изображения:

#define getelm(x) (((pix+index)->x)*(1-xdiff)*(1-ydiff))+(((pix+index+1)->x)*(xdiff)*(1-ydiff))+(((pix+index+o_w)->x)*(1-xdiff)*(ydiff))+((pix+index+o_w+1)->x)*xdiff*ydiff 

int pad = (2*n_w) & 3; 
if (pad) 
pad = 4-pad; 
uint16_t *buffer; 
if (buf) 
buffer = malloc(2*n_w); 
for (i = 0; i < n_h; i++) { 
    for (j = 0; j < n_w; j++) { 
     x = (int)(j*xrat); 
     y = (int)(i*yrat); 
     xdiff = (xrat*j)-x; 
     ydiff = (yrat*i)-y; 
     index = y*o_w+x; 
     uint16_t container = 0; 
     container |= (int)(round(getelm(b))) << 11; 
     container |= (int)(round(getelm(g))) << 5; 
     container |= (int)round(getelm(r)); 
     if (buf) 
      *(buffer+j) = container; 
     else 
      fwrite(&container, 1, 2, dest); 
    } 
    if (buf) 
     fwrite(buffer, 1, 2*n_w, dest); 
     fwrite(&pad, 1, pad, dest); 
} 

Моя 24-битная версия этого кода (где разница лишь в том, что контейнер не используется, а вместо 3 8-разрядных целых чисел УДЕРЖИВАЙТЕ RGB значения) прекрасно работает.

Этот код, однако, дает странные результаты. Посмотрите на изображение ниже: Original image

При изменении размера этого, он дает мне эту спину: Resized image

Я не могу понять, почему это будет происходить, особенно когда он работает на 24-битных растровых изображений, а также что некоторые другие алгоритмы изменения размера (например, Nearest Neighbor) работают с 16-бит так же, как это должно быть.

EDIT: Я не думаю, что это проблема переполнения, потому что, добавив следующий код не дает никакого вывода при запуске:

if (MAX((int)(getelm(b)), 31) > 31) 
    printf("blue overflow: %.10f\n", (getelm(b))); 
if (MAX((int)(getelm(g)), 63) > 63) 
    printf("green overflow: %.10f\n", (getelm(g))); 
if (MAX((int)(getelm(r)), 31) > 31) 
    printf("red overflow: %.10f\n", (getelm(r))); 

EDIT 2: Я не думаю, что это сгущенного проблема либо, это ничего не делает:

if ((getelm(b)) < 0 || (getelm(g)) < 0 || (getelm(r)) < 0) 
    printf("Underflow\n"); 
+0

Вы пробовали проверить результат getelem(), чтобы убедиться, что он имеет соответствующую ширину и не перетекает за пределы ожидаемого диапазона? Это объясняет избыточные пиксели и тот факт, что он работает в 24 бит. – Sniggerfardimungus

+0

См. Мое редактирование, спасибо –

+0

И что, если вы проверите * underflow *?Отрицательное значение будет установлено на max после литья без знака. – usr2564301

ответ

2

Предполагая, что данные в pix не имеют тип

struct 
{ 
    uint16_t r : 5; 
    uint16_t g : 6; 
    uint16_t b : 5; 
}; 

Ошибка при подсчете container. Использование round не всегда предотвратит переполнение. Следующий код будет:

uint16_t container = 0; 
     container |= ((int)(round(getelm(b))) & 31) << 11; // optionally 
     container |= ((int)(round(getelm(g))) & 63) << 5; 
     container |= ((int)round(getelm(r)) & 31); 

или сохранить максимум потерянной информации:

uint16_t container = 0; 
     container |= min((int)(round(getelm(b))) , 31) << 11; 
     container |= min(((int)(round(getelm(g))) , 63) << 5; 
     container |= min(((int)round(getelm(r)) , 31); 

EDIT

С pix->r, pix->g и pix->b приходят из значений 8bit, такая же аргументация примените к ним, и их диапазон необходимо проверить.

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

Чтобы найти ошибку, я рекомендую разбивать код на небольшие функции и утверждать ввод каждого из них.

+0

Данные в pix не связаны с структурой, которая имеет предопределенный размер битового поля, поскольку для 24-битных значений используется одна и та же структура. Он просто считывает каждое значение 5, 6 и 5 бит в соответствующую переменную uint8_t. Поскольку они меньше 8 бит, они подходят, поэтому нет необходимости в дополнительной структуре. Я не могу заставить код выше работать, но нет никакой разницы. –

+0

Извините, наблюдение, которое я сделал, не помогает. Я отредактирую с более общей информацией, которая могла бы помочь! –