Read the book: «Мультимедийное Программирование OpenCV»
Мультимедийное программирование

07.15.2019
Профессор: Orazdurdyyev Serdar Begnarlyevich
Внедрение цифровой обработки изображений / Introduction of Digital Image Processing
Выборка и квантование / Sampling and Quantization

Continuous Tone Image – Непрерывное тональное изображение
Sampled Image – Пример изображения
Sampled and Quandtized Image – Выборочное и квантованное изображение
Sampler – образец
Quantizer – Квантизатор
Аналого-цифровое преобразование / Analog to Digital Conversion

(a) Analog Signal – Аналоговый сигнал
(b) Sampling – Выборка
(c) Quantization – Квантование
(d) Coding – Кодирование
TS: Sampling Period – Период выборки
Происхождение изображения / Image Origin
Upper-left corner of image – Левый верхний угол изображения
Pixels – Пиксели
Lines – Линии

Изменение яркости изображения / Image Brightness Variation


Brightness – Яркость
Distance – Расстояние
Шаги яркости изображения / Image Brightness Steps


(a) 8 Steps : 3 bits (b) 16 Steps : 4 bits
(а) 8 шагов: 3 бита (б) 16 шагов: 4 бита


(c) 32 Steps : 5 bits (d) 64 Steps : 6 bits
(c) 32 шагов: 5 бит (d) 64 шагов: 6 бит


(e) 128 Steps : 7 bits (f) 256 Steps : 8 bits
(e) 128 шагов: 7 бит (f) 256 шагов: 8 бит
Яркость изображения Разрешение / Image Brightness Resolution








Световой спектр / Light Spectrum

WHITE LIGHT / БЕЛЫЙ СВЕТ
INFRARED / ИНФРАКРАСНЫЙ
ULTRAVIOLET / УЛЬТРАФИОЛЕТ
OPTICAL PRISM / ОПТИЧЕСКАЯ ПРИЗМА
Табличка I. Цветовой спектр, видимый при прохождении белого света через призму. (С разрешения General Electric Co., подразделения по производству ламп.) / Plate I. Color spectrum seen by passing white light a prism. (Courtesy of General Electric Co., Lamp Business Division.)
COSMIC RAYS / КОСМИЧЕСКИЕ ЛУЧИ
GAMMA RAYS / ГАММА ИЗЛУЧЕНИЕ
X-RAYS / X-ЛУЧИ
INFRARED / ИНФРАКРАСНЫЙ
MICRO-WAVES / МИКРОВОЛНЫ
RADIO / РАДИО
ELECTRIC POWER / ЭЛЕКТРОЭНЕРГИЯ
ULTRAVIOLET / УЛЬТРАФИОЛЕТ
VISIBLE SPECTRUM / ВИДИМЫЙ СПЕКТР
INFRARED / ИНФРАКРАСНЫЙ
Смеси света и пигментов / Mixtures of Light and Pigments

RGB Color – Цвет RGB
MIXTURES OF LIGHT (Additive primaries)
СМЕСИ СВЕТА (Аддитивные праймериз)
RED – КРАСНЫЙ
YELLOW – ЖЕЛТЫЙ
GREEN – ЗЕЛЕНЫЙ
CYAN – ГОЛУБОЙ
WHITE – БЕЛЫЙ
BLUE – СИНИЙ
MAGENTA – ПУРПУРНЫЙ
MIXTURES OF PIGMENTS СМЕСИ ПИГМЕНТОВ
(Subtractive primaries) (Субтрактивные праймериз)

CMY(K) Color / (CMYK) Цвет
RED – КРАСНЫЙ
YELLOW – ЖЕЛТЫЙ
GREEN – ЗЕЛЕНЫЙ
CYAN – ГОЛУБОЙ
BLACK – ЧЕРНЫЙ
BLUE – СИНИЙ
MAGENTA – ПУРПУРНЫЙ
Изображение R, G, B / R, G, B Image


Исходное изображение (Original Image) Красный компонент (Red Component)


Зеленый компонент (Green Component) Синий компонент (Blue Component)
Тип цифрового изображения / A Type of Digital Image

(а) Цветное изображение (Color Image)
(b) Изображение с уровнем серого (Gray Level Image)
(c) Двоичное изображение (Binary Image)
Тип цифрового изображения / A Type of Digital Image

(a) Двоичное изображение / Binary Image

(b) Изображение с уровнем серого / Gray Level Image
Тип цифрового изображения / A Type of Digital Image

Цветное изображение (Color Image)
2. Введение OpenCV (Introduction of OpenCV)
OpenCV?
●
OpenCV – библиотека компьютерного зрения с открытым исходным кодом
– Библиотека с открытым исходным кодом для обработки изображений
и компьютерного зрения
– Состоит из более чем 2500 алгоритмов
– Поддержка интерфейсов C, C++, Python, Matlab.
– Поддержка операционных систем для Windows, Linux, Android, Mac
OS и т. д.
– Быстрая реализация алгоритма с использованием инструкций MX
(MultiMedia eXtension) и SSE (потоковые расширения SIMD).
– Разработка интерфейса CUDA и OpenCL
Установка OpenCV / OpenCV Install
•
Условия для программирования OpenCV с использованием C ++ (для ОС Windows)
–
На вашем компьютере должна быть установлена 64-битная ОС Windows. (OpenCV поддерживает только 64-битные ОС)
–
Visual Studio 2017 должен быть установлен как инструмент редактора программ для программирования на C ++. (Последняя версия Visual Studio – 2019, но в настоящее время поддерживает только OpenCV для Visual Studio 2017.)
① Установка сообщества Visual Studio 2017.
(① Visual Studio Community 2017 Install)
●
https://visualstudio.microsoft.com/ru/free-developer-offers/

•
На официальном сайте выше можно загрузить только последнюю версию 2019 года, поэтому вы можете найти версию 2017 года с помощью веб-поиска и загрузки.
•
30-дневная ознакомительная версия, затем зарегистрируйтесь в Microsoft, войдите в Visual Studio и продолжайте использовать ее бесплатно
② Загрузка OpenCV (OpenCV Download)
•
http://opencv.org
> Releases
•
После загрузки установочного файла, дважды щелкните файл exe для установки

③ Add to “System Environment Path” of Windows
•
Зарегистрируйте место установки OpenCV в «Путь к системной среде» Windows
•
Если вы установили диск C следующим образом, добавьте следующее в Path
•
C:\OpenCV\build\x64\vc15\bin

Настройка OpenCV для Visual Studio 2017
(OpenCV Setup of Visual Studio 2017)





Проверьте, что Debug mode(режим отладки) в настоящее время включен !!!













Режим отладки → opencv_worldxxxd.lib
(Режим выпуска → opencv_worldxxx.lib)
Debug mode → opencv_worldxxxd.lib
(Release mode → opencv_worldxxx.lib)



●
Имя → OpenCV410_x64_v15_
отлаживать
Name → OpenCV410_x64_v15_debug
●
Местоположение → Папка сохранения программы OpenCV (помните!!!)
Location → OpenCV program saving folder (remember!!!)

•
При использовании Visual Studio в Release mode(режиме выпуска)
–
Запустите проект> Свойства в Main Menu

–
Выполните то же самое содержание на страницах с 24 по 30
Release mode → opencv_worldxxx.lib
(Режим выпуска → opencv_worldxxx.lib)



•
Имя → OpenCV410_x64_v15_release
Name → OpenCV410_x64_v15_release
•
Местоположение → Папка сохранения программы OpenCV (помните!!!)
Location → OpenCV program saving folder (remember!!!)

Пример программы OpenCV / OpenCV Sample Program
•
запись OpenCV Sample Program

•
Ввод имени программы C++… → ???.cpp
C++ program name typing… → ???.cpp




#include <opencv2/highgui.hpp>
пустая функция()
{
cv::Mat image(300, 400, CV_8UC1, cv::Scalar(200));
cv::imshow("Просмотр изображений", image);
резюме::waitKey (0);
}
#include <opencv2/highgui.hpp>
void main()
{
cv::Mat image(300, 400, CV_8UC1, cv::Scalar(200));
cv::imshow("Image Viewer", image);
cv::waitKey(0);
}

•
Ошибка → установка x64!! / Error → x64 setting!!


•
Ctrl+F5: запустить без отладки. / Ctrl+F5 : Start without Debugging

Выход (Результат) / Output (Result)

3. OpenCV Classes
Точка_Класс / Point_ Class
•
Шаблонный класс (template class) для представления позиций width (ширины) и height (высоты) в двухмерных координатах (2 Dimension coordinate).

•
(Объявление класса Point_( Declaration of Point_ Class)
Point_<int> <==> Point2i <==> Point;
Point_<float> <==> Point2f;
Point_<double> <==> Point2d;
•
Бывший)
Ex)
Point_<int> pt1(100, 200);
Point_<float> pt2(92.3f, 125.23f);
Point_<double> pt3(100.2, 300.9);
Point pt4(120, 69);
Point2f pt5(0.3f, 0.f), pt6(0.f, 0.4f);
Point2d pt7(0.25, 0.6);
Размер_Класс / Size_ Class
•
Шаблонный класс(template class), который определяет размер изображения(image) или прямоугольника(rectangle).

•
Объявление класса Size_ (Declaration of Size_ Class)
Size_<int> <==> Size2i <==> Size;
Size_<float> <==> Size2f;
Size_<double> <==> Size2d;
•
Бывший)
•
Ex)
Size_<int> sz1(100, 200);
Size_<float> sz2(192.3f, 25.3f);
Size_<double> sz3(100.2, 30.9);
Size sz4(120, 69);
Size2f sz5(0.3f, 0.f);
Size2d sz6(0.25, 0.6);
Прямой_класс / Rect_ Class
•
класс шаблона для представления rectangle(прямоугольников)
•
((Начальная точка_x, Начальная точка_y), (Конечная точка_x, Конечная точка_y))
•
((Начальная точка_x, Начальная точка_y), Ширина, Высота)

