2.60M
Категория: ПрограммированиеПрограммирование

Цифровая обработка изображений

1.

ЦИФРОВАЯ
ОБРАБОТКА
ИЗОБРАЖЕНИЙ

2.

3.

4.

Цифровое изображение – это графическая форма представления данных, предназначенная
для зрительного восприятия, которая имеет такие характеристики, как яркость, контрастность,
разрешение, цветопередача и т. д.
В настоящее время важное место среди мультимедиа-технологий занимает компьютерная
обработка видеоинформации, которая включает совокупность изображений, демонстрируемых
последовательно и позволяющих человеческому глазу воспринимать отображаемые объекты как
движущиеся.
Зрительный эффект движения достигается за счёт того, что каждое следующее
демонстрируемое изображение отличается от предыдущего небольшими последовательно
перемещающимися деталями. Следует отметить, что в обиходных ситуациях под термином
«видео» понимают ряд изображений, демонстрирующих движение, сопровождаемых звуковым
рядом.
Технологию мультимедиа образуют следующие компоненты:
• аппаратные средства компьютера, обеспечивающие доступ к данным и воспроизведение
мультимедийной информации;
• программные средства, обслуживающие доступ и воспроизведение;
• носители информации в мультимедиа-формате

5.

С математической точки зрения цифровое изображение представляет собой двумерную матрицу
Im[x,y][x,y] размера DimX×DimYDimX×DimY, где xx - целое число от 00 до DimX−1DimX−1, описывающее
номер элемента в строке матрицы, yy - целое число от 0 до DimY−1DimY−1, описывающее номер строки
матрицы, в которой расположен данный элемент.
При этом сам элемент цифрового изображения (ячейка прямоугольной матрицы) носит
название пикселпиксел (pixel, picture element). В простейшем случае каждый пиксел Im[x,y][x,y] имеет скалярное
целочисленное значение, пропорциональное значению функции распределения яркости f(x,y)f(x,y) в данной точке
плоскости.
На рисунке слева показано изображение женского лица, представленное как изображение, а справа показан
увеличенный фрагмент изображения того же лица (правый глаз), где для каждого элемента изображения указано
соответствующее числовое значение пиксела. Светлым элементам изображения соответствуют большие значения
матрицы, темным - меньшие значения.

6.

Библиотека Open CV
Для обработки цифровых изображений существует библиотека Open CV.
Это библиотека компьютерного зрения и машинного обучения с открытым исходным
кодом.
В неё входят более 2500 алгоритмов, в которых есть как классические, так и современные
алгоритмы для компьютерного зрения и машинного обучения.
Она имеет интерфейсы на различных языках, среди которых есть Python, Java, C++ и
Matlab.

7.

Python
Python — высокоуровневый язык программирования общего назначения с динамической
строгой типизацией и автоматическим управлением памятью, ориентированный на повышение
производительности разработчика, читаемости кода и его качества, а также на обеспечение переносимости
написанных на нём программ.
Для того, чтобы начать писать код на Python необходимо иметь установленный интерпретатор.
Эталонной реализацией Python является интерпретатор CPython, поддерживающий большинство
активно используемых платформ и являющийся стандартом языка. Он распространяется
под свободной лицензией Python Software Foundation License, позволяющей использовать его без
ограничений в любых приложениях.
Скачать интерпретатор можно на сайте: https://www.python.org/

8.

Исполнение Python кода
Программные файлы, с
расширением .py
Компилятор байт-кода
Файлы байт-кода, с
расширением .pyc
Выполнение на
виртуальной машине (PVM)

9.

Для написание кода можно использовать любой текстовый редактор, однако,
для удобства и быстроты разработки используются интегрированные среды
разработки (IDE).
Самой распространенной для Python является PyCharm (есть платная
и бесплатная версия)

10.

Скачать PyCharm
https://www.jetbrains.com/ru-ru/pycharm/download/#section=windows

