§ Квантование изображения

eebd9f0703ef6813c5815ecaab4136c1.png
1#include <qblib.c>
2
3int main(int argc, char* argv[]) {
4
5    screen(13);
6    ditherpal();
7
8    float t = 0;
9    while (sdlevent(EVT_REDRAW)) {
10
11        cls();
12        useindex(0);
13
14        for (int i = 0; i < 192; i++)
15        for (int j = 0; j < 320; j++) {
16
17            vec2 src_r = {160 + sin(t)*100, 100 + cos(t)*100};
18            vec2 src_g = {160 - sin(t)*100, 100 + cos(t)*100};
19            vec2 src_b = {160 + sin(t)*100, 100 - cos(t)*100};
20
21            int r = 255 - sqrt(pow(j-src_r.x, 2) + pow(i-src_r.y, 2));
22            int g = 255 - sqrt(pow(j-src_g.x, 2) + pow(i-src_g.y, 2));
23            int b = 255 - sqrt(pow(j-src_b.x, 2) + pow(i-src_b.y, 2));
24
25            pset(j, i, rgb(r, g, b));
26        }
27
28        t = t + 0.01;
29        int middle = 160 + 160*sin(t);
30        line(middle, 0, middle, 192, 0xffffff);
31
32        // Сам алгоритм
33        ditherect(0, 0, middle, 192, 1);
34    }
35
36    return 0;
37}
Найти ближайший цвет
1int dither_search_nearest(rgbf& incl) {
2
3    float dist_min = 4 * pow(256, 2);
4    int   dist_col = 0;
5
6    // dospal
7    for (int i = 0; i < 256; i++) {
8
9        // Сравниваемый цвет
10        struct rgbf cl = palette[i];
11
12        // Дистанция между точками (r`-r)^2 + (g`-g)^2 + (b`-b)^2
13        float dist = pow(incl.r - cl.r, 2) +
14                     pow(incl.g - cl.g, 2) +
15                     pow(incl.b - cl.b, 2);
16
17        if (dist < dist_min) {
18
19            dist_min = dist;
20            dist_col = i;
21        }
22    }
23
24    return dist_col;
25}
Процедура дизеринга (left, top)-(right, bottom), dith=0 (nearest) 1(dithered)
1void ditherect(int left, int top, int right, int bottom, int dith) {
2
3    rgbf ws[QB_MAX_WIDTH][QB_MAX_HEIGHT];
4    int  idx[QB_MAX_WIDTH][QB_MAX_HEIGHT];
5
6    // Копировать целочисленные точки в не целочисленные
7    for (int y = top; y < bottom; y++)
8    for (int x = left; x < right;  x++) {
9
10        ws[x][y] = {
11            (float) qb_pixels[x][y].r,
12            (float) qb_pixels[x][y].g,
13            (float) qb_pixels[x][y].b
14        };
15    }
16
17    // Выполнить дизеринг
18    for (int y = top;  y < bottom; y++)
19    for (int x = left; x < right;  x++) {
20
21        // Старые цвета
22        rgbf old = ws[x][y];
23
24        // Поиск ближайшего цвета из палитры
25        int color_id = dither_search_nearest(old);
26
27        // Полученный индекс цвета
28        idx[x][y] = color_id;
29
30        // Учесть ошибки квантования
31        if (dith) {
32
33            // Заменить на новый цвет (из палитры)
34            rgbf ncl = palette[];
35
36            // Отметить цвет @todo может это вообще не надо
37            ws[x][y] = ncl;
38
39            // Вычисляем ошибку квантования
40            rgbf quant;
41
42            quant.r = (old.r - ncl.r);
43            quant.g = (old.g - ncl.g);
44            quant.b = (old.b - ncl.b);
45
46            //   x 7
47            // 3 5 1
48
49            // [+1, +0] 7/16
50            if (x + 1 < right) {
51
52                ws[x + 1][y].r += (quant.r * 7.0/16.0);
53                ws[x + 1][y].g += (quant.g * 7.0/16.0);
54                ws[x + 1][y].b += (quant.b * 7.0/16.0);
55            }
56
57            // [-1, +1] 3/16
58            if (x - 1 >= 0 && y + 1 < bottom) {
59
60                ws[x - 1][y + 1].r += (quant.r * 3.0/16.0);
61                ws[x - 1][y + 1].g += (quant.g * 3.0/16.0);
62                ws[x - 1][y + 1].b += (quant.b * 3.0/16.0);
63            }
64
65            // [+0, +1] 5/16
66            if (y + 1 < bottom) {
67
68                ws[x][y + 1].r += (quant.r * 5.0/16.0);
69                ws[x][y + 1].g += (quant.g * 5.0/16.0);
70                ws[x][y + 1].b += (quant.b * 5.0/16.0);
71            }
72
73            // [+1, +1] 1/16
74            if (x + 1 < right && y + 1 < bottom) {
75
76                ws[x + 1][y + 1].r += (quant.r * 1.0/16.0);
77                ws[x + 1][y + 1].g += (quant.g * 1.0/16.0);
78                ws[x + 1][y + 1].b += (quant.b * 1.0/16.0);
79            }
80        }
81    }
82}