•
Объявление класса Rect_ (Declaration of Rect_ Class)
Rect_<int> <==> Rect2i <==> Rect;
Rect_<float> <==> Rect2f;
Rect_<double> <==> Rect2d;
•
Бывший)
•
Ex)
Size2d sz(100.5, 60.6);
Point2f pt1(20.f, 30.f), pt2(100.f, 200.f);
Rect_<int> rect1(10, 10, 30, 50);
// column, row, width, height
Rect_<float> rect2(pt1, pt2);
Rect_<double> rect3(Point2d(20.5, 10), sz);
Век-класс / Vec Class
•
Шаблонный класс(template class) для вектора(Vector) чисел с небольшим количеством элементов.
•
Укажите data type(тип данных) и количество element(элементов) между < и >.
Vec<uchar, 2> <==> Vec2b
Vec<int, 3> <==> Vec3i
Vec<float, 4> <==> Vec4f
Vec<double, 5> <==> Vec5d
•
Ex)
Vec<int, 2> v1(5, 12);
Vec<double, 3> v2(40, 130.7, 125.6);
Vec2b v3(10, 10);
Vec6f v4(40.f, 230.25f, 525.6f);
Vec3i v5(200, 230, 250);
Скаляр_класс / Scalar_ Class
•
Укажите четыре значения в качеств data type(типа данных), чтобы указать значение яркости pixel(пикселя)
•
Сохраните четыре значения Blue, Green, Red, Alpha(transparency).
•
Установите в 0, если при инициализации (Initialization) не указано значение
•
Scalar_<double> <==> Scalar
•
Ex)
Scalar_<uchar> red(0, 0, 255);
Scalar_<int> blue(255, 0, 0);
Scalar_<double> color1(500);
Scalar_<float> color2(100.f, 200.f, 125.9f);
Мат Класс / Mat Class
•
Класс(class), используемый для представления image(изображения).
•
Mat (строки, столбцы, тип, скаляр (rows, cols, type, Scalar))
строки: размер строки (rows: row size)
столбцы: размер столбца (cols : column size)
тип: тип данных (type : data type)
Скаляр: матричное значение (Scalar : matrix value)

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
float data[] = {
1.2f, 2.3f, 3.2f,
4.5f, 5.f, 6.5f,
};
Mat m1(2, 3, CV_8U);
Mat m2(2, 3, CV_8U, Scalar(300));
Mat m3(2, 3, CV_32F, data);
Size sz(2, 3);
Mat m4(Size(2, 3), CV_64F);
Mat m5(sz, CV_32F, data);
cout << "[m1] =" << endl << m1 << endl;
cout << "[m2] =" << endl << m2 << endl;
cout << "[m3] =" << endl << m3 << endl << endl;
cout << "[m4] =" << endl << m4 << endl;
cout << "[m5] =" << endl << m5 << endl;
return 0;
}


#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat m1(4, 3, CV_32FC3);
cout << “Dimension = " << m1.dims << endl;
cout << “Rows = " << m1.rows << endl;
cout << “Columns = " << m1.cols << endl << endl;
cout << “Channels = " << m1.channels() << endl;
cout << “Data Type = " << m1.depth() << endl;
cout << “Matrix Size = " << m1.size() << endl << endl;
cout << “Total Data Number = " << m1.total() << endl;
return 0;
}

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat m1(2, 3, CV_8U, 2);
Mat m2(2, 3, CV_8U, Scalar(10));
Mat m3 = m1 + m2;
Mat m4 = m2 – 6;
Mat m5 = m1;
cout << "[m2] =" << endl << m2 << endl;
cout << "[m3] =" << endl << m3 << endl;
cout << "[m4] =" << endl << m4 << endl << endl;
cout << "[m1] =" << endl << m1 << endl;
cout << "[m5] =" << endl << m5 << endl << endl;
m5 = 100;
cout << "[m1] =" << endl << m1 << endl;
cout << "[m5] =" << endl << m5 << endl;
return 0;
}
• Копирование исходной матрицы в другую матрицу / Copy original matrix to another matrix
• Матовый клон () / Mat clone ()
• void copy To (матрица целей, матрица маски) / void copy To
(objective matrix, mask matrix)
–
mask matrix : Копирование только ненулевых элементов (elemen)
•
void convertTo (objective matrix, data type)
–
data type : data type, которые вы хотите изменить
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
double data[] = {
1.1, 2.2, 3.3, 4.4,
5.5, 6.6, 7.7, 8.9,
9.9, 10, 11, 12
};
Mat m1(3, 4, CV_64F, data);
Mat m2 = m1.clone(); // copy m1 to m2
Mat m3, m4;
m1.copyTo(m3); // copy m1 to m3
m1.convertTo(m4, CV_8U); // copy m1 to m4 converting to uchar
cout << "[m1] =\n" << m1 << endl;
cout << "[m2] =\n" << m2 << endl;
cout << "[m3] =\n" << m3 << endl;
cout << "[m4] =\n" << m4 << endl;
return 0;
}
векторный класс / vector Class
•
Контейнер последовательностей(Sequence Container) C++ STL(Standard Template Library)
•
доступ к элементу(element access) вектора(vector) : используйте оператор индекса(subscript operator), [], как массив(array)
•
vector() : конструктор(constructor)
•
void push_back() : добавляет элемент в конец vector
•
void pop_back() : удалить последний элемент
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
vector<Point> v1;
v1.push_back(Point(10, 20));
v1.push_back(Point(20, 30));
v1.push_back(Point(50, 60));
vector<float> v2(3, 9.25);
Size arr_size[] = { Size(2, 2), Size(3, 3), Size(4, 4) };
int arr_int[] = { 10, 20, 30, 40, 50 };
vector<Size> v3(arr_size, arr_size + sizeof(arr_size) / sizeof(Size));
vector<int> v4(arr_int + 2, arr_int + sizeof(arr_int) / sizeof(int));
cout << "[v1] " << ((Mat)v1) << endl << endl;
cout << "[v2] " << ((Mat)v2) << endl << endl;
cout << "[v2] " << ((Mat)v2).reshape(1, 1) << endl;
cout << "[v3] " << ((Mat)v3).reshape(1, 1) << endl;
cout << "[v4] " << ((Mat)v4).reshape(1, 1) << endl;
return 0;
}
Класс диапазона / Range class
•
Используется в основном для указания диапазона row(строк) и column(столбцов) в классе Mat.
•
Range(int start, int end)
•
start(начало) в диапазоне, end(конец) не в диапазоне
Функция операции с матрицей / Matrix Operation Function
•
Matexp inv(метод): расчет обратной матрицы
– метод
•
Matexp inv(method) : inverse matrix calculation
– method

•
Matexp mul (input matrix): Выполнить поэлементное (element-wise) умножение двух матриц
•
Matexp t () : вычислить транспонированную матрицу(transposed matrix)
•
Одновременные уравнения (simultaneous equation)

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
float data[] = {
1, 0, 2,
-3, 2, 6,
-1, -2, 3
};
float ans[] = {6, 30, 8};
Mat m1(3, 3, CV_32F, data);
Mat m2(1, 3, CV_32F, ans);
Mat m2_t = m2.t();
Mat m1_inv = m1.inv(DECOMP_LU);
Mat x = m1_inv * m2_t;
cout << "[m1] = " << endl << m1 << endl;
cout << "[m1_inv] = " << endl << m1_inv << endl << endl;
cout << "[m2(transposed)] = " << endl << m2_t << endl << endl;
cout << “solution x1, x2, x3 = " << x.t() << endl;
}
насыщенный_ бросок < > / saturate_cast < >
•
image data는 основном представляют собой кодированные(encoding) данные с 8 битами на канал.
•
Поскольку он использует только 8bit, он имеет ограниченный диапазон значений пикселей (0 ~ 255).
•
saturate_cast() template method : Когда значение сохраняется в 8-битном, если оно превышает 8-битный диапазон, оно сохраняется как 0 или 255
•
Ex)
Mat m1(2, 2, CV_8U);
m1(0, 0) = -50; // -> 206
m1(0, 1) = 300; // -> 44
m1(1, 0) = saturate_cast<uchar>(-50);
m1(1, 1) = saturate_cast<uchar>(300);
4. Пользовательские интерфейсы OpenCV
(OpenCV User Interfaces)
Контрольние виндов / Window Control
•
Named Window (winname, flags) : Устанавливает имя window и создает window с этим именем
–
flags : Изменение размера window

•
imshow (): отображает матрицу "mat" как окно в окне winname
•
destroyWindow (): удаляет указанное окно с экрана
•
destroyAllWindows (): удалить все видимые окна
•
moveWindow (x, y): переместить окно winname в указанную позицию (x (столбец, y (строка))
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image1(300, 400, CV_8U, Scalar(255));
Mat image2(300, 400, CV_8U, Scalar(100));
string title1 = "white window control";
string title2 = "gray window control";
namedWindow(title1, WINDOW_AUTOSIZE);
namedWindow(title2, WINDOW_NORMAL);
moveWindow(title1, 100, 200);
moveWindow(title2, 300, 200);
imshow(title1, image1);
imshow(title2, image2);
waitKey();
destroyAllWindows();
return 0;
}
Контрольние событиями клавиатуры / Keyboard Event Control
•
waitKey (delay, задержка): ожидает ввода ключа в течение времени задержки(delay), возвращает(return) значение клавиши, когда происходит событие клавиши,
–
delay : время задержки. ms.
–
delay <= 0 : Бесконечное ожидание, пока не произойдет ключевое событие
–
delay > 0 : дождитесь ввода ключа в течение времени задержки. return (Возвращает) -1, если в течение времени задержки нет клавишного ввода
•
Используйте waitKeyEx () для ввода клавиши со стрелкой (arrow key)
•
Event (Событие) происходит только когда window active (активно).
Контрольние событиями мыши / Mouse Event Control
•
Создать callback function (функцию обратного вызова) (event handler) (обработчик событий) для обработки событий мыши и зарегистрировать эту функцию в системе через setMouseCallback ()
•
Если во время выполнения программы обнаружено событие мыши, оно call(вызовет) созданную пользователем callback function (функцию обратного вызова).