11.

Подробные шаги по установке:
https://webformyself.com/kak-ustanovit-python-nawindows-pycharm-ide/

12.

Создание нового
проекта в PyCharm

13.

выбор версии интерпретатора

14.

Таким образом будет выглядеть только что созданный проект.

15.

Установка PyQt5 и Open CV

16.

PyQt5
PyQt5 - это набор Python библиотек для создания графического интерфейса на базе платформы Qt5 от
компании Digia. Библиотека Qt является одной из самых мощных библиотек GUI (графического
интерфейса пользователя).
PyQt5 реализован в виде набора python-модулей. Эта библиотека имеет более 620 классов и 6000 функций
и методов. Это мультиплатформенная библиотека, которая работает на всех основных операционных
системах, в том числе Unix, Windows и Mac OS.

17.

Для
установки
и
управления
программными пакетами, написанными на
Python, мы будем использовать систему
управления пакетами pip
Чтобы установить библиотеки с помощью
pip необходимо открыть терминал и
прописать следующую команду
pip install pyqt5 opencv-python
Затем необходимо нажать enter
дождаться установки библиотек
и

18.

Создание программы с графическим
интерфейсом

19.

1)
2)
Нажмем правой кнопкой мыши
по проекту.
Затем создадим два python-файла.
3)
Назовем их main.py, main_window.py, image_widget.py,
channels_window.py.

20.

from PyQt5.QtWidgets import (
QMainWindow,
QWidget,
QVBoxLayout,
QLabel
)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle("ImageViewer")
self.centralWidget = QWidget()
self.centralLayout = QVBoxLayout()
self.setCentralWidget(self.centralWidget)
self.centralWidget.setLayout(self.centralLayout)
self.setUI()
def setUI(self):
helloLabel = QLabel("Hello, PyQt5")
helloLabel.setFont(QFont('Arial', 32))
helloLabel.setAlignment(Qt.AlignCenter)
self.centralLayout.addWidget(helloLabel)
Откроем файл main_window.py и вставим
следующий код.
Сначала мы импортируем все необходимые
классы из PyQt. Далее мы создадим класс
MainWindow, который будет описывать
главное окно нашего приложения.
Метод __init__ является конструктором и
запускается при создании класса. В нем мы
описываем действия которые необходимо
выполнить при создании нового объекта
класса MainWindow.
В методе setUI мы будем создавать виджеты,
которые будут отображаться в главном окне. В
данном случае мы просто создаём текстовое
поле, в котором будет отображаться надпись
“Hello, PyQt5”.

21.

import sys
from PyQt5.QtWidgets import QApplication
from main_window import MainWindow
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
ex.showMaximized()
sys.exit(app.exec())
Далее откроем файл main.py и напишем
следующий код.
Каждое приложение PyQt5 должно создать объект
приложения (экземпляр QApplication). Параметр
sys.argv это список аргументов командной строки.
После создания
главное окно.
объекта
приложения
создаём

22.

Теперь можно попробовать его запустить. Для этого необходимо перейти в файл main.py и
нажать на зеленый треугольник
тэп хиар

23.

Вот, что должно получиться

24.

Создание виджета отображения изображений

25.

