Как сделать пикселирование изображения - PullRequest
2 голосов
/ 03 апреля 2019

Я пытаюсь пикселировать изображение в формате P6 PPM, выполнив следующие действия:

  1. Чтение изображения PPM в сетках 4x4
  2. Найти среднее значение цвета RGB для каждой сетки 4x4
  3. Записать в новый файл , установив для каждой сетки 4x4 пикселей в новом изображении среднее значение цвета RGB.

Файл PPM начинается в следующем формате:

P6 
# ignores comments in header 
width 
height 
max colour value

Моя проблема: Выходной файл изображения PPM (который я открываю с помощью редактора изображений GIMP, а также может быть открыт в любом текстовом редакторе, таком как Блокнот для просмотра необработанных данных) состоит из одного плоского цветового блока, когда вместо этого он должен напоминать своего рода мозаику.

Примечание: Сетка 4x4 может быть изменена, т. Е. Чем больше значение размеров сетки, тем более пикселируется выходное изображение. На мой код больше всего повлиял другой вопрос переполнения стека, где пользователь пытался сделать аналогичную реализацию в C #. Ссылка на этот вопрос: https://codereview.stackexchange.com/questions/140162/pixelate-image-with-average-cell-color

ОБНОВЛЕНИЕ: Вывод теперь, кажется, пикселирует первую 1/5 изображения, но остальная часть выходного изображения остается одним цветным блоком. Я думаю, что моя проблема заключается в том, что я рассматриваю клетки как пиксели в линейном порядке.

Моя попытка:

#include <stdio.h>
#include <assert.h>

//Struct to store RGB values 
typedef struct {
    unsigned char r, g, b;
} pixel;

int main()
{
    int y, x;               //Loop iteration variables
    int yy = 0;             //Loop iteration variables
    int xx = 0;             //Loop iteration variables
    char magic_number[10];  //Variable which reads P6 in the header 
    int w, h, m;            //Image dimension variables
    pixel currentPix;       //Current pixel variable 
    int avR;                //Red declaration
    int avG;                //Green declaration 
    int avB;                //Blue declarataion 
    int total;              //Loop iteration counter declaration 

    //Input file 
    FILE* f;
    f = fopen("Dog2048x2048.ppm", "r"); //Read PPM file 
    if (f == NULL)                      //Error notifiaction if file cannot be found 
    {
        fprintf(stderr, "ERROR: cannot open input file");
        getchar();
        exit(1);
    }
    //Scan the header of the PPM file to get the magic number (P6), width
    //height and max colour value 
    fscanf(f, "%s %d %d %d", &magic_number, &w, &h, &m);

    //initialize file for writing (open and header)
    FILE* f_output;
    f_output = fopen("some_file.ppm", "w");
    //fprintf(f_output, "%s %d %d %d", magic_number, w, h, m);
    fprintf(f_output, "P6\n%d %d\n255\n", w, h);
    if (f_output == NULL)                       //Error notifiaction if file cannot be found 
    {
        fprintf(stderr, "ERROR: cannot open output file");
        getchar();
        exit(1);
    }

    // Loop through the image in 4x4 cells.
    for (int yy = 0; yy < h && yy < h; yy += 4)
    {
        for (int xx = 0; xx < w && xx < w; xx += 4)
        {
            avR = 0;
            avG = 0;
            avB = 0;
            total = 0;

            // Store each color from the 4x4 cell into cellColors.
            for (int y = yy; y < yy + 4 && y < h; y++)
            {
                for (int x = xx; x < xx + 4 && x < w; x++)
                {
                    //Reads input file stream 
                    fread(&currentPix, 3, 1, f);

                    //Current pixels 
                    avR += currentPix.r;
                    avG += currentPix.g;
                    avB += currentPix.b;

                    //Counts loop iterations for later use in colour averaging
                    total++;

                }
            }
            //Average RGB values
            avR /= total; 
            avG /= total;
            avB /= total;

            // Go BACK over the 4x4 cell and set each pixel to the average color.
            for (int y = yy; y < yy + 4 && y < h; y++)
            {
                for (int x = xx; x < xx + 4 && x < w; x++)
                {
                    //Print out to new file 
                    fprintf(f_output, "%i %i %i\t", avR, avG, avB);
                }
            }
        }
        fprintf(f_output, "\n");
    }
    return 0;
}

1 Ответ

2 голосов
/ 06 апреля 2019

Ваша основная ошибка заключается в том, что вы предполагаете, что вы читаете и пишете 4 × 4 блока пикселей, в то же время фактически обращаясь к пиксельным данным линейно;Ваше подозрение верно.

Рассмотрим следующий пример.Пусть будет одноканальное изображение 12 × 4:

01 02 03 04 05 06 07 08 09 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32 33 34 35 36
37 38 39 40 41 42 43 44 45 46 47 48

Каждый из пикселей имеет цвет, равный его позиции в файле PPM.

Теперь это пиксели, которые выожидают чтения при пикселировании первого блока 4 × 4:

01 02 03 04
13 14 15 16
25 26 27 28
37 38 39 40

И это те пиксели, которые фактически читаются путем последовательного выполнения fread():

01 02 03 04 05 06 07 08 09 10 11 12
13 14 15 16

Так что в конечном итогеВы рассматриваете входное изображение так, как если бы оно выглядело так:

01 02 03 04 05 06 07 08 09 10 11 12
13 14 15 16                                 01 02 03 04   17 18 19 20   33 34 35 36
            17 18 19 20 21 22 23 24   -->   05 06 07 08   21 22 23 24   37 38 39 40
25 26 27 28 29 30 31 32                     09 10 11 12   25 26 27 28   41 42 43 44
                        33 34 35 36         13 14 15 16   29 30 31 32   45 46 47 48
37 38 39 40 41 42 43 44 45 46 47 48

вместо:

01 02 03 04   05 06 07 08   09 10 11 12
13 14 15 16   17 18 19 20   21 22 23 24
25 26 27 28   29 30 31 32   33 34 35 36
37 38 39 40   41 42 43 44   45 46 47 48

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

...