В данном приложении содержатся процедуры поддержки низкочастотной фильтрации растровых изображений и процедуры усреднения растровых изображений с понижением разрешения, а также тестовая программа демонстрирующая их работу.
Всего представлены две процедуры низкочастотной фильтрации V_fltr0 и V_fltr1, предназначенные для обработки изображений прямо в видеопамяти и с построчной буферизацией в оперативной памяти, соответственно. Последняя при модификации вспомогательных процедур доступа к изображению может обрабатывать картины, находящиеся в файле на внешнем носителе или просто в оперативной памяти.
Аналогично, представлены две процедуры усреднения изображения с понижением разрешения - V_fltr2 и V_fltr3.
При фильтрации и усреднении может использоваться одна из пяти предусмотренных масок фильтрации.
/*================================================== V_FILTR.C * В файле V_FILTR.C содержатся процедуры * поддержки фильтрации изображений: * * GetStr, PutStr - служебные * * V_fltr0 - фильтрует изображение в прямоугольной области, * работая прямо с видеопамятью * V_fltr1 - фильтрует изображение в прямоугольной области, * работая с буферами строк * V_fltr2 - усредняет картину по маске с понижением * разрешения, работая прямо с видеопамятью * V_fltr3 - усредняет картину по маске с понижением * разрешения, работая с буферами строк */ #include <alloc.h> #define GetMay getpixel #define PutMay putpixel static int Mask0[]= {1,1, 1,1 }, Mask1[]= {1,1,1, 1,1,1, 1,1,1 }, Mask2[]= {1,1,1, 1,2,1, 1,1,1 }, Mask3[]= {1,2,1, 2,4,2, 1,2,1 }, Mask4[]= {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 }, Mask5[]= {1,2, 3, 4, 3,2,1, 2,4, 6, 8, 6,4,2, 3,6, 9,12, 9,6,5, 4,8,12,16,12,8,4, 3,6, 9,12, 9,6,5, 2,4, 6, 8, 6,4,2, 1,2, 3, 4, 3,2,1 }, Mask_ln[]= {2, 3, 3, 3, 4, 7}, /* Размер маски */ Mask_st[]= {2, 2, 2, 2, 4, 4}, /* Шаг усреднения */ Mask_vl[]= {4, 9,10,16,16,256}, /* Сумма элементов */ *Mask_bg[]={ /* Адреса начал */ Mask0,Mask1,Mask2,Mask3,Mask4,Mask5 }; /*----------------------------------------------------- GetStr * Запрашивает фрагмент растровой строки из видеопамяти */ static void GetStr (st, Yst, Xn, Xk) char *st; int Yst, Xn, Xk; { while (Xn <= Xk) *st++= GetMay (Xn++, Yst); } /*----------------------------------------------------- PutStr * Записывает фрагмент растровой строки в видеопамять */ static void PutStr (st, Yst, Xn, Xk) char *st; int Yst, Xn, Xk; {while (Xn <= Xk) PutMay (Xn++, Yst, *st++); }
/*---------------------------------------------------- V_fltr0 * Фильтрует изображение в прямоугольной области, * работая прямо с видеопамятью * msknum = 0-5 - номер маски фильтра * Xn_source,Yn_source - окно исходного изображения * Xk_source,Xk_source * Xn_target,Yn_target - верхний левый угол результата */ void V_fltr0 (msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target) int msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target; { char *plut; /* Указатель палитры */ int *pi; /* Тек указат маски */ int pixel; /* Пиксел исх изображения */ int *Maska, /* Указатель маски */ Mask_Y,Mask_X, /* Размеры маски */ X_centr,Y_centr,/* Центр маски */ Mask_sum, /* Сумма элементов */ Xk, /* Предельные положения маски */ Yk, /* в исходной области */ s, sr, sg, sb, /* Скаляры для суммир в маской */ ii, jj, Xt, Yt; /* Запрос параметров маски */ Maska= Mask_bg[msknum]; /* Указатель маски */ Mask_Y= Mask_X= Mask_ln[msknum]; /* Размеры маски */ X_centr= Mask_X / 2; /* Центр маски */ Y_centr= Mask_Y / 2; Mask_sum= Mask_vl[msknum]; /* Сумма элементов */ /* Предельные положения маски в исходной области */ Xk= Xk_source+1-Mask_X; Yk= Yk_source+1-Mask_Y; /*------- Фильтрация с прямой работой с видеопамятью -------*/ for (Yt= Yn_source; Yt<=Yk; ++Yt) { for (Xt=Xn_source; Xt<=Xk; ++Xt) { pi= Maska; sr=0; sg=0; sb=0; /* Суммированные RGB*/ for (ii=0; ii<Mask_Y; ++ii) for (jj=0; jj<Mask_X; ++jj) { pixel= GetMay (Xt+jj, Yt+ii); plut= &V_pal256[pixel][0]; s= *pi++; /* Элемент маски */ sr+= (s * *plut++); /* Суммирование */ sg+= (s * *plut++); /* по цветам с */ sb+= (s * *plut++); /* весами маски */ } sr /= Mask_sum; sg /= Mask_sum; sb /= Mask_sum; /* Поиск элемента ТЦ, наиболее подходящего для данных R,G,B */ ii= V_clrint (sr, sg, sb); PutMay (Xn_target+(Xt-Xn_source)+X_centr, Yn_target+(Yt-Yn_source)+Y_centr, ii); } } } /* V_fltr0 */
/*---------------------------------------------------- V_fltr1 * Фильтрует изображение в прямоугольной области, * работая с буферами строк * msknum = 0-5 - номер маски фильтра * Xn_source,Yn_source - окно исходного изображения * Xk_source,Xk_source * Xn_target,Yn_target - верхний левый угол результата */ void V_fltr1 (msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target) int msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target; { char *plut; /* Указатель палитры */ int *pi; /* Тек указат маски */ int pixel; /* Пиксел исх изображения */ int *Maska, /* Указатель маски */ Mask_Y,Mask_X, /* Размеры маски */ X_centr,Y_centr,/* Центр маски */ Mask_sum, /* Сумма элементов */ Xk, /* Предельные положения маски */ Yk, /* в исходной области */ Dx_source, /* Размер строки исх изображения */ Ystr, /* Y тек читаемой строки изображ */ s, sr, sg, sb, /* Скаляры для суммир в маской */ ii, jj, Xt, Yt; char *ps, *sbuf, *pt, *tbuf, *ptstr[8]; Dx_source= Xk_source-Xn_source+1; /* Запрос параметров маски */ Maska= Mask_bg[msknum]; /* Указатель маски */ Mask_Y= Mask_X= Mask_ln[msknum]; /* Размеры маски */ X_centr= Mask_X / 2; /* Центр маски */ Y_centr= Mask_Y / 2; Mask_sum= Mask_vl[msknum]; /* Сумма элементов */ /* Предельные положения маски в исходной области */ Xk= Xk_source+1-Mask_X; Yk= Yk_source+1-Mask_Y; /* Заказ буферов */ if ((sbuf= malloc (Dx_source * Mask_Y)) == NULL) goto all; if ((tbuf= malloc (Dx_source)) == NULL) goto fr_sbuf; /*------- Фильтрация с использованием буферов строк --------*/ /* Подготовка массива указателей на строки * ptstr[0] --> последняя строка * ptstr[1] --> строка 0 * ptstr[2] --> строка 1 * и т.д. */ ps= sbuf; ii= Mask_Y; jj= 1; do { ptstr[jj]= ps; ps+= Dx_source; if (++jj == Mask_Y) jj= 0; } while (--ii > 0); /* Начальное чтение Mask_Y - 1 строк */ Ystr= Yn_source; for (ii=1; ii<Mask_Y; ++ii) GetStr (ptstr[ii], Ystr++, Xn_source, Xk_source); for (Yt= Yn_source; Yt<=Yk; ++Yt) { /* Запрос следующей строки и циклический сдвиг указателей */ GetStr (ps= ptstr[0], Ystr++, Xn_source, Xk_source); jj= Mask_Y-1; for (ii=0; ii<jj; ++ii) ptstr[ii]= ptstr[ii+1]; ptstr[jj]= ps; pt= tbuf; for (Xt=Xn_source; Xt<=Xk; ++Xt) { pi= Maska; sr=0; sg=0; sb=0; /* Суммированные RGB*/ for (ii=0; ii<Mask_Y; ++ii) { ps= ptstr[ii] + (Xt-Xn_source); for (jj=0; jj<Mask_X; ++jj) { plut= &V_pal256[*ps++ & 255][0]; s= *pi++; /* Элемент маски */ sr+= (s * *plut++); /* Суммирование */ sg+= (s * *plut++); /* по цветам с */ sb+= (s * *plut++); /* весами маски */ } } sr /= Mask_sum; sg /= Mask_sum; sb /= Mask_sum; /* Поиск элемента ТЦ, наиболее подходящего для данных R,G,B */ *pt++= V_clrint (sr, sg, sb); } PutStr (tbuf, /* Запись строки */ Yn_target + Y_centr + (Yt-Yn_source) , Xn_target + X_centr, Xn_target + X_centr + (--pt - tbuf)); } free (tbuf); fr_sbuf: free (sbuf); all:; } /* V_fltr1 */
/*---------------------------------------------------- V_fltr2 * Усредняет картину по маске с понижением разрешения, * работая прямо с видеопамятью * msknum = 0-5 - номер маски фильтра * Xn_source,Yn_source - окно исходного изображения * Xk_source,Xk_source * Xn_target,Yn_target - верхний левый угол результата */ void V_fltr2 (msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target) int msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target; { char *plut; /* Указатель палитры */ int *pi; /* Тек указат маски */ int pixel; /* Пиксел исх изображения */ int *Maska, /* Указатель маски */ Mask_Y,Mask_X, /* Размеры маски */ X_centr,Y_centr,/* Центр маски */ Mask_sum, /* Сумма элементов */ Xk, /* Предельные положения маски */ Yk, /* в исходной области */ s, sr, sg, sb, /* Скаляры для суммир в маской */ Xr,Yr, /* Координаты пиксела результата */ Sm, /* Сдвиг маски для обраб след точки */ ii, jj, Xt, Yt; /* Запрос параметров маски */ Maska= Mask_bg[msknum]; /* Указатель маски */ Mask_Y= Mask_X= Mask_ln[msknum]; /* Размеры маски */ X_centr= Mask_X / 2; /* Центр маски */ Y_centr= Mask_Y / 2; Mask_sum= Mask_vl[msknum]; /* Сумма элементов */ /* Предельные положения маски в исходной области */ Xk= Xk_source+1-Mask_X; Yk= Yk_source+1-Mask_Y; Yt= Yn_source; Yr= Yn_target+Y_centr; Sm= Mask_st[msknum]; /* Шаг усреднения*/ while (Yt <= Yk) { Xt=Xn_source; Xr= Xn_target+X_centr; while (Xt <= Xk) { pi= Maska; sr=0; sg=0; sb=0; /* Суммированные RGB*/ for (ii=0; ii<Mask_Y; ++ii) for (jj=0; jj<Mask_X; ++jj) { pixel= GetMay (Xt+jj, Yt+ii); plut= &V_pal256[pixel][0]; s= *pi++; /* Элемент маски */ sr+= (s * *plut++); /* Суммирование */ sg+= (s * *plut++); /* по цветам с */ sb+= (s * *plut++); /* весами маски */ } sr /= Mask_sum; sg /= Mask_sum; sb /= Mask_sum; /* Поиск элемента ТЦ, наиболее подходящего для данных R,G,B */ ii= V_clrint (sr, sg, sb); PutMay (Xr++, Yr, ii); Xt+= Sm; } Yt+= Sm; ++Yr; } } /* V_fltr2 */
/*---------------------------------------------------- V_fltr3 * Усредняет картину по маске с понижением разрешения, * работая с буферами строк * msknum = 0-5 - номер маски фильтра * Xn_source,Yn_source - окно исходного изображения * Xk_source,Xk_source * Xn_target,Yn_target - верхний левый угол результата */ void V_fltr3 (msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target) int msknum,Xn_source,Yn_source,Xk_source,Yk_source, Xn_target,Yn_target; { char *plut; /* Указатель палитры */ int *pi; /* Тек указат маски */ int pixel; /* Пиксел исх изображения */ int *Maska, /* Указатель маски */ Mask_Y,Mask_X, /* Размеры маски */ X_centr,Y_centr,/* Центр маски */ Mask_sum, /* Сумма элементов */ Xk, /* Предельные положения маски */ Yk, /* в исходной области */ Dx_source, /* Размер строки исх изображения */ s, sr, sg, sb, /* Скаляры для суммир в маской */ Xr,Yr, /* Координаты пиксела результата */ Sm, /* Сдвиг маски для обраб след точки */ ii, jj, Xt, Yt; char *ps, *sbuf, *pt, *tbuf, *ptstr[8]; Dx_source= Xk_source-Xn_source+1; /* Запрос параметров маски */ Maska= Mask_bg[msknum]; /* Указатель маски */ Mask_Y= Mask_X= Mask_ln[msknum]; /* Размеры маски */ X_centr= Mask_X / 2; /* Центр маски */ Y_centr= Mask_Y / 2; Mask_sum= Mask_vl[msknum]; /* Сумма элементов */ /* Предельные положения маски в исходной области */ Xk= Xk_source+1-Mask_X; Yk= Yk_source+1-Mask_Y; /* Заказ буферов */ if ((sbuf= malloc (Dx_source * Mask_Y)) == NULL) goto all; if ((tbuf= malloc (Dx_source/Mask_st[msknum]+16)) == NULL) goto fr_sbuf; /* Подготовка массива указателей на строки * ptstr[0] --> строка 0 * ptstr[1] --> строка 1 * ptstr[2] --> строка 2 * и т.д. */ ps= sbuf; for (ii=0; ii<Mask_Y; ++ii) { ptstr[ii]= ps; ps+= Dx_source; } Yt= Yn_source; Yr= Yn_target+Y_centr; Sm= Mask_st[msknum]; /* Шаг усреднения*/ while (Yt <= Yk) { for (ii=0; ii<Mask_Y; ++ii) /* Чтен исх строк */ GetStr (ptstr[ii], Yt+ii, Xn_source, Xk_source); Xt=Xn_source; pt= tbuf; while (Xt <= Xk) { pi= Maska; sr=0; sg=0; sb=0; /* Суммированные RGB*/ for (ii=0; ii<Mask_Y; ++ii) { ps= ptstr[ii] + (Xt-Xn_source); for (jj=0; jj<Mask_X; ++jj) { plut= &V_pal256[*ps++ & 255][0]; s= *pi++; /* Элемент маски */ sr+= (s * *plut++); /* Суммирование */ sg+= (s * *plut++); /* по цветам с */ sb+= (s * *plut++); /* весами маски */ } } sr /= Mask_sum; sg /= Mask_sum; sb /= Mask_sum; /* Поиск элемента ТЦ, наиболее подходящего для данных R,G,B */ *pt++= V_clrint (sr, sg, sb); Xt+= Sm; } PutStr (tbuf,Yr++, /* Запись строки */ Xn_target+X_centr, Xn_target+X_centr + (--pt - tbuf)); Yt+= Sm; } free (tbuf); fr_sbuf: free (sbuf); all:; } /* V_fltr3 */
/*================================================== T_FILTR.C * * ТЕСТ ФИЛЬТРАЦИИ * * Программа вначале строит два смещенных вектора * большими пикселами, затем последовательно для каждой * из пяти масок: * - фильтрует с непосредственным доступом к видеопамяти * - фильтрует с буферизацией растровых строк * - формирует усредненную картинку меньшего разрешения * с непосредственным доступом к видеопамяти * - формирует усредненную картинку меньшего разрешения * с буферизацией растровых строк * * После вывода очередной картинки ждет нажатия любой клавиши * * Виды масок: * 0: 1 1 1: 1 1 1 2: 1 1 1 3: 1 2 1 * 1 1 1 1 1 1 2 1 2 4 2 * 1 1 1 1 1 1 1 2 1 * * 4: 1 1 1 1 5: 1 2 3 4 3 2 1 * 1 1 1 1 2 4 6 8 6 4 2 * 1 1 1 1 3 6 9 12 9 6 5 * 1 1 1 1 4 8 12 16 12 8 4 * 3 6 9 12 9 6 5 * 2 4 6 8 6 4 2 * 1 2 3 4 3 2 1 */ #include "V_VECTOR.C" #include "VGA_256.C" #include "V_FILTR.C" #include <conio.h> #include <graphics.h> #include <stdio.h> #define VECTOR 0 /* 0/1 - фикс вектор/ввод координат */ /*------------------------------------------------------- Grid * Строит сетку 10*10 */ void Grid (void) { int Xn,Yn,Xk,Yk; setcolor (170); Xn= 0; Xk= getmaxx(); Yn= 0; Yk= getmaxy(); while (Xn <= Xk) {line (Xn,Yn,Xn,Yk); Xn+= 10; } Xn= 0; while (Yn <= Yk) {line (Xn,Yn,Xk,Yn); Yn+= 10; } } /* Grid */
/*---------------------------------------------- main Filtr */ void main (void) { int ii, jj, mov_lin, /* 0/1 - позиционир/отрезок */ Xn,Yn,Xk,Yk, /* Координаты отрезка */ fon= 140; /* Индекс фона */ int gdriver= DETECT, gmode; int Xn_source, Yn_source, /* Фильтруемая область */ Xk_source, Yk_source, Dx_source; int Xn_target, Yn_target, /* Результаты фильтрации */ Xk_target, Yk_target; int msknum; /* Номер текущей маски */ char *ps; V_ini256 (&gdriver, &gmode, ""); ps= (char *)V_pal256; for (ii=0; ii<=255; ++ii) { /* Ч/б палитра */ jj= ii / 4; *ps++= jj; *ps++= jj; *ps++= jj; setrgbpalette (ii, jj, jj, jj); } setbkcolor(fon); /* Очистка экрана */ cleardevice(); Xk= getmaxx(); Yk= getmaxy(); /* Начальные установки для фильтрации */ Xn_source= 0; /* Исходная область */ Yn_source= 0; Xk_source= (Xk + 1)/2 - 1; Yk_source= Yk; Xn_target= Xk_source + 1; /* Результ. область */ Yn_target= 0; Xk_target= Xk; Yk_target= Yk_source; Dx_source= Xk_source-Xn_source+1; /* X-размер исходной*/ #if VECTOR Grid (); mov_lin= 1; Xn= 0; Yn= 0; Xk= 0; Yk= 0; for (;;) { gotoxy (1, 1); printf(" \r"); printf("mov_lin Xk Yk= (%d %d %d) ? ", mov_lin, Xk, Yk); scanf ("%d%d%d", &mov_lin, &Xk, &Yk); if (mov_lin < 0) cleardevice(); else if (!mov_lin) Grid (); else { if (mov_lin & 1) V_DDA (0, 0, Xk, Yk); if (mov_lin & 2) V_Bre (0, 0, Xk, Yk); } } #else Xk= Dx_source / Pix_X - 1; Yk= (Yk_source-Yn_source+1) / Pix_Y - 1; V_DDA (Xn_source, Yn_source, Xk, Yk-17); V_Bre (Xn_source, Yn_source+17, Xk, Yk); getch(); #endif ii= 0xF; /* Обе фильтрации и оба сжатия */ setfillstyle (SOLID_FILL, fon); for (msknum=0; msknum<6; ++msknum) { if (ii & 1) { /* Фильтрация из видеоозу */ bar (Xn_target, Yn_target, Xk_target, Yk_target); V_fltr0 (msknum,Xn_source,Yn_source, Xk_source,Yk_source,Xn_target,Yn_target); getch (); } if (ii & 2) { /* Фильтрация из буферов */ bar (Xn_target, Yn_target, Xk_target, Yk_target); V_fltr1 (msknum,Xn_source,Yn_source, Xk_source,Yk_source,Xn_target,Yn_target); getch (); } if (ii & 4) { /* Сжатие из из видеоозу */ bar (Xn_target, Yn_target, Xk_target, Yk_target); V_fltr2 (msknum,Xn_source,Yn_source, Xk_source,Yk_source,Xn_target,Yn_target); getch (); } if (ii & 8) { /* Сжатие из буферов */ bar (Xn_target, Yn_target, Xk_target, Yk_target); V_fltr3 (msknum,Xn_source,Yn_source, Xk_source,Yk_source,Xn_target,Yn_target); getch (); } } closegraph(); } /* main */