#include <opencv2/opencv.hpp>
using name space cv;
using name space std;
void on Mouse (int, int, int, int, void *);
int main ()
{
Mat image (200, 300, CV_8U);
image.setTo (255);
imshow (“mouse event 1", image);
imshow (“mouse event 2", image);
set Mouse Callback (“mouse event 1", on Mouse, 0);
waitKey(0);
return 0;
}
// next page continued....
void on Mouse (int event, int x, int y, int flags, void *params)
{
switch (event)
{
case EVENT_LBUTTONDOWN:
cout << “Left mouse button press" << endl;
break;
case EVENT_RBUTTONDOWN:
cout << "Right mouse button press" << endl; break;
case EVENT_RBUTTONUP:
cout << "Right mouse button release" << endl;
break;
case EVENT_LBUTTONDBLCLK:
cout << "Left mouse button double click" << endl; break;
}
}
Контрольние событиями трекбара / Trackbar Event Control
•
Полоса прокрутки (scroll bar) или ползунок (slider bar), используемые при выборе определенного значения в определенном диапазоне
•
Create Trackbar (tn, pw, sv, max, обратный вызов, данные)
– tn: имя трекбара
– pw: имя родительского window
– sv: значение ползунка
– max: максимальное значение ползунка (минимальное значение = 0)
– callback: функция обратного вызова (onChange)
– data: userdata transferred to callback function
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
string title = “Trackbar Event";
Mat image;
void onChange(int value, void* userdata)
{
int add_value = value – 128;
cout << “added pixel value " << add_value << endl;
Mat tmp = image + add_value;
imshow(title, tmp);
}
// next page continued....
int main()
{
int value = 128;
image = Mat(300, 400, CV_8UC1, Scalar(128));
namedWindow(title, WINDOW_AUTOSIZE);
createTrackbar(“Brightness", title, &value, 255, onChange);
imshow(title, image);
waitKey(0);
return 0;
}
Линия, Прямоугольный рисунок / Line, Rectangle Drawing
•
Line (img, pt1, pt2, цвет, толщина, тип линий, сдвиг)
•
rectangle (img, pt1, pt2, цвет, толщина, тип линий, сдвиг)
–
img: Тема должна быть нарисована matrix (image)
–
pt1, pt2: звездная точка, конечная точка (star point, end point)
–
color: цвет линии или прямоугольника (line or rectangle color)
–
thickness : line thickness (-1: Заполните внутри)
–
linetype

–
сдвиг: вправо, битовый сдвиг // сдвиг вправо и влево
–
сдвиг: бит вправо // сдвиг вправо и влево
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main ()
{
Scalar blue (255, 0, 0), red (0, 0, 255), green = Scalar (0, 255, 0);
Scalar white (255, 255, 255);
Scalar yellow (0, 255, 255);
Mat image (400, 600, CV_8UC3, white);
Point pt1(50, 130), pt2(200, 300), pt3(300, 150), pt4(400, 50);
Rect rect (pt3, Size (200, 150));
Line (image, pt1, pt2, red);
line (image, pt3, pt4, green, 2, LINE_AA);
line (image, pt3, pt4, green, 3, LINE_8, 1);
rectangle (image, rect, blue, 2);
rectangle (image, rect, blue, FILLED, LINE_4, 1);
rectangle (image, pt1, pt2, red, 3);
imshow (“Line & Rectangle", image);
waitKey (0);
return 0;
}
•
Выход (Output) 80-niň suratyna täzeden seret

Текстовый рисунок / Text Drawing
•
putText (img, текст, организация, FontFace, FontScale, цвет, толщина, тип линии (img, text, org, fontFace, fontScale, color, thickness, linetype))
–
img: матрица написать Текст (изображение)
–
text: написать характер
–
org: начальные координаты текста
–
font Face: текстовый шрифт
–
font Scale: Коэффициент увеличения размера шрифта
–
color: цвет текста
–
thickness: толщина текста
–
linetype: тип текстовой строки (по умолчанию = 8)
•
Начальные координаты строки дисплея – lower left (левый нижний)
font Face: текстовый шрифт //ширина (text font //shirift)

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Scalar olive(128, 128, 0), violet(221, 160, 221), brown(42, 42, 165);
Point pt1(20, 100), pt2(20, 200), pt3(20, 250);
Mat image(300, 500, CV_8UC3, Scalar(255, 255, 255));
putText(image, "SIMPLEX", Point(20, 30), FONT_HERSHEY_SIMPLEX, 1, brown);
putText(image, "DUPLEX", pt1, FONT_HERSHEY_DUPLEX, 2, olive);
putText(image, "TRIPLEX", pt2, FONT_HERSHEY_TRIPLEX, 3, violet);
putText(image, "ITALIC", pt3, FONT_HERSHEY_PLAIN | FONT_ITALIC, 2, violet);
imshow(“Text Drawing", image);
waitKey(0);
return 0;
}
•
Выход (Output) 84-nji sahypa hem täzeden seretmeli

Рисунок круга / Circle Drawing
•
circle (изображение, центр, радиус, цвет, толщина, тип линии)
–
img: matrix Чтобы нарисовать круг (image)
–
center: координаты центра круга
–
radius: радиус круга
–
color: цвет круга
–
thickness: толщина круга
–
linetype: тип окружной линии (по умолчанию = 8)
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Scalar orange(0, 165, 255), blue(255, 0, 0), magenta(255, 0, 255);
Mat image(300, 500, CV_8UC3, Scalar(255, 255, 255));
Point center = image.size() / 2;
Point pt1(70, 50), pt2(350, 220);
circle(image, center, 100, blue);
circle(image, pt1, 80, orange, 2);
circle(image, pt2, 60, magenta, -1);
int font = FONT_HERSHEY_COMPLEX;
putText(image, "center_blue", center, font, 1.2, blue);
putText(image, "pt1_orange", pt1, font, 0.8, orange);
putText(image, "pt2_magenta", pt2 + Point(2, 2), font, 0.5, Scalar(0, 0, 0), 2);
putText(image, "pt2_magenta", pt2, font, 0.5, magenta, 1);
imshow(“Circle Drawing", image);
waitKey(0);
return 0;
}
●
Выход
/ Output

Обработка файлов изображений / Image File Processing
•
imread (имя файла, флаги)
–
имя файла: имя файла изображения для чтения
–
флаги: тип цвета на следующей странице…

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void print_matInfo(string name, Mat img)
{
string str;
int depth = img.depth();
if (depth == CV_8U) str = "CV_8U";
else if (depth == CV_8S) str = "CV_8S";
else if (depth == CV_16U) str = "CV_16U";
else if (depth == CV_16S) str = "CV_16S";
else if (depth == CV_32S) str = "CV_32S";
else if (depth == CV_32F) str = "CV_32F";
else if (depth == CV_64F) str = "CV_64F";
cout << name;
cout << format(": depth(%d) channels(%d) -> data type: ", depth, img.channels());
cout << str << "C" << img.channels() << endl;
}
// next page continued....
int main()
{
string filename = "../image/read_color.jpg";
Mat color2gray = imread(filename, IMREAD_GRAYSCALE);
Mat color2color = imread(filename, IMREAD_COLOR);
CV_Assert(color2gray.data && color2color.data);
Rect roi(100, 100, 1, 1);
cout << “Matrix (100,100) pixel value " << endl;
cout << "color2gray " << color2gray(roi) << endl;
cout << "color2color " << color2color(roi) << endl;
print_matInfo("color2gray", color2gray);
print_matInfo("color2color", color2color);
imshow("color2gray", color2gray);
imshow("color2color", color2color);
waitKey(0);
return 0;
}


•
imwrite (имя файла, изображение, вектор параметров)
–
имя файла: сохранение имени файла
–
изображение: матрица (изображение) для сохранения
–
вектор параметров: пара векторов параметров в зависимости от метода сжатия

•
Легко save (сохранить) image file (файл изображения) с расширением имени (extension name)
•
Форматы файлов изображений JPG, BMP, PNG, TIF, PPM и т. д.
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat img8 = imread("../image/read_color.jpg", IMREAD_COLOR);
CV_Assert(img8.data);
vector<int> params_jpg, params_png;
params_jpg.push_back(IMWRITE_JPEG_QUALITY);
params_jpg.push_back(50);
params_png.push_back(IMWRITE_PNG_COMPRESSION);
params_png.push_back(9);
imwrite("../image/write_test1.jpg", img8);
imwrite("../image/write_test2.jpg", img8, params_jpg);
imwrite("../image/write_test.png", img8, params_png);
imwrite("../image/write_test.bmp", img8);
return 0;
}
Обработка видео / Video Processing
•
Video file (Видеофайл) сжимается (compression) кодеком (codec) в соответствии с форматом (format), а сохраненный видеофайл распаковывается (decompression).
•
Video Capture Class / Класс видеозахвата: Читать frame (кафраме) с камеры или видео файла
–
Video Capture /
Захват видео (имя файла, устройство)
•
device / устройство: идентификатор устройства захвата (Если есть одна камера, 0)
–
open (): открытие видеофайла или камеры
–
isOpened(): подключено ли возврат устройства захвата
–
get(): возвращаемое значение идентификатора свойства
–
set(): установка свойств видео с использованием идентификатора свойств
–
read(): чтение видеокадра, затем передача в матрицу изображения
●
идентификатор свойства
/ properties identifier

•
Video Writer Class: save (сохранить) image (изображение) matrix (матрицы) в видео файл(video file)
–
VideoWriter (file name, fourcc, fps, framesize, isColor / имя файла, fourcc, частота кадров, размер кадра, isColor)
•
fourcc: 4-character code of codec (4-значный код кодека)
•
fps: frame per second (кадр в секунду)
•
framesize: video frame size (column x row) /размер видеокадра (столбец x строка)
•
isColor: true – color ecoding, false – gray frame encoding /
true – кодирование цвета, false – кодирование серого кадра
–
open () : opening of video file (открытие видеофайла)
–
isOpened () : будь открытым возврат файла записи видео
–
write() : writing video frame from image matrix (запись видеокадра из матрицы изображений)
●
4-значный код кодека (
www.fourcc.org
)
(4-character code of codec (www.fourcc.org)

// Video Frame Reading Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
VideoCapture capture(0);
if (!capture.isOpened())
{
cout << “camera not connected!!" << endl;
exit(1);
}
cout << “Width " << capture.get(CAP_PROP_FRAME_WIDTH) << endl;
cout << “Height" << capture.get(CAP_PROP_FRAME_HEIGHT) << endl;
cout << “Exposure " << capture.get(CAP_PROP_EXPOSURE) << endl;
cout << “Brightness " << capture.get(CAP_PROP_BRIGHTNESS) << endl;
// next page continued....
Point shade = Point(10, 40) + Point(2, 2);
int font = FONT_HERSHEY_SIMPLEX;
string text = "EXPOS: " + to_string((int)capture.get(CAP_PROP_EXPOSURE));
Mat frame;
for (;;) {
capture.read(frame);
putText(frame, text, shade, font, 0.7, Scalar(0, 0, 0), 2); putText(frame, text, Point(10, 40), font, 0.7, Scalar(120, 200, 90), 2);
imshow(“Camera Viewer", frame);
if (waitKey(30) >= 0)
break;
}
return 0;
}
// Video Frame Writing Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
VideoCapture capture(0);
CV_Assert(capture.isOpened());
double fps = 29.97;
int delay = cvRound(1000.0 / fps);
Size size(640, 480);
int fourcc = VideoWriter::fourcc('D', 'X', '5', '0');
capture.set(CAP_PROP_FRAME_WIDTH, size.width);
capture.set(CAP_PROP_FRAME_HEIGHT, size.height);
// next page continued....
cout << "width x height : " << size << endl;
cout << "VideoWriterfourcc : " << fourcc << endl;
cout << "delay : " << delay << endl;
cout << "fps : " << fps << endl;
VideoWriter writer;
writer.open("../image/video_file.avi", fourcc, fps, size);
CV_Assert(writer.isOpened());
Mat frame;
for (;;) {
capture >> frame;
writer << frame;
imshow(“Camera Viewer", frame);
if (waitKey(delay) >= 0)
break;
}
return 0;
}
// Video File Reading Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
VideoCapture capture;
capture.open("../image/video_file.avi");
CV_Assert(capture.isOpened());
Mat frame;
double frame_rate = capture.get(CAP_PROP_FPS);
int delay = 1000 / frame_rate;
int frame_cnt = 0, font = FONT_HERSHEY_PLAIN;
Point pt(25, 55);
Point shade = pt + Point(2, 2);
// next page continued....
while (capture.read(frame))
{
if (waitKey(delay) >= 0) break;
string text = "Frame Count : ";
text += to_string(frame_cnt++);
putText(frame, text, shade, font, 1.8, Scalar(0, 0, 0), 2);
putText(frame, text, pt, font, 1.8, Scalar(120, 200, 90), 2);
imshow(“Video File Reading", frame);
}
return 0;
}
5. Работа OpenCV с массивами / OpenCV Operation on Arrays
Основные функции обработки массивов / Fundamental Array Processing Functions
•
flip (src, dst, flipCode): вертикальное, горизонтальное, переворот в обоих направлениях
–
src: входной массив
–
dst: внешний массив
–
flipCode : 0 – горизонтальное перевор
1 – вертикальное переворот
–1 – горизонтальное и вертикальное переворачивание
•
transpose (): вернуть транспонированную матрицу входной матрицы
// Image Flipping Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("../image/flip_test.jpg", IMREAD_COLOR);
CV_Assert(image.data);
Mat x_axis, y_axis, xy_axis, trans_img;
flip(image, x_axis, 0);
flip(image, y_axis, 1);
flip(image, xy_axis, -1);
transpose(image, trans_img);
imshow("image", image);
imshow("x_axis", x_axis);
imshow("y_axis", y_axis);
imshow("xy_axis", xy_axis);
imshow("trans_img", trans_img);
waitKey();
return 0;
}
Функции обработки каналов / Channel Processing Functions
Метод сохранения элемента трехканальной матрицы (цвет)

// Image Channel Dividing Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("../image/color.jpg", IMREAD_COLOR);
CV_Assert(image.data);
Mat bgr[3];
split(image, bgr);
imshow("image", image);
imshow(“Blue Channel", bgr[0]);
imshow(“Green Channel", bgr[1]);
imshow(“Red Channel", bgr[2]);
waitKey(0);
return 0;
}
Четыре фундаментальные операции над массивами / The Four Fundamental Operations of Arrays
•
Выполняет поэлементную (element-wise) операцию (operation)
•
add (), subtract (), multiply (), divide ()
•
element-wise
element-wise
// The Four Fundamental Operations of Arrays
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat m1(3, 6, CV_8UC1, Scalar(10));
Mat m2(3, 6, CV_8UC1, Scalar(50));
Mat m_add1, m_add2, m_sub, m_div1, m_div2;
Mat mask(m1.size(), CV_8UC1, Scalar(0));
Rect rect(Point(3, 0), Size(3, 3));
mask(rect).setTo(1);
add(m1, m2, m_add1);
add(m1, m2, m_add2, mask);
// next page continued....
divide(m1, m2, m_div1);
m1.convertTo(m1, CV_32F);
m2.convertTo(m2, CV_32F);
divide(m1, m2, m_div2);
cout << "[m1] = " << endl << m1 << endl;
cout << "[m2] = " << endl << m2 << endl;
cout << "[mask] = " << endl << mask << endl << endl;
cout << "[m_add1] = " << endl << m_add1 << endl;
cout << "[m_add2] = " << endl << m_add2 << endl;
cout << "[m_div1] = " << endl << m_div1 << endl;
cout << "[m_div2] = " << endl << m_div2 << endl;
return 0;
}
Операции с корнем, степенью и величиной массивов / Root, Power, Magnitude Operations of Arrays
•
sqrt (input, ouput): вычисление квадратного корня из всех элементов массива
•
pow (input, power, ouput):
расчет мощности всех элементов массива
•
magnitude (x, y, output): расчет величин векторов x и y
•
exp (input, ouput): вычисление экспоненты всех элементов массива
•
log (input, ouput): вычисление натуральных логарифмов всех элементов массива
Логические битовые операции с массивами / Logical Bit Operations of Arrays
•
Выполнять logical operation (логические операции) в битовых единицах (bit-wise) элементов массива (array elements)
•
bitwise_and (вход 1, вход 2, выход, маска)
–
mask: Выполнять расчеты только для позиций с ненулевым значением
•
bitwise_or (вход 1, вход 2, выход, маска)
•
bitwise_xor (вход 1, вход 2, выход, маска)
•
bitwise_not (вход, вывод, маска)
// Logical Bit Operations of Arrays
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image1(250, 250, CV_8U, Scalar(0));
Mat image2(250, 250, CV_8U, Scalar(0));
Mat image3, image4, image5, image6;
Point center = image1.size() / 2;
circle(image1, center, 80, Scalar(255), -1);
rectangle(image2, Point(0, 0), Point(125, 250), Scalar(255), -1);
bitwise_or(image1, image2, image3);
bitwise_and(image1, image2, image4);
bitwise_xor(image1, image2, image5);
bitwise_not(image1, image6);
imshow("image1", image1);
imshow("image2", image2);
imshow("bitwise_or", image3);
imshow("bitwise_and", image4);
imshow("bitwise_xor", image5);
imshow("bitwise_not", image6);
waitKey();
return 0;
}
●
Выход (Output)






Абсолютное значение, Макс., Мин. Операции с массивами / Absolute value, Max, Min Operations of Arrays
•
abs (): Расчет абсолютного значения всех элементов массива
•
absdiff (): После поэлементного (element-wise) вычитания двух массивов рассчитайте absolute value (абсолютное значение).
•
max (src1, src2, dst): сравнить src1 и src2 поэлементно (element-wise) и return большое значение в dst matrix
•
min (src1, src2, dst): сравнить src1 и src2 поэлементно (element-wise) и return Меньшие значение в dst matrix
// Absolute value, Max, Min Operations of Arrays
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image1 = imread("../image/Semiconduct.tif", 0);
Mat image2 = imread("../image/Semiconduct2.tif", 0);
CV_Assert(image1.data && image2.data);
Mat dif_img, abs_dif1, abs_dif2;
image1.convertTo(image1, CV_16S);
image2.convertTo(image2, CV_16S);
subtract(image1, image2, dif_img);
abs_dif1 = abs(dif_img);
image1.convertTo(image1, CV_8U);
image2.convertTo(image2, CV_8U);
dif_img.convertTo(dif_img, CV_8U);
abs_dif1.convertTo(abs_dif1, CV_8U);
// next page continued....
absdiff(image1, image2, abs_dif2);
imshow("image1", image1), imshow("image2", image2);
imshow("dif_img", dif_img);
imshow("abs_dif1", abs_dif1), imshow("abs_dif2", abs_dif2);
Mat image_max, image_min;
image1 = imread("../image/abs_test1.jpg", 0);
image2 = imread("../image/abs_test2.jpg", 0);
CV_Assert(image1.data && image2.data);
max(image1, 120, image_max);
min(image1, image2, image_min);
image_max.convertTo(image_max, CV_8U);
image_min.convertTo(image_min, CV_8U);
imshow("image_max", image_max);
imshow("image_min", image_min);
waitKey();
return 0;
}
Статистические операции с массивами / Statistics Operations of Arrays
•
sum (input): вычисляет сумму элементов (element) для каждого канала (channel) в array (массиве)
•
mean (input, mask): вычисляет среднее значение элементов (element) для каждого канала (channel) в array
–
mask: Выполнять расчеты только для позиций с ненулевым значением
•
mean Std Dev (input, mean, stddev, mask): Рассчитать среднее (mean) и стандартное отклонение (standard deviation) элементов массива (array elements).
•
count Non Zero (): return (Вернуть) количество ненулевых элементов массива
// Statistics Operations of Arrays
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("../image/sum_test.jpg", 1);
CV_Assert(image.data);
Mat mask(image.size(), CV_8U, Scalar(0));
mask(Rect(20, 40, 70, 70)).setTo(255);
Scalar sum_value = sum(image);
Scalar mean_value1 = mean(image);
Scalar mean_value2 = mean(image, mask);
cout << "[sum_value] = " << sum_value << endl;
cout << "[mean_value1] = " << mean_value1 << endl;
cout << "[mean_value2] = " << mean_value2 << endl << endl;
// next page continued....
Mat mean, stddev;
meanStdDev(image, mean, stddev);
cout << "[mean] = " << mean << endl;
cout << "[stddev] = " << stddev << endl << endl;
meanStdDev(image, mean, stddev, mask);
cout << "[mean] = " << mean << endl;
cout << "[stddev] = " << stddev << endl;
imshow("image", image), imshow("mask", mask);
waitKey();
return 0;
}
6. Обработка изображений с использованием OpenCV / Image
Processing using OpenCV
Доступ к пикселям изображения / Image Pixel Access
•
Mat::at (): Функция шаблона (template function), которая access (обращается) к указанному элементу (пикселю) (element (pixel)) матрицы (matrix).
•
Тип возвращаемых данных (return data type) функции Mat :: at () должен соответствовать типу данных (data type) элемента массива (array element).
•
mat1.at<uchar>(10, 20);
•
mat2.at<int>(i, j);
•
mat3.at<double>(y, x);
•
mat4.at<Vec3d>(y, x)[0];
Пиксельное отображение изображения / Image Pixel Display
// Image Pixel Display
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("../image/pixel_test.jpg", IMREAD_GRAYSCALE);
if (image.empty()){
cout << “can’t open Image!!!" << endl;
exit(1);
}
Rect roi(135, 95, 20, 15);
Mat roi_img = image(roi);
Mat image_roi(Size(roi_img.cols * 10, roi_img.rows * 10), CV_8U, Scalar(0));
// next page continued....
for (int i = 0; i < roi_img.rows; i++) {
for (int j = 0; j < roi_img.cols; j++) {
for (int k = 0; k < 10; k++) {
for (int m = 0; m < 10; m++)
image_roi.at<uchar>(i*10+k, j*10+m) = roi_img.at<uchar>(i, j);
}
}
}
imshow("image_roi", image_roi);
cout << "[roi_img] =" << endl;
cout << roi_img << endl;
rectangle(image, roi, Scalar(255), 1);
imshow("image", image);
waitKey();
return 0;
}
●
Выход /
Output

Сложение/вычитание значения яркости изображения / Addition/Subtraction of Image Brightness Value
// Addition/Subtraction of Image Brightness Value
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("../image/bright.jpg", IMREAD_GRAYSCALE);
CV_Assert(!image.empty());
Mat dst1 = image + 100; // Automatic saturate_cast
Mat dst2 = image – 100; // Automatic saturate_cast
Mat dst3 = 255 – image; // Image negative transform
Mat dst4(image.size(), image.type());
Mat dst5(image.size(), image.type());
// next page continued....
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
dst4.at<uchar>(i, j) = image.at<uchar>(i, j) + 100;
dst5.at<uchar>(i, j) = 255 – image.at<uchar>(i, j);
}
}
imshow(“Original Image", image);
imshow("dst1 – Brighter", dst1);
imshow("dst2 – Darker", dst2);
imshow("dst3 – Inversion", dst3);
imshow("dst4 – Brighter", dst4);
imshow("dst5 – Darker", dst5);
waitKey();
return 0;
}
//dst4.at<uchar>(i, j) = saturate_cast<uchar>(image.at<uchar>(i, j) + 100);
Гистограмма / Histogram
•
График, показывающий количество значений яркости каждого пикселя (pixel) в image (изображении)
•
Горизонтальная ось – значение яркости пикселя
•
Вертикальная ось – частота (frequency) яркости (brightness) каждого пикселя (pixel)
•
Image вы можете узнать распределение значений яркости пикселей для
•
Предоставленная Open CV Histogram Calculation Function (функция вычисления гистограммы)
calcHist (img, nimg, chn, mask, hist, dims, histsize, range)
–
img: исходный массив изображений (тип данных CV_8U или CV_32F)
–
nimg: номера оригинальных изображений
–
chn: список каналов
–
mask: mask array (Выполнять расчеты только для позиций с ненулевым значением)
–
hist: гистограмма, сохраняющая массив результатов вычислений
–
dims: номер измерения гистограммы
–
histsize: размер массива гистограммы каждого измерения
–
range: диапазон значений пикселей гистограммы
Расчет гистограммы / Histogram Calculation
// Histogram Calculation
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void calc_Histo(const Mat& image, Mat& hist, int bins, int range_max = 256)
{
int histSize[] = { bins };
float range[] = { 0, (float)range_max };
int channels[] = { 0 };
const float* ranges[] = { range };
calcHist(&image, 1, channels, Mat(), hist, 1, histSize, ranges); // OpenCV
}
int main()
{
Mat image = imread("../image/pixel_test.jpg", IMREAD_GRAYSCALE);
CV_Assert(!image.empty());
Mat hist, hist_img;
calc_Histo(image, hist, 256);
cout << hist.t() << endl;
imshow("image", image);
waitKey();
return 0;
}
●
Выход
/ Output