from PyQt5.QtWidgets import (
QWidget,
QVBoxLayout,
QLabel,
QSizePolicy,
QScrollArea,
)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QPalette, QPixmap
class ImageWidget(QWidget):
def __init__(self, title):
super(ImageWidget, self).__init__()
self.mainLayout = QVBoxLayout()
self.setLayout(self.mainLayout)
self.imageTitle = QLabel(title)
self.imageTitle.setFont(QFont('Arial', 12))
self.imageTitle.setAlignment(Qt.AlignCenter)
self.imageTitle.setFixedHeight(50)
self.imageLabel = QLabel()
self.imageLabel.setSizePolicy(
QSizePolicy.Ignored, QSizePolicy.Ignored)
self.imageLabel.setAlignment(Qt.AlignCenter)
self.imageScrollArea = QScrollArea()
self.imageScrollArea.setBackgroundRole(QPalette.Base)
self.imageScrollArea.setWidget(self.imageLabel)
self.imageScrollArea.setAlignment(Qt.AlignCenter)
self.mainLayout.addWidget(self.imageTitle)
self.mainLayout.addWidget(self.imageScrollArea)
def setPixmapFromImage(self, image):
self.imageLabel.setPixmap(QPixmap.fromImage(image))
self.imageLabel.adjustSize()
Откроем файл image_widget.py и добавим следующий
код.
Здесь
мы
создаём
вспомогательный
класс
ImageWidget, который служит для отображения
заголовка изображения и самого изображения. Также
данный класс будет отображать полосы прокрутки,
если изображение окажется слишком большим.
Метод setPixmapFromImage
отображаемого изображения.
служит
для
задания

26.

Создание шаблона пользовательского
интерфейса

27.

import cv2
from PyQt5.QtWidgets import (
QMainWindow,
QWidget,
QVBoxLayout,
QHBoxLayout,
QMessageBox,
QAction,
QFileDialog
)
from PyQt5.QtGui import QImage
from image_widget import ImageWidget
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle("ImageViewer")
self.centralWidget = QWidget()
self.centralLayout = QVBoxLayout()
self.setCentralWidget(self.centralWidget)
self.centralWidget.setLayout(self.centralLayout)
self.setUI()
self.setMenu()
Откроем файл main_window.py, подключим
библиотеку opencv и импортируем все
необходимые классы из библиотеки PyQt.
Добавим в конструктор класса
MainWindow вызов метода setMenu.

28.

def setUI(self):
self.imgLayout = QHBoxLayout()
self.origImageWidget = ImageWidget("Original Image")
self.editedImageWidget = ImageWidget("Edited Image")
self.imgLayout.addWidget(self.origImageWidget)
self.imgLayout.addWidget(self.editedImageWidget)
self.centralLayout.addLayout(self.imgLayout)
def setMenu(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
openAction = QAction('Open Image', self)
closeAction = QAction('Exit', self)
openAction.triggered.connect(self.openImage)
closeAction.triggered.connect(self.close)
fileMenu.addAction(openAction)
fileMenu.addSeparator()
fileMenu.addAction(closeAction)
Удалим предыдущий код из метода setUI
класса MainWindow и вставим код,
изображённый на картинке, в котором
мы создадим два окна просмотра
изображений, одно из которых будет
отображать изначальное изображение, а
второе изменённое.
Для создания меню с активными
выпадающими элементами, создадим
метод setMenu. В нём мы создадим
меню с двумя элементами: Open Image и
Exit. Первый нужен для открытия
изображения, второй для закрытия
программы. Далее мы назначаем
каждому элементу функцию, которая
будет вызываться при нажатии на этот
элемент.

29.

Чтобы осуществить открытие изображения используя файловую систему, добавим следующий метод в
класс MainWindow. В нём мы создаём диалоговое окно для выбора изображения, далее с помощью функции
cv2.imread мы считываем выбранное изображение в переменную self.origImage. Далее мы выводим
изображение на экран.
def openImage(self):
options = QFileDialog.Options()
fileName, _ = QFileDialog.getOpenFileName(self, ‘Open', '',
'Images (*.png *.jpeg *.jpg)', options=options)
if fileName:
image = QImage(fileName)
if image.isNull():
QMessageBox.information(self, "Image Viewer", "Cannot load %s." % fileName)
else:
self.origImage = cv2.imread(fileName)
self.editedImage = self.origImage.copy()
height, width = self.origImage.shape[:2]
bytesPerLine = 3 * width
qOrigImg = QImage(self.origImage, width, height, bytesPerLine, QImage.Format_BGR888)
qEditedImg = QImage(self.editedImage, width, height, bytesPerLine, QImage.Format_BGR888)
self.origImageWidget.setPixmapFromImage(qOrigImg)
self.editedImageWidget.setPixmapFromImage(qEditedImg)

30.

Проверка работы пунктов меню Open Image и Exit.
1) Выберем пункт меню
Open Image
2)
Открылся доступ к файловой системе.

