масштабирование, изменение размера структуры BMP, программирование c - PullRequest
0 голосов
/ 30 апреля 2020

Моя задача - масштабировать изображение BMP с заданным коэффициентом:

stream: base64 Код изображения BMP:

Qk1CAAAAAAAAADYAAAAoAAAABAAAAAEAAAABABgAAAAAAAwAAAAjLgAAIy4AAAAAAAAAAAAA/////wAAAP8AAAAA

масштаб. c

struct bmp_image* scale(const struct bmp_image* image, float factor){
    if(image == NULL || factor <= 0){
        return NULL;
    }

    .........
    int width = bmp->header->width;
    int height = bmp->header->height;
    int widthNew = (int)round((float)width * factor);
    int heightNew = (int)round((float)height * factor);


    for (uint32_t y = 0; y < heightNew; y++){
        for(uint32_t z = 0; z< widthNew; z++){
            bmp->data[(y*widthNew)+z].red=image->data[(int)(floor((float)y/(float)factor)*width+floor((float)z/(float)factor))].red;
            bmp->data[(y*widthNew)+z].green=image->data[(int)(floor((float)y/(float)factor)*width+floor((float)z/(float)factor))].green;
            bmp->data[(y*widthNew)+z].blue=image->data[(int)(floor((float)y/(float)factor)*width+floor((float)z/(float)factor))].blue;
        }
    }

    return bmp;     
}

основной. c

FILE *output_p8 = fopen("scale.bmp", "w");
    struct bmp_image* newimage8 = NULL;
    newimage8 = scale(image, 1.025656);  
    free_bmp_image(image);    
    write_bmp(output_p8,newimage8);
    free_bmp_image(newimage8);    
    fclose(output_p8);

вывод данных, которые я получил после этого:

ffffff ffffff ff0000 00ff00

данные, которые я должен иметь:

ffffff ff0000 00ff00 000000

есть предложения?

1 Ответ

0 голосов
/ 30 апреля 2020

Когда вы вычисляете новые измерения, вы выполняете вычисление с плавающей запятой и затем округляете до ближайшего целого числа:

int widthNew = round(width * factor);

(Вам не нужны приведения: factor - это float и результат умножения целого числа на float также является float; widthNew является целым числом, поэтому результат float должен быть преобразован в целое число.)

Потому что при округлении ваш эффективный коэффициент масштабирования (назовем его factor_eff) может отличаться от номинального factor:

float factor_eff = (float) widthNew / width;

В вашем случае:

factor == 1.025656;
width == 4;
widthNew == round(1.025656 * 4) == round(4.102624) == 4;
factor_eff = 4.0 / 4 == 1.0;

Но вы делаете свое вычисления индекса со старым коэффициентом:

int zNew = floor(z / factor);

(Опять же, вам не нужен приведение.) Для ваших четырех z индексов это даст:

z == 0;    zNew == floor(0 / 1.025656) == floor(0.0)       == 0;   // ok
z == 1;    zNew == floor(1 / 1.025656) ~~ floor(0.9749858) == 0;   // ! should be 1
z == 2;    zNew == floor(2 / 1.025656) ~~ floor(1.9499715) == 1;   // ! should be 2
z == 3;    zNew == floor(3 / 1.025656) ~~ floor(2.9249573) == 2;   // ! should be 3

Вы можете исправить коэффициент с плавающей точкой, но я думаю, что лучше (и быстрее) вычислить ваши новые индексы с целочисленным арифметическим c:

int zNew = z * width / widthNew;
int yNew = y * height / heightNew;

Сначала убедитесь, что вы выполняете умножение. Этот метод должен быть безопасным для размеров до 46 000.

...