Рисование гистограммы / Histogram Drawing
// Histogram Drawing Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void calc_Histo(const Mat& image, Mat& hist, int bins, int range_max = 256)
{
int histSize[] = { bins };
float range[] = { 0, (float)range_max };
int channels[] = { 0 };
const float* ranges[] = { range };
calcHist(&image, 1, channels, Mat(), hist, 1, histSize, ranges);
}
void draw_histo(Mat hist, Mat &hist_img, Size size = Size(256, 200))
{
hist_img = Mat(size, CV_8U, Scalar(255));
normalize(hist, hist, 0, hist_img.rows, NORM_MINMAX);
// next page continued....
for (int i = 0; i < hist.rows; i++){
Point2f pt1 = Point2f(i, 0);
Point2f pt2 = Point2f((i + 1), hist.at <float>(i));
if (pt2.y > 0)
rectangle(hist_img, pt1, pt2, Scalar(0), -1);
}
flip(hist_img, hist_img, 0);
}
int main()
{
Mat image = imread("../image/lena_std.tif", IMREAD_GRAYSCALE);
CV_Assert(!image.empty());
Mat hist, hist_img;
calc_Histo(image, hist, 256);
draw_histo(hist, hist_img);
imshow(“Histogram Image”, hist_img);
imshow(“Image", image);
waitKey();
return 0;
}


Растяжение гистограммы / Histogram Stretching





①

②
③ 
// Histogram Stretching Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void calc_Histo(const Mat& image, Mat& hist, int bins, int range_max = 256)
{
int histSize[] = { bins };
float range[] = { 0, (float)range_max };
int channels[] = { 0 };
const float* ranges[] = { range };
calcHist(&image, 1, channels, Mat(), hist, 1, histSize, ranges);
}
void draw_histo(Mat hist, Mat &hist_img, Size size = Size(256, 200))
{
hist_img = Mat(size, CV_8U, Scalar(255));
normalize(hist, hist, 0, hist_img.rows, NORM_MINMAX);
for (int i = 0; i < hist.rows; i++) {
Point2f pt1 = Point2f(i, 0);
Point2f pt2 = Point2f((i+1), hist.at <float>(i));
if (pt2.y > 0)
rectangle(hist_img, pt1, pt2, Scalar(0), -1);
}
flip(hist_img, hist_img, 0);
}
void search_valueIdx(Mat hist, int &low_value, int &high_value)
{
int i;
for (i = 0; i < hist.rows; i++) {
if (hist.at<float>(i) > 0)
break;
}
low_value = i;
// next page continued....
for (i = hist.rows-1; i > 0; i–){
if (hist.at<float>(i) > 0)
break;
}
high_value = i;
}
int main()
{
Mat image = imread("../image/Lenna-histo_str.tif", 0);
CV_Assert(!image.empty());
Mat hist, hist_dst, hist_img, hist_dst_img;
int histsize = 256, ranges = 256;
calc_Histo(image, hist, histsize, ranges);
draw_histo(hist, hist_img);
int low_value, high_value;
search_valueIdx(hist, low_value, high_value);
cout << "high_value = " << high_value << endl;
cout << "low_value = " << low_value << endl;
int d_value = high_value – low_value;
Mat dst = (image – low_value) * (255.0 / d_value);
calc_Histo(dst, hist_dst, histsize, ranges);
draw_histo(hist_dst, hist_dst_img);
imshow("Original Image", image);
imshow("Hist. Stretch. Image", dst);
imshow("Hist. of Origin", hist_img);
imshow("Hist. of Stretch. Image", hist_dst_img);
waitKey();
return 0;
}
Выравнивание гистограммы / Histogram Equalization
•
Применяется к изображениям с широким распределением гистограммы (Histogram), но с распределением контраста, смещенным в одном направлении
•
[Шаг 1] Расчет гистограммы
•
[Шаг 2] Расчет накопленной суммы гистограммы

•
[Шаг 3] Нормализация накопленной суммы

: Общее количество пикселей
: Максимальное значение яркости пикселей
●
Шаг 1
– Расчет гистограммы
ㅔㅑㅔㅑㅑ
a) яркость пикселей
изображение
изображение
image
(b) histogram
яркость пикселей
●
Шаг 2
– Расчет накопленной суммы гистограммы
(a)Гистограмма
яркость пикселей
(b) Накопленная сумма
●
Шаг 3
– Нормализация накопленной суммы
–
n[i]=sum[i]*(1/16)*7
j Нормализованная гистограмма