31.

3) Выберем картинку для
отображения.
5) Если выбрать пункт Exit, то программа
завершит работу.
4) Она должна отобразиться в окне
приложения.

32.

Преобразование изображения из RGB в оттенки серого

33.

Изображение в оттенках серого использует черный цвет с разной насыщенностью для представления
каждой точки изображения, например, 8-битные числа 0-255.
Преобразование между значением RGB и оттенками серого на самом деле является преобразованием
восприятия цвета человеческим глазом в яркость. Существует формула:
Grey = 0.299*R + 0.587*G + 0.114*B
Согласно этой формуле считайте каждый пиксель R G B Value, вычислить значение серого
(преобразованное в целое число), присвоить значение серого соответствующей позиции нового
изображения и завершить преобразование после того, как пройдут все пиксели.
Чтобы избежать операций над числами с плавающей точкой, можно оптимизировать данную формулу и
получить следующее выражение:
Grey = (299*R + 587*G + 114*B + 500) /1000
Целочисленные операции будут усекать десятичную часть , а прибавление 500 нужно для округления и
уменьшения потери точности.

34.

Преобразование изображения из RGB с помощью Open CV может осуществляться либо
встроенной функцией, либо можно написать свой алгоритм.
Добавим метод getGrayscale. В нём мы получаем матрицы цветовых каналов изображения и затем
складываем их с нужными коэффициентами.
def getGrayscale(self):
blue, green, red = self.origImage[:, :, 0], self.origImage[:, :, 1], self.origImage[:, :, 2]
self.editedImage = 0.299 * red + 0.587 * green + 0.114 * blue
qImg = QImage(self.editedImage.astype(np.int8), self.editedImage.shape[1],
self.editedImage.shape[0], self.editedImage.shape[1], QImage.Format_Grayscale8)
self.editedImageWidget.setPixmapFromImage(qImg)

35.

Создадим кнопку “Gray”, при нажатии которую изображение будет преобразовываться из RGB в
grayscale. Для этого в файле main_window.py импортируем необходимые библиотеки и в методе
setUI добавим код, в котором мы создаём кнопку и назначаем ей в качестве обработчика метод
getGrayscale, чтобы при нажатии на эту кнопку исходное изображение преобразовывалось в
grayscale.
import cv2
import numpy as np
from PyQt5.QtWidgets import (
QMainWindow,
QWidget,
QVBoxLayout,
QHBoxLayout,
QMessageBox,
QAction,
QFileDialog,
QPushButton
)
from PyQt5.QtGui import QImage
from image_widget import ImageWidget
def setUI(self):
self.imgLayout = QHBoxLayout()
self.origImageWidget = ImageWidget("Original Image")
self.editedImageWidget = ImageWidget("Edited Image")
self.imgLayout.addWidget(self.origImageWidget)
self.imgLayout.addWidget(self.editedImageWidget)
self.actionLayout = QHBoxLayout()
self.toGrayButton = QPushButton("Gray")
self.toGrayButton.clicked.connect(self.getGrayscale)
self.toGrayButton.setEnabled(False)
self.actionLayout.addWidget(self.toGrayButton)
self.centralLayout.addLayout(self.imgLayout)
self.centralLayout.addLayout(self.actionLayout)
После этого добавим в конец метода openImage строчку
self.toGrayButton.setEnabled(True)

36.

Для проверки работоспособности нашей функции запускаем наше приложение, открываем
изображение и нажимаем на кнопку “Gray”. Мы видим что в окне Edited Image исходное
изображение отображается в формате grayscale.

