Лабораторная работа 2_2011.ppt
- Количество слайдов: 38
Преобразование изображений анализ кода
2
Порядок работы: • загрузить изображение-оригинал ("original"); • определить основные его характеристики; • вывести отдельные каналы изображения: r_original, g_original, b_original; • создать серую копию оригинала ("grey_original"); 3
• создать шаблон изображения "image", соответствующий характеристикам "grey_original"; • последовательно заполнить шаблон "image" пикселами изображения согласно заданной схеме преобразований (формула), всякий раз сохраняя результат в соответствующем файле изображения ("image 1. bmp", . . . 2. bmp, . . . 3. bmp, . . . ); • использовать с х е м ы обработки изобра- жения: инверсия, бинаризация, сдвиг etc. 4
Подключаемые файлы: В файл stdfx. h включены: #pragma once #include "targetver. h“ #include <stdio. h> #include <tchar. h> //подключаемые файлы #include <iostream> #include <conio. h>// Для _getwch(); 5
подключаемые файлы //=================== #include <cv. h> #include <highgui. h> //=================== #define _USE_MATH_DEFINES #include <math. h> #include <ctime>//random 6
Вспомогательная функция • //Прототип функции пользователя для просмотра изображения. • //Служить исключительно для сокращения кода • void lookimag (Ipl. Image* myimage ); • Определение: ========================= • void lookimag(Ipl. Image* myimage ){ • // создаем окно для отображения img • cv. Named. Window("my window", CV_WINDOW_AUTOSIZE); • //. . . и показываем myimage в созданном окне • cv. Show. Image("my window", myimage); • //ждем нажатия клавиши • cv. Wait. Key(0); • //закрываем окно, но не освобождаем память myimage! • cv. Destroy. Window("my window"); • } • ============================== 7
Функция main: #include "stdafx. h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { <. . . блоки программ. . . . > _getwch(); return 0; } 8
Загружаем изображение оригинал char* filename="e: \chipsaoriginal. bmp"; //сохраняем имя Ipl. Image* original = cv. Load. Image(filename, 1); //загружаем cout<<"n. Originaln"; lookimag(original); //показываем. . . int mwx, mhy; //считываем и с о х р а н я е м характеристики как переменные mwx=(original->width); //матрица, ширина изображения, ось х mhy=(original->height); //матрица, высота изображения, ось y 9
Свойства изображения (в стиле С) printf( "image: %sn", filename); printf( "channels: %dn", original->n. Channels ); printf( "pixel depth: %d bitsn", original->depth ); printf( "width (mwx): %d pixelsn", original->width ); printf( "height(mhy): %d pixelsn", original->height ); printf( "image size: %d bytesn", original->image. Size ); printf( "width step: %d bytesn", original->width. Step ); 10
Выделение цветовых каналов //создаем три шаблона изобажения для трех каналов //r_original, g_original, b_original Ipl. Image* r = cv. Create. Image(cv. Size(mwx, mhy), IPL_DEPTH_8 U, 1 ); // вместо известных cv. Size(mwx, mhy) можжно было использовать // cv. Get. Size(original). NB! Сv -класс, cv - конструктор! //сократим код используя новую переменную: Cv. Size size = cv. Size(mwx, mhy); Ipl. Image* g = cv. Create. Image(size, IPL_DEPTH_8 U, 1 ); Ipl. Image* b = cv. Create. Image(size, IPL_DEPTH_8 U, 1 ); // разделим изображение на цветовые слои: cv. Split( original, r, g, b, NULL ); 11
Вывод по слоям (каналам) cout<<"n. Redn"; cout<<"Greenn"; cout<<"Bluen"; lookimag(r); lookimag(g); lookimag(b); 12
Поэлементное сложение яркостей Ipl. Image* s = cv. Create. Image( cv. Get. Size(original), IPL_DEPTH_8 U, 1 ); //выполним поэлементное сложение каналов cv. Add(r, g, s, 0); cv. Add(b, s, s, 0); cout<<"R+G+Bn"; lookimag(s); //очевидно, что яркости сместились к белому, почему? 13
Пропорциональное сложение //поэтому выполним п р о п о р ц и о н а л ь н о е сложение: Ipl. Image* grey_original = cv. Create. Image(cv. Get. Size(original), IPL_DEPTH_8 U, 1 ); cv. Add. Weighted( r, 1. /3. , g, 1. /3. , 0. 0, grey_original ); cv. Add. Weighted( grey_original, 2. /3. , b, 1. /3. , 0. 0, grey_original ); cout<<"Grey Originaln"; printf( "channels: %dn", grey_original->n. Channels ); printf( "pixel depth: %d bitsn", grey_original->depth ); lookimag(grey_original); //следующий слайд, справа //освободим память сохранив только рабочий шаблон cv. Release. Image( &r ); cv. Release. Image( &g ); cv. Release. Image( &b ); cv. Release. Image( &s ); 14
Простое и взвешенное (пропорциональное) сложение 15
Пустой шаблон image //создадим одноканальный пустой рабочий шаблон image Ipl. Image* image = cv. Create. Image( cv. Get. Size(grey_original), IPL_DEPTH_8 U, 1 ); cout<<"Empty Screenn"; lookimag(image); 16
Матрица помех // Заполним шаблон случайными значениями яркости Cv. RNG rng_state = cv. RNG(0 xffff); //стартовая точка rng_state, ее тип-класс — Cv. RNG /* создаем массив values случайных значений указателей: */ Cv. Mat* values = cv. Create. Mat(mhy, mwx, CV_8 UC 1); //8 bit-unsign-1 c. /* генерируем значения элементов д в у м е р н о г о массива values нормальным распределением*/ cv. Rand. Arr(&rng_state, values, CV_RAND_NORMAL, cv. Real. Scalar(100), // "среднее" нормального распределения cv. Real. Scalar(30) // отклонение "сигма" (корень из дисперсии) ); //////////////////////////////// 17
Матрица помех (2) int i, j; //i--номера строк 0. . . (mhy-1), j -- номера колонок; //изображение считывается по строкам, т. е. for(i = 0; i < mhy; i++ ) // строки с 0 -й до последней нижней mhy for(j = 0; j < mwx ; j++ ) { //колонки с 0 -й до крайней правой mwx // Выбираем все подряд яркости из массива values. . . float value = *(float*)cv. Ptr 2 D(values, i, j, 0); //. . . и вставляем их п о д р я д в изображение image *((float*)cv. Ptr 2 D(image, i, j, 0 )) = value; } cout<<"Random Screenn"; lookimag(image); //экран помех // отличия от пустого есть, но для серого → отчетливо видны на экране 18
Матрица помех (3) Обратите внимание на отличия в заполнении изображения. . . 19
Заполнение image пикселами исходника • // Заполним image пикселами исходного изображения • for(i = 0; i < mhy; i++ )// строки с 0 -й до последней нижней mhy • for(j = 0; j < mwx ; j++ ) {//колонки с 0 -й до крайней правой mwx • // иногда можно int value, если использ. целые • int value = *(int*)cv. Ptr 2 D(grey_original, i, j, 0); • *((int*)cv. Ptr 2 D(image, i, j, 0 )) = value; • } • cout<<"Paste Grey image to screenn"; • lookimag(image); 20
Пустой шаблон заполнили пикселами «исходника» . В нашем случае - grey_original 21
Инверсия for(i = 0; i < mhy; i++ ) // строки с 0 -й до последней нижней mhy for(j = 0; j < mwx ; j++ ) { //колонки с 0 -й до крайней правой mwx int x = *(int*)cv. Ptr 2 D(grey_original, i, j, 0); int value = 255 -x; *((int*)cv. Ptr 2 D(image, i, j, 0 )) = value; } cout<<"Inverse imagen"; lookimag(image); //сохраним битовое image в виде копии изображения Ipl. Image* image_bin = cv. Clone. Image(image); 22
Инверсия 23
Создание области интересов (ROI) на изображении char* imagename="e: \airplane. bmp"; //сохраняем имя //загружаем и смотрим в цвете: RGB = 1, "как есть" =3, серый =2; // NB! обратить внимание на изменение числа каналов! Ipl. Image* airplane_color = cv. Load. Image(imagename, 3); cout<<"nairplane_colorn"; printf( "channels: %dn", airplane_color->n. Channels ); printf( "pixel depth: %d bitsn", airplane_color->depth ); lookimag(airplane_color); cv. Release. Image( &airplane_color ); 24
//загружаем как Grey: CV LOAD IMAGE GRAYSCALE Ipl. Image* airplane = cv. Load. Image(imagename, 2); cout<<"nairplane Greyn"; printf( "channels: %dn", airplane->n. Channels ); printf( "pixel depth: %d bitsn", airplane->depth ); lookimag(airplane); //укажем область интересов ROI, которую можно сохранить отдельно //конструктор cv. Set. Image. ROI(src, cv. Rect(x, y, width, height)); cv. Set. Image. ROI(airplane, cv. Rect(215, 200, 200)); //Обратить внимание - в каком квадранте выделена область cout<<"nairplane ROIn"; lookimag(airplane); 25
26
Восстановим рисунок… cv. Reset. Image. ROI(airplane); //проверим. . . cout<<"Reset airplanen"; lookimag(airplane); //освободим память, если myroi больше не нужен cv. Release. Image( &myroi ); cv. Release. Image( &airplane ); 27
Повторная загрузка З а г р у ж а е м изображение-оригинал как с е р о е char* filename="e: \chipsaoriginal. bmp"; //сохраняем имя Ipl. Image* original = cv. Load. Image(filename, 2); //загружаем как серый cout<<"n. Originaln"; lookimag(original); //не показано (то же, что и "сработано вручную") //==== Сохраняем изображение в файл ======= cv. Save. Image("e: \chipsagrey. bmp", original); //Проверить!!! // Создаем одноканальный пустой рабочий шаблон image === Ipl. Image* image = cv. Create. Image( cv. Get. Size(original), IPL_DEPTH_8 U, 1 ); cout<<"Empty Screenn"; lookimag(image); //не показано (то же, что и "сработано вручную") 28
Бинаризация printf( "width step: %d bytesn", image->width. Step ); for(i = 0; i < mhy; i++ )// строки с 0 -й до последней нижней mhy for(j = 0; j < mwx ; j++ ) {//колонки с 0 -й до крайней правой mwx //NB! Пояснить, почему тип uchar, а не int uchar x = *(uchar*)cv. Ptr 2 D(original, i, j, 0); uchar value = (x <128 ? 0: 255); *((uchar*)cv. Ptr 2 D(image, i, j, 0 )) = value; } cout<<"Binare imagen"; lookimag(image); //Для сравнения, справа "правильная" бинаризация по нескольким пикс. 29
Бинаризация 30
Бинаризация 2 На изображении нет "серого", только разная плотность размещения точек. А как размещается растр при типографском наборе? . . 31
Перемещение Ipl. Image* copy_original = cv. Clone. Image(original); // сдвинем изображение на 100 пикселов for(i = 0; i < mhy; i++ )// строки с 0 -й до последней нижней mhy for(j = 0; j < mwx ; j++ ) {//колонки с 0 -й до крайней правой mwx int x 1= *(int*)cv. Ptr 2 D(original, i, j, 0); int x 2; if(i<100||j<100) x 2 = 0; else x 2 =*(int*)cv. Ptr 2 D(original, i-100, j-100, 0); //не забывать про модификацию значений, если они выходят за тип U 8 int value = (i<100 ||j < 100? x 1: x 2); *((int*)cv. Ptr 2 D(copy_original, i, j, 0 )) = value; } lookimag(copy_original); //cv. Release. Image( ©_original ); используется ниже! 32
“Move” на фоне основного изображения 33
Контуры изображения // сдвинем изображение на 1 пиксел for(i = 0; i < mhy; i++ )// строки с 0 -й до последней нижней mhy for(j = 0; j < mwx ; j++ ) {//колонки с 0 -й до крайней правой mwx uchar x 1= *(uchar*)cv. Ptr 2 D(original, i, j, 0); uchar x 2; //или long int if(i<1||j<1) x 2 = 0; else x 2 =*(uchar*)cv. Ptr 2 D(original, i-1, j-1, 0); //не забывать про значения, если они выходят за объявлеый тип U 8 uchar value = (abs(x 1 -x 2)<(x 1+x 2)/8? 0: 255); *((uchar*)cv. Ptr 2 D(copy_original, i, j, 0 )) = value; } cout<<"CONTOURn"; lookimag(copy_original); //cv. Release. Image( ©_original ); //===============================| 34
порог = 10 35
порог = 20 36
порог =(х1 -х2)/8 37
The END 38
Лабораторная работа 2_2011.ppt