(b) гистограмма
(a) входное изображение


// Histogram Equalization Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void calc_Histo(const Mat& image, Mat& hist, int bins, int range_max = 256)
{
int histSize[] = { bins };
float range[] = { 0, (float)range_max };
int channels[] = { 0 };
const float* ranges[] = { range };
calcHist(&image, 1, channels, Mat(), hist, 1, histSize, ranges);
}
void draw_histo(Mat hist, Mat &hist_img, Size size = Size(256, 200))
{
hist_img = Mat(size, CV_8U, Scalar(255));
Mat hist2;
normalize(hist, hist2, 0, hist_img.rows, NORM_MINMAX);
for (int i = 0; i < hist2.rows; i++) {
Point2f pt1 = Point2f(i, 0);
Point2f pt2 = Point2f((i+1), hist2.at <float>(i));
if (pt2.y > 0)
rectangle(hist_img, pt1, pt2, Scalar(0), -1);
}
flip(hist_img, hist_img, 0);
}
void create_hist(Mat img, Mat &hist, Mat &hist_img)
{
int histsize = 256, range = 256;
calc_Histo(img, hist, histsize, range);
draw_histo(hist, hist_img);
}
// next page continued....
int main()
{
Mat image = imread("../image/Ave.tif", 0);
CV_Assert(!image.empty());
Mat hist, dst1, dst2, hist_img, hist_img1, hist_img2;
create_hist(image, hist, hist_img);
Mat accum_hist = Mat(hist.size(), hist.type(), Scalar(0));
accum_hist.at<float>(0) = hist.at<float>(0);
for (int i = 1; i < hist.rows; i++)
accum_hist.at<float>(i) = accum_hist.at<float>(i – 1) + hist.at<float>(i);
accum_hist /=(image.rows*image.cols);;
accum_hist *= 255;
dst1 = Mat(image.size(), CV_8U);
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
int idx = image.at<uchar>(i, j);
dst1.at<uchar>(i, j) = (uchar)accum_hist.at<float>(idx);
}
}
create_hist(dst1, hist, hist_img1);
// Using Histogram Equalization of OpenCV Function
equalizeHist(image, dst2);
create_hist(dst2, hist, hist_img2);
imshow(“image", image), imshow("img_hist", hist_img);
imshow("dst1-User", dst1), imshow("User_hist", hist_img1);
imshow("dst2-OpenCV", dst2), imshow("OpenCV_hist", hist_img2);
waitKey();
return 0;
}
7. Обработка свертки с использованием OpenCV / Convolution
Processing using OpenCV
Обработка свертки / Convolution Processing
•
Изображение обрабатывается с использованием метода свертки (convolution technique), включая ассоциацию с соседним пикселем (neighbor pixel) пикселя
•
использование Mask (= Kernel, Window, Filter)
Маска(М)
Соседние пиксели
Входное изображение(f)
Текущий пиксели
Pixel
Выходной пиксель
Выходное изображение (г)
Сумма всех умножений
Умножение маски и соседних пикселей
Размытие / Blurring
•
Как внести постепенные изменения в резкость изменения значения пикселя (pixel value)
•
Обработка свертки с использованием маски размытия.
•
Маска размытия
Входное изображение
(a) Входное изображение
(b) Размытое изображение
// Blurring Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void filter(Mat img, Mat& dst, Mat mask)
{
dst = Mat(img.size(), CV_32F, Scalar(0));
// Image Extension (using 3 x 3 Mask)
Mat ExtImg(img.rows+2, img.cols+2, CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++)
ExtImg.at<float>(i + 1, j + 1) = img.at<uchar>(i, j); // center
}
for (int i = 1; i < img.rows+1; i++) {
ExtImg.at<float>(i, 0) = ExtImg.at<float>(i, 1); // Left line
ExtImg.at<float>(i, img.cols + 1) = ExtImg.at<float>(i, img.cols); // Right line
}
for (int j = 1; j < img.cols+1; j++){
ExtImg.at<float>(0, j) = ExtImg.at<float>(1, j); // Upper line
ExtImg.at<float>(img.rows + 1, j) = ExtImg.at<float>(img.rows, j); // Bottom line
}
ExtImg.at<float>(0, 0) = ExtImg.at<float>(1, 1); // Upper left corner
ExtImg.at<float>(0, img.cols+1) = ExtImg.at<float>(1, img.cols); // Upper right corner
ExtImg.at<float>(img.rows+1, 0) = ExtImg.at<float>(img.rows, 1); // Bottom left corner
ExtImg.at<float>(img.rows+1, img.cols+1) = ExtImg.at<float>(img.rows, img.cols); // Bottom right
// corner
// next page continued....
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
float sum = 0;
for (int u = 0; u < mask.rows; u++) {
for (int v = 0; v < mask.cols; v++)
sum += ExtImg.at<float>(i + u, j + v) * mask.at<float>(u, v);
}
dst.at<float>(i, j) = sum;
}
}
}
int main()
{
Mat image = imread("../image/filter_blur.jpg", IMREAD_GRAYSCALE);
CV_Assert(image.data);
float data[] = {
1 / 9.f, 1 / 9.f, 1 / 9.f,
1 / 9.f, 1 / 9.f, 1 / 9.f,
1 / 9.f, 1 / 9.f, 1 / 9.f };
Mat mask(3, 3, CV_32F, data), blur;
filter(image, blur, mask);
blur.convertTo(blur, CV_8U);
namedWindow(“Original Image", WINDOW_AUTOSIZE);
namedWindow(“Blurring", WINDOW_AUTOSIZE);
moveWindow(“Original Image", 200, 200), moveWindow(“Blurring", 600, 200);
imshow(“Original image", image), imshow(“Blurring", blur);
waitKey();
return 0;
}
Заточка / Sharpening
•
Разница между соседними пикселями (neighbor pixel) заставляет их чувствовать себя резкими
•
Детали изображения могут быть подчеркнуты, а контраст яркости (brightness contrast) увеличен на краевой (edge) части
•
Заточка маски

(a) Входное изображение
(b) Резкое изображение
// Sharpening Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void filter(Mat img, Mat& dst, Mat mask)
{
dst = Mat(img.size(), CV_32F, Scalar(0));
// Image Extension (using 3 x 3 Mask)
Mat ExtImg(img.rows+2, img.cols+2, CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++)
ExtImg.at<float>(i + 1, j + 1) = img.at<uchar>(i, j); // center
}
for (int i = 1; i < img.rows+1; i++) {
ExtImg.at<float>(i, 0) = ExtImg.at<float>(i, 1); // Left line
ExtImg.at<float>(i, img.cols + 1) = ExtImg.at<float>(i, img.cols); // Right line
}
for (int j = 1; j < img.cols+1; j++){
ExtImg.at<float>(0, j) = ExtImg.at<float>(1, j); // Upper line
ExtImg.at<float>(img.rows + 1, j) = ExtImg.at<float>(img.rows, j); // Bottom line
}
ExtImg.at<float>(0, 0) = ExtImg.at<float>(1, 1); // Upper left corner
ExtImg.at<float>(0, img.cols+1) = ExtImg.at<float>(1, img.cols); // Upper right corner
ExtImg.at<float>(img.rows+1, 0) = ExtImg.at<float>(img.rows, 1); // Bottom left corner
ExtImg.at<float>(img.rows+1, img.cols+1) = ExtImg.at<float>(img.rows, img.cols); // Bottom right
// corner
// next page continued....
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
float sum = 0;
for (int u = 0; u < mask.rows; u++) {
for (int v = 0; v < mask.cols; v++)
sum += ExtImg.at<float>(i + u, j + v) * mask.at<float>(u, v);
}
dst.at<float>(i, j) = sum;
}
}
}
int main()
{
Mat image = imread("../image/filter_sharpen.jpg", IMREAD_GRAYSCALE);
CV_Assert(image.data);
float data[] = {
–1, -1, -1,
–1, 9, -1,
–1, -1, -1};
Mat mask(3, 3, CV_32F, data), sharpen;
filter(image, sharpen, mask);
sharpen.convertTo(sharpen, CV_8U);
namedWindow(“Original Image", WINDOW_AUTOSIZE);
namedWindow(“Sharpening Image", WINDOW_AUTOSIZE);
moveWindow("Original Image", 200, 200), moveWindow("Sharpening Image", 600, 200);
imshow("Original Image", image), imshow("Sharpening Image", sharpen);
waitKey();
return 0;
}
Обнаружение края / Edge Detection
•
В изображении край (edge) – это часть, где значение пикселя (pixel value) резко меняется
Hhh
•
Однородный оператор
– центральный пиксель 8 – дифференциальный расчет
●
Дифференциальный оператор
– центральный пиксель и пиксель на противоположной стороне и 4 дифференциальных вычисления (differential calculation)
Выход дифференциального оператора =
Однородный вывод оператора
Обнаружение края (однородный оператор) / Edge Detection (Homogeneous Operator)
// Edge Detection (Homogeneous Operator) Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void homogenOp(Mat img, Mat& dst, int mask_size)
{
dst = Mat(img.size(), CV_8U, Scalar(0));
// Image Extension (using 3 x 3 Mask)
Mat ExtImg(img.rows + 2, img.cols + 2, CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++)
ExtImg.at<float>(i + 1, j + 1) = img.at<uchar>(i, j);
}
for (int i = 1; i < img.rows + 1; i++) {
ExtImg.at<float>(i, 0) = ExtImg.at<float>(i, 1);
ExtImg.at<float>(i, img.cols + 1) = ExtImg.at<float>(i, img.cols);
}
for (int j = 1; j < img.cols + 1; j++) {
ExtImg.at<float>(0, j) = ExtImg.at<float>(1, j);
ExtImg.at<float>(img.rows + 1, j) = ExtImg.at<float>(img.rows, j);
}
ExtImg.at<float>(0, 0) = ExtImg.at<float>(1, 1);
ExtImg.at<float>(0, img.cols + 1) = ExtImg.at<float>(1, img.cols);
ExtImg.at<float>(img.rows + 1, 0) = ExtImg.at<float>(img.rows, 1);
ExtImg.at<float>(img.rows + 1, img.cols + 1) = ExtImg.at<float>(img.rows, img.cols);
// next page continued....
Обнаружение края (однородный оператор) / Edge Detection (Homogeneous Operator)
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
float max = 0;
for (int u = 0; u < mask_size; u++) {
for (int v = 0; v < mask_size; v++) {
float difference = abs(ExtImg.at<float>(i+1, j+1) – ExtImg.at<float>(i+u, j+v));
if (difference > max)
max = difference;
}
}
dst.at<uchar>(i, j) = max;
}
}
}
int main()
{
Mat image = imread("../image/edge_test.jpg", IMREAD_GRAYSCALE);
CV_Assert(image.data);
Mat edge;
homogenOp(image, edge, 3);
namedWindow(“Original Image", WINDOW_AUTOSIZE);
namedWindow(“Homogen. Edge", WINDOW_AUTOSIZE);
moveWindow(“Original Image", 200, 200);
moveWindow("Homogen. Edge", 600, 200);
imshow(“Original Image", image);
imshow("Homogen. Edge", edge);
waitKey();
return 0;
}
Обнаружение края (Дифференциальный оператор) / Edge Detection (Differential Operator)
// Edge Detection (Differential Operator) Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void differOp(Mat img, Mat& dst, int mask_size)
{
dst = Mat(img.size(), CV_8U, Scalar(0));
// Image Extension (using 3 x 3 Mask)
Mat ExtImg(img.rows + 2, img.cols + 2, CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++)
ExtImg.at<float>(i + 1, j + 1) = img.at<uchar>(i, j);
}
for (int i = 1; i < img.rows + 1; i++) {
ExtImg.at<float>(i, 0) = ExtImg.at<float>(i, 1);
ExtImg.at<float>(i, img.cols + 1) = ExtImg.at<float>(i, img.cols);
}
for (int j = 1; j < img.cols + 1; j++) {
ExtImg.at<float>(0, j) = ExtImg.at<float>(1, j);
ExtImg.at<float>(img.rows + 1, j) = ExtImg.at<float>(img.rows, j);
}
ExtImg.at<float>(0, 0) = ExtImg.at<float>(1, 1);
ExtImg.at<float>(0, img.cols + 1) = ExtImg.at<float>(1, img.cols);
ExtImg.at<float>(img.rows + 1, 0) = ExtImg.at<float>(img.rows, 1);
ExtImg.at<float>(img.rows + 1, img.cols + 1) = ExtImg.at<float>(img.rows, img.cols);
// next page continued....
// Edge Detection (Differential Operator) Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void differOp(Mat img, Mat& dst, int mask_size)
{
dst = Mat(img.size(), CV_8U, Scalar(0));
// Image Extension (using 3 x 3 Mask)
Mat ExtImg(img.rows + 2, img.cols + 2, CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++)
ExtImg.at<float>(i + 1, j + 1) = img.at<uchar>(i, j);
}
for (int i = 1; i < img.rows + 1; i++) {
ExtImg.at<float>(i, 0) = ExtImg.at<float>(i, 1);
ExtImg.at<float>(i, img.cols + 1) = ExtImg.at<float>(i, img.cols);
}
for (int j = 1; j < img.cols + 1; j++) {
ExtImg.at<float>(0, j) = ExtImg.at<float>(1, j);
ExtImg.at<float>(img.rows + 1, j) = ExtImg.at<float>(img.rows, j);
}
ExtImg.at<float>(0, 0) = ExtImg.at<float>(1, 1);
ExtImg.at<float>(0, img.cols + 1) = ExtImg.at<float>(1, img.cols);
ExtImg.at<float>(img.rows + 1, 0) = ExtImg.at<float>(img.rows, 1);
ExtImg.at<float>(img.rows + 1, img.cols + 1) = ExtImg.at<float>(img.rows, img.cols);
// next page continued....
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
vector<float> mask;
for (int u = 0; u < mask_size; u++) {
for (int v = 0; v < mask_size; v++)
mask.push_back(ExtImg.at<float>(i + u, j + v));
}
float max = 0;
for (int k = 0; k <= mask_size; k++) {
float difference = abs(mask[k]-mask[8-k]);
if (difference > max) max = difference;
}
dst.at<uchar>(i, j) = max;
}
}
}
int main()
{
Mat image = imread("../image/edge_test.jpg", IMREAD_GRAYSCALE);
CV_Assert(image.data);
Mat edge;
differOp(image, edge, 3);
namedWindow(“Original Image", WINDOW_AUTOSIZE);
namedWindow(“Diff. Edge", WINDOW_AUTOSIZE);
moveWindow("Original Image", 200, 200), moveWindow("Diff. Edge", 600, 200);
imshow("Original Image", image), imshow("Diff. Edge", edge);
waitKey();
return 0;
}
Обнаружение краев (оператор маски Робертса/Собела) / Edge Detection (Roberts/Sobel Mask Operator)
●
Оператор маски Робертса
/ Roberts Mask Operator
163-iň suratyny alyp bilmedim.
●
Оператор Маски Собел (Оператор Маски Собел)
/
Sobel Mask Operator (Sobel Mask Operator)
Обнаружение края (оператор маски Робертса) / Edge Detection (Roberts Mask Operator)
// Edge Detection (Roberts Mask Operator)
// Using filter2D function of OpenCV
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void differential(Mat image, Mat& dst, float data1[], float data2[])
{
Mat dst1, mask1(3, 3, CV_32F, data1);
Mat dst2, mask2(3, 3, CV_32F, data2);
filter2D(image, dst1, CV_32F, mask1, Point(-1, -1), 0, BORDER_REPLICATE);
filter2D(image, dst2, CV_32F, mask2, Point(-1, -1), 0, BORDER_REPLICATE);
// Point : filtering start point of kernel, 0 : value added to result
// BORDER_REPLICATE : image extension using border replication
magnitude(dst1, dst2, dst);
dst.convertTo(dst, CV_8U);
dst1 = abs(dst1);
dst2 = abs(dst2);
dst1.convertTo(dst1, CV_8U);
dst2.convertTo(dst2, CV_8U);
namedWindow(“Mask 1 Result", WINDOW_AUTOSIZE);
namedWindow("Mask 2 Result", WINDOW_AUTOSIZE);
moveWindow("Mask 1 Result", 200, 500);
moveWindow("Mask 2 Result", 700, 500);
imshow("Mask 1 Result", dst1);
imshow("Mask 2 Result", dst2);
}
// next page continued....
int main()
{
Mat image = imread("../image/edge_test1.jpg", IMREAD_GRAYSCALE);
CV_Assert(image.data);
float data1[] = {
-1, 0, 0,
0, 1, 0,
0, 0, 0
};
float data2[] = {
0, 0, -1,
0, 1, 0,
0, 0, 0
};
Mat dst;
differential(image, dst, data1, data2);
namedWindow(“Original Image", WINDOW_AUTOSIZE);
namedWindow(“Roberts Edge", WINDOW_AUTOSIZE);
moveWindow("Original Image", 200, 100);
moveWindow("Roberts Edge", 700, 100);
imshow("Original Image”, image);
imshow("Roberts Edge", dst);
waitKey();
return 0;
}
Обнаружение края (оператор маски Собеля) / Edge Detection (Sobel Mask Operator)
// Edge Detection (Sobel Mask Operator)
// Using filter2D and Sobel function of OpenCV
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void differential(Mat image, Mat& dst, float data1[], float data2[])
{
Mat dst1, mask1(3, 3, CV_32F, data1);
Mat dst2, mask2(3, 3, CV_32F, data2);
filter2D(image, dst1, CV_32F, mask1, Point(-1, -1), 0, BORDER_REPLICATE);
filter2D(image, dst2, CV_32F, mask2, Point(-1, -1), 0, BORDER_REPLICATE);
magnitude(dst1, dst2, dst);
dst.convertTo(dst, CV_8U);
convertScaleAbs(dst1, dst1);
convertScaleAbs(dst2, dst2);
namedWindow("dst1 – Vertical Mask", WINDOW_AUTOSIZE);
namedWindow("dst2 – Horiz. Mask", WINDOW_AUTOSIZE);
moveWindow("dst1 – Vertical Mask", 700, 100);
moveWindow("dst2 – Horiz. Mask", 700, 500);
imshow("dst1 – Vertical Mask", dst1);
imshow("dst2 – Horiz. Mask", dst2);
}
int main()
{
Mat image = imread("../image/edge_test1.jpg", IMREAD_GRAYSCALE);
CV_Assert(image.data);
// next page continued....
float data1[] = {
-1, 0, 1,
-2, 0, 2,
-1, 0, 1 };
float data2[] = {
-1, -2, -1,
0, 0, 0,
1, 2, 1 };
Mat dst, dst3, dst4;
differential(image, dst, data1, data2);
namedWindow(“Original Image", WINDOW_AUTOSIZE);
namedWindow(“Sobel Edge", WINDOW_AUTOSIZE);
moveWindow("Original Image", 200, 100);
moveWindow("Sobel Edge", 200, 500);
imshow("Original Image", image);
imshow("Sobel Edge", dst);
// Sobel Edge Detection using OpenCV Function
Sobel(image, dst3, CV_32F, 1, 0, 3); // 4th = 1 -> vertical mask (vertical edge)
Sobel(image, dst4, CV_32F, 0, 1, 3); // 5th = 1 -> horizontal mask (horizontal edge)
convertScaleAbs(dst3, dst3); // 3 -> kernal size
convertScaleAbs(dst4, dst4);
namedWindow("dst3 – vert._OpenCV", WINDOW_AUTOSIZE);
namedWindow("dst4 – horiz._OpenCV", WINDOW_AUTOSIZE);
moveWindow("dst3 – vert._OpenCV", 1200, 100);
moveWindow("dst4 – horiz._OpenCV", 1200, 500);
imshow("dst3 – vert.OpenCV", dst3), imshow("dst4 – horiz._OpenCV", dst4);
waitKey();
return 0;
}
Медианный фильтр / Median Filter

Медианный фильтр / Median Filter
–
После выравнивания значений соседних пикселей (neighbor pixel) в порядке возрастания выберите значение центра в качестве выходного значения
–
Используется для удаления импульсного шума (impulse noise), который имеет резкое изменение цвета, как искра(spark) на изображении (image)
// Median Filtering Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void medianFilter(Mat img, Mat& dst, int size)
{
dst = Mat(img.size(), CV_8U, Scalar(0));
// Image Extension (using 3 x 3 Mask)
Mat ExtImg(img.rows + 2, img.cols + 2, CV_32F);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++)
ExtImg.at<float>(i + 1, j + 1) = img.at<uchar>(i, j);
}
for (int i = 1; i < img.rows + 1; i++) {
ExtImg.at<float>(i, 0) = ExtImg.at<float>(i, 1);
ExtImg.at<float>(i, img.cols + 1) = ExtImg.at<float>(i, img.cols);
}
for (int j = 1; j < img.cols + 1; j++) {
ExtImg.at<float>(0, j) = ExtImg.at<float>(1, j);
ExtImg.at<float>(img.rows + 1, j) = ExtImg.at<float>(img.rows, j);
}
ExtImg.at<float>(0, 0) = ExtImg.at<float>(1, 1);
ExtImg.at<float>(0, img.cols + 1) = ExtImg.at<float>(1, img.cols);
ExtImg.at<float>(img.rows + 1, 0) = ExtImg.at<float>(img.rows, 1);
ExtImg.at<float>(img.rows + 1, img.cols + 1) = ExtImg.at<float>(img.rows, img.cols);
// next page continued....
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
vector<float> mask;
for (int u = 0; u < size; u++) {
for (int v = 0; v < size; v++)
mask.push_back(ExtImg.at<float>(i + u, j + v));
}
cv::sort(mask, mask, SORT_EVERY_ROW); // cv:: writing to distinguish from std::sort()
dst.at<uchar>(i, j) = (uchar)mask[4];
}
}
}
int main()
{
Mat gray = imread("../image/Boat-noise.tif", IMREAD_GRAYSCALE);
CV_Assert(gray.data);
Mat med_img1, med_img2;
namedWindow("Original Image", WINDOW_AUTOSIZE);
moveWindow("Original Image", 200, 200);
imshow("Original Image", gray);
medianFilter(gray, med_img1, 3); // Median Filtering using User Function
namedWindow("median-User", WINDOW_AUTOSIZE);
moveWindow("median-User", 600, 200);
imshow("median-User", med_img1);
medianBlur(gray, med_img2, 3); // Median Filtering using OpenCV Function
namedWindow("median-OpenCV", WINDOW_AUTOSIZE);
moveWindow("median-OpenCV", 1000, 200);
imshow("median-OpenCV", med_img2);
waitKey();
return 0;
}
8. Преобразование обработки домена / Transform Domain Processing
Пространственная частота (Мекансал фреканс)/ Spatial Frequency (Mekansal frekans)
•
Hertz (Hz)
–
единица частоты
–
Количество раз, чтобы вибрировать в 1 секунду
•
При обработке изображений (image processing) используется понятие пространственной частоты (spatial frequency)
•
Определение степени яркости пикселя
sec
sec
sec
•
Пространственная частота (spatial frequency)
–
Низкочастотная пространственная область
•
В области, где яркость пикселей(pixel brightness) практически не изменяется или постепенно изменяется
•
Фоновая часть изображений.
–
Высокочастотная пространственная область
•
Яркость пикселей (pixel brightness) быстро меняется
Краевая часть изображений
Низкая частота

Высокая частота
•
Что делать, если вы разделяете изображения (image) по частотной области(frequency domain)?
–
Изображение с удаленными высокочастотными компонентами (high frequency components)
☞
Изображение (image) с размытым краем (edge)
–
Изображение снято только с высокочастотными компонентами (high frequency components)
☞
Изображение, включающее только край (edge), то есть edge image
•
Преобразование частоты (Frequency Transform)
Входное изображение
Частота
Трансформировать
Частота
Обратное преобразование
Частота
Коэффициенты
Преобразование Фурье / Fourier Transform
●
Пространственная область → Ширина частотной области, высота, размер изображения: N
(Spatial Domain → Frequency Domain width, height size of image: N)

●
Частотная область → Ширина пространственной области, высота, размер изображения:
N
(Frequency Domain → Spatial Domain width, height size of image: N)

(a) Входное изображение
(b) Изображение частоты
(c) Изображение перетасованной частоты
Частота будет увеличиваться от центра изображения к краям.
Фурье
Трансформировать
Фурье
Обратный
Трансформировать
Дискретное косинусное преобразование / (DCT) Discrete Cosine Transform(DCT)
●
Пространственная область → Ширина частотной области, высота, размер изображения:
N
(Spatial Domain → Frequency Domain width, height size of image: N)

●
Частотная область → Ширина пространственной области, высота, размер изображения:
N
(Frequency Domain → Spatial Domain width, height size of image: N)

Ленна 16x16 Блок пикселей / Lenna 16x16 Block Pixels

suratyny oňarmaly, doly goup bilmedim.
Ленна 16x16 Блок коэффициентов DCT / Lenna 16x16 Block DCT Coefficients
●
Ленна 16x16 Блок коэффициентов DCT
●
Смещение=128
179-daky Suraty goýup bilmedim


Высокий (High)
180-däki Suraty goýup bilmedim
Дискретное косинусное преобразование (DCT) / Discrete Cosine Transform(DCT)
// Discrete Cosine Transform(DCT) Program
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
Mat DCT_block(Mat g) // Forward DCT
{
Mat dst(g.size(), g.type());
int N = g.rows, M = g.cols;
for (int k = 0; k < N; k++) {
for (int l = 0; l < M; l++) {
float sum = 0;
for (int n = 0; n < N; n++) {
for (int m = 0; m < M; m++) {
float theta1 = (float)((2 * n + 1) * k * CV_PI / (2 * N));
float theta2 = (float)((2 * m + 1) * l * CV_PI / (2 * M));
sum += g.at<float>(n, m) * cos(theta1) * cos(theta2);
}
}
float ck = (k) ? sqrt(2.0f / N) : sqrt(1.0f / N);
float cl = (l) ? sqrt(2.0f / M) : sqrt(1.0f / M);
dst.at<float>(k, l) = ck * cl * sum;
}
}
return dst;
}
// next page continued....
Mat IDCT_block(Mat f) // Inverse DCT
{
Mat dst(f.size(), f.type());
int N = f.rows, M = f.cols;
for (int n = 0; n < N; n++) {
for (int m = 0; m < M; m++) {
float sum = 0;
for (int k = 0; k < N; k++) {
for (int l = 0; l < M; l++) {
float theta1 = (float)((2 * n + 1) * k * CV_PI / (2 * N));
float theta2 = (float)((2 * m + 1) * l * CV_PI / (2 * M));
float ck = (k) ? sqrt(2.0f / N) : sqrt(1.0f / N);
float cl = (l) ? sqrt(2.0f / M) : sqrt(1.0f / M);
sum += ck * cl * f.at<float>(k, l) * cos(theta1) * cos(theta2);
}
}
dst.at<float>(n, m) = sum;
}
}
return dst;
}
void DCT_2D(Mat img, Mat& dst, int N, int M, int dir)
{
dst = Mat(img.size(), CV_32F);
img.convertTo(img, CV_32F);
// next page continued....
for (int bi = 0; bi < img.rows; bi += N) {
for (int bj = 0; bj < img.cols; bj += M) {
Rect rect(Point(bj, bi), Size(M, N));
Mat block = img(rect);
Mat new_block = (dir == 0) ? DCT_block(block) : IDCT_block(block);
new_block.copyTo(dst(rect));
}
}
}
int main()
{
Mat image = imread("../image/lena_std.tif", IMREAD_GRAYSCALE);
CV_Assert(image.data);
Mat m_dct, m_idct;
DCT_2D(image, m_dct, 8, 8, 0);
DCT_2D(m_dct, m_idct, 8, 8, 1);
m_idct.convertTo(m_idct, CV_8U);
namedWindow("Original Image", WINDOW_AUTOSIZE);
namedWindow("Inverse DCT", WINDOW_AUTOSIZE);
moveWindow("Original Image", 200, 200), moveWindow("Inverse DCT", 800, 200);
imshow("Original Image", image), imshow("Inverse DCT", m_idct);
Rect rect(0, 0, 8, 8);
cout << “First 8x8 Block Original Image Elements" << endl;
cout << image(rect) << endl << endl;
cout << “First 8x8 Block DCT Coefficients" << endl;
cout << m_dct(rect) << endl;
waitKey();
}