37.

Разделение RGB изображения на три канала

38.

import cv2
import numpy as np
from PyQt5.QtWidgets import (
QWidget,
QVBoxLayout,
QHBoxLayout
)
from PyQt5.QtGui import QImage
from image_widget import ImageWidget
class ChannelsWindow(QWidget):
def __init__(self, image):
super().__init__()
self.setWindowTitle("Channels")
self.mainLayout = QVBoxLayout()
self.setLayout(self.mainLayout)
self.setUI()
self.getChannels(image)
def setUI(self):
self.channelsLayout = QHBoxLayout()
self.redChannelWidget = ImageWidget("Blue Channel")
self.greenChannelWidget = ImageWidget("Green Channel")
self.blueChannelWidget = ImageWidget("Red Channel")
self.channelsLayout.addWidget(self.redChannelWidget)
self.channelsLayout.addWidget(self.greenChannelWidget)
self.channelsLayout.addWidget(self.blueChannelWidget)
self.mainLayout.addLayout(self.channelsLayout)
Для отображения каждого канала по
отдельности создадим новый класс.
Для этого откроем файл channels_window.py и
вставим код с картинки.
В этом окне мы создаём три виджета для
просмотра каждого канала.

39.

В этом же классе создадим метод getChannels, в котором с помощью функции cv2.split мы разделяем
наше изображение на 3 канала и затем каждый из них выводим на экран.
def getChannels(self, image):
height, width = image.shape[:2]
blueChannel, greenChannel, redChannel = cv2.split(image)
zero_matrix = np.zeros((image.shape[0], image.shape[1]), dtype=np.uint8)
blueChannel = cv2.merge([zero_matrix, zero_matrix, blueChannel])
greenChannel = cv2.merge([zero_matrix, greenChannel, zero_matrix])
redChannel = cv2.merge([redChannel, zero_matrix, zero_matrix])
bytesPerLine = 3 * width
qBlueImg = QImage(blueChannel, width, height, bytesPerLine, QImage.Format_BGR888)
qGreenImg = QImage(greenChannel, width, height, bytesPerLine, QImage.Format_BGR888)
qRedImg = QImage(redChannel, width, height, bytesPerLine, QImage.Format_BGR888)
self.blueChannelWidget.setPixmapFromImage(qBlueImg)
self.greenChannelWidget.setPixmapFromImage(qGreenImg)
self.redChannelWidget.setPixmapFromImage(qRedImg)

40.

def getChannels(self):
self.dialog = ChannelsWindow(self.origImage)
self.dialog.showMaximized()
Возвращаемся в клаcc MainWindow и создаём
метод getChannels.
def setUI(self):
self.imgLayout = QHBoxLayout()
self.origImageWidget = ImageWidget("Original Image")
self.editedImageWidget = ImageWidget("Edited Image")
self.imgLayout.addWidget(self.origImageWidget)
self.imgLayout.addWidget(self.editedImageWidget)
Также в методе setUI добовляем код создания
кнопки “Get channels”.
self.actionLayout = QHBoxLayout()
self.toGrayButton = QPushButton("Gray")
self.getChannelsButton = QPushButton("Get channels")
self.toGrayButton.clicked.connect(self.getGrayscale)
self.getChannelsButton.clicked.connect(self.getChannels)
self.toGrayButton.setEnabled(False)
self.getChannelsButton.setEnabled(False)
self.actionLayout.addWidget(self.toGrayButton)
self.actionLayout.addWidget(self.getChannelsButton)
self.centralLayout.addLayout(self.imgLayout)
self.centralLayout.addLayout(self.actionLayout)
Затем в конец метода openImage вставляем
строчку self.getChannelsButton.setEnabled(True)

41.

Теперь можно попробовать запустить приложение и убедиться что все работает.
Для начала нажмем Open Image, выберем изображение и нажмем на кнопку Get Channels.
English     Русский Правила