Рубрики
Без рубрики

Введение в обработку изображений на Python с помощью OpenCV

В статье дается краткое введение в различные задачи обработки изображений с помощью языка программирования Python.

Автор оригинала: Muhammad Junaid Khalid.

Вступление

В этом уроке мы узнаем, как мы можем выполнять обработку изображений с помощью языка Python. Мы не собираемся ограничиваться одной библиотекой или фреймворком; однако есть одна, которую мы будем использовать чаще всего, – библиотека Open CV . Мы начнем с небольшого разговора об обработке изображений, а затем перейдем к рассмотрению различных приложений/сценариев, где обработка изображений может пригодиться. Итак, начнем!

Что такое Обработка изображений?

Важно знать, что именно представляет собой обработка изображений и какова ее роль в общей картине, прежде чем погружаться в ее “как”. Обработка изображений чаще всего называется “Цифровой обработкой изображений”, а область, в которой она часто используется, – “Компьютерное зрение”. Не смущайтесь – мы будем говорить об обоих этих терминах и о том, как они связаны. Как алгоритмы обработки изображений, так и алгоритмы компьютерного зрения (CV) принимают изображение в качестве входных данных; однако в обработке изображений выход также является изображением , тогда как в компьютерном зрении выход может быть некоторыми функциями/информацией об изображении.

Зачем нам это нужно?

Данные, которые мы собираем или генерируем, в основном являются необработанными данными, то есть они не подходят для непосредственного использования в приложениях по ряду возможных причин. Поэтому нам нужно сначала проанализировать его, выполнить необходимую предварительную обработку, а затем использовать.

Например, предположим, что мы пытались построить классификатор cat. Наша программа взяла бы изображение в качестве входных данных, а затем сказала бы нам, содержит ли изображение кошку или нет. Первым шагом для создания этого классификатора было бы собрать сотни изображений кошек. Одна общая проблема заключается в том, что все фотографии, которые мы соскоблили, не будут иметь одинакового размера/размеров, поэтому, прежде чем подавать их в модель для обучения, нам нужно будет изменить размер/предварительно обработать их все до стандартного размера.

Это лишь одна из многих причин, почему обработка изображений необходима для любого приложения компьютерного зрения.

Предпосылки

Прежде чем идти дальше, давайте обсудим, что вам нужно знать, чтобы легко следовать этому учебнику. Во-первых, вы должны иметь некоторые базовые знания программирования на любом языке. Во-вторых, вы должны знать, что такое машинное обучение и основы его работы, так как в этой статье мы будем использовать некоторые алгоритмы машинного обучения для обработки изображений. В качестве бонуса было бы полезно, если бы вы имели какое-либо представление или базовые знания об OpenCV, прежде чем приступить к этому учебнику. Но этого и не требуется.

Одна вещь, которую вы определенно должны знать, чтобы следовать этому учебнику, – это то, как именно изображение представлено в памяти. Каждое изображение представлено набором пикселей, то есть матрицей значений пикселей. Для изображения в оттенках серого значения пикселей варьируются от 0 до 255, и они представляют интенсивность этого пикселя. Например, если у вас есть изображение размером 20 х 20, оно будет представлено матрицей 20х20 (всего 400 пикселей).

Если вы имеете дело с цветным изображением, вы должны знать, что оно будет иметь три канала – Красный, зеленый и синий (RGB). Следовательно, для одного изображения таких матриц было бы три.

Установка

Примечание: Поскольку мы собираемся использовать OpenCV через Python, это неявное требование, чтобы у вас уже был Python (версия 3), уже установленный на вашей рабочей станции.

Окна

$ pip install opencv-python

macOS

$ brew install opencv3 --with-contrib --with-python3

Линукс

$ sudo apt-get install libopencv-dev python-opencv

Чтобы проверить, была ли ваша установка успешной или нет, выполните следующую команду либо в оболочке Python, либо в командной строке:

import cv2

Некоторые Основы, Которые Вы Должны Знать

Прежде чем мы перейдем к использованию обработки изображений в приложении, важно получить представление о том, какие операции относятся к этой категории и как их выполнять. Эти операции, наряду с другими, будут использоваться позже в наших приложениях. Итак, давайте перейдем к делу.

Для этой статьи мы будем использовать следующее изображение:

исходное изображение, используемое для базовой обработки изображений

Примечание : Изображение было масштабировано для отображения его в этой статье, но исходный размер, который мы используем, составляет около 1180×786.

Вы, наверное, заметили, что изображение в данный момент окрашено, а это значит, что оно представлено тремя цветовыми каналами-Красным, Зеленым и Синим. Мы будем преобразовывать изображение в оттенки серого, а также разбивать изображение на отдельные каналы, используя приведенный ниже код.

Поиск Деталей Изображения

После загрузки изображения с помощью функции imread() мы можем получить некоторые простые свойства о нем, такие как количество пикселей и размеры:

import cv2

img = cv2.imread('rose.jpg')

print("Image Properties")
print("- Number of Pixels: " + str(img.size))
print("- Shape/Dimensions: " + str(img.shape))

Выход:

Image Properties
- Number of Pixels: 2782440
- Shape/Dimensions: (1180, 786, 3)

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

Теперь мы разделим изображение на его красные, зеленые и синие компоненты с помощью OpenCV и отобразим их:

from google.colab.patches import cv2_imshow

blue, green, red = cv2.split(img) # Split the image into its channels
img_gs = cv2.imread('rose.jpg', cv2.IMREAD_GRAYSCALE) # Convert image to grayscale

cv2_imshow(red) # Display the red channel in the image
cv2_imshow(blue) # Display the red channel in the image
cv2_imshow(green) # Display the red channel in the image
cv2_imshow(img_gs) # Display the grayscale version of image

Для краткости мы просто покажем изображение в оттенках серого.

Изображение в оттенках серого:

изображение цветка в оттенках серого

Пороговое значение изображения

Концепция порогового значения довольно проста. Как обсуждалось выше в представлении изображения, значения пикселей могут быть любыми значениями от 0 до 255. Допустим, мы хотим преобразовать изображение в двоичное, то есть присвоить пикселю значение 0 или 1. Для этого мы можем выполнить пороговое значение. Например, если Пороговое значение (T) равно 125, то всем пикселям со значениями больше 125 будет присвоено значение 1, а всем пикселям со значениями меньше или равными этому будет присвоено значение 0. Давайте сделаем это с помощью кода, чтобы лучше понять.

Изображение, используемое для порогового значения:

изображение, используемое для порогового значения
import cv2

# Read image
img = cv2.imread('image.png', 0)

# Perform binary thresholding on the image with T = 125
r, threshold = cv2.threshold(img, 125, 255, cv2.THRESH_BINARY)
cv2_imshow(threshold)

Выход:

выход порогового значения изображения

Как вы можете видеть, в результирующем изображении были установлены две области: черная область (значение пикселя 0) и белая область (значение пикселя 1). Оказывается, порог, который мы установили, находился прямо в середине изображения, поэтому черно-белые значения разделены там.

Приложения

#1: Удаление шума из изображения

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

В большинстве случаев необработанные данные, которые мы собираем, содержат шум, то есть нежелательные функции, которые затрудняют восприятие изображения. Хотя эти изображения могут быть использованы непосредственно для извлечения признаков, точность алгоритма сильно пострадает. Вот почему обработка изображений применяется к изображению перед передачей его алгоритму для получения большей точности.

Существует много различных типов шума, таких как гауссовский шум, шум соли и перца и т. Д. Мы можем удалить этот шум из изображения, применив фильтр, который удаляет этот шум или, по крайней мере, минимизирует его эффект. Есть много вариантов, когда дело доходит до фильтров, каждый из них имеет разную силу и, следовательно, является лучшим для определенного вида шума.

Чтобы понять это правильно, мы добавим шум “соль и перец” к оттенкам серого изображения розы, которое мы рассмотрели выше, а затем попытаемся удалить этот шум из нашего шумного изображения с помощью различных фильтров и посмотрим, какой из них лучше всего подходит для этого типа.

import numpy as np

# Adding salt & pepper noise to an image
def salt_pepper(prob):
      # Extract image dimensions
      row, col = img_gs.shape

      # Declare salt & pepper noise ratio
      s_vs_p = 0.5
      output = np.copy(img_gs)

      # Apply salt noise on each pixel individually
      num_salt = np.ceil(prob * img_gs.size * s_vs_p)
      coords = [np.random.randint(0, i - 1, int(num_salt))
            for i in img_gs.shape]
      output[coords] = 1

      # Apply pepper noise on each pixel individually
      num_pepper = np.ceil(prob * img_gs.size * (1. - s_vs_p))
      coords = [np.random.randint(0, i - 1, int(num_pepper))
            for i in img_gs.shape]
      output[coords] = 0
      cv2_imshow(output)

      return output

# Call salt & pepper function with probability = 0.5
# on the grayscale image of rose
sp_05 = salt_pepper(0.5)

# Store the resultant image as 'sp_05.jpg'
cv2.imwrite('sp_05.jpg', sp_05)

Хорошо, мы добавили шум к нашему розовому изображению, и вот как оно выглядит сейчас:

Шумное Изображение:

изображение с шумом

Теперь давайте применим к нему различные фильтры и запишем ваши наблюдения, то есть насколько хорошо каждый фильтр уменьшает шум.

Арифметический фильтр с ядром заточки
# Create our sharpening kernel, the sum of all values must equal to one for uniformity
kernel_sharpening = np.array([[-1,-1,-1],
                              [-1, 9,-1],
                              [-1,-1,-1]])

# Applying the sharpening kernel to the grayscale image & displaying it.
print("\n\n--- Effects on S&P Noise Image with Probability 0.5 ---\n\n")

# Applying filter on image with salt & pepper noise
sharpened_img = cv2.filter2D(sp_05, -1, kernel_sharpening)
cv2_imshow(sharpened_img)

Полученное изображение, полученное в результате применения арифметического фильтра к изображению с шумом соли и перца, показано ниже. При сравнении с исходным изображением в оттенках серого мы видим, что оно слишком сильно осветляет изображение и не может выделить яркие пятна на розе. Следовательно, можно сделать вывод, что арифметический фильтр не в состоянии удалить шум соли и перца.

Выход арифметического фильтра:

изображение без шума через арифметический фильтр
Фильтр средней точки
from scipy.ndimage import maximum_filter, minimum_filter

def midpoint(img):
    maxf = maximum_filter(img, (3, 3))
    minf = minimum_filter(img, (3, 3))
    midpoint = (maxf + minf) / 2
    cv2_imshow(midpoint)

print("\n\n---Effects on S&P Noise Image with Probability 0.5---\n\n")
midpoint(sp_05)

Полученное изображение, полученное в результате применения фильтра средней точки к изображению с шумом соли и перца, показано ниже. При сравнении с исходным изображением в оттенках серого мы видим, что, как и описанный выше метод ядра, изображение слишком сильно светится, однако он способен выделить яркие пятна на розе. Поэтому можно сказать, что это лучший выбор, чем арифметический фильтр, но все же он не восстанавливает исходное изображение полностью.

Выход фильтра Средней точки:

изображение без шума через фильтр средней точки
Контрагармонический Средний фильтр

Примечание : Реализации этих фильтров можно легко найти в Интернете, и то, как именно они работают, выходит за рамки этого учебника. Мы будем рассматривать приложения с абстрактного/более высокого уровня.

def contraharmonic_mean(img, size, Q):
    num = np.power(img, Q + 1)
    denom = np.power(img, Q)
    kernel = np.full(size, 1.0)
    result = cv2.filter2D(num, -1, kernel) / cv2.filter2D(denom, -1, kernel)
    return result

print("\n\n--- Effects on S&P Noise Image with Probability 0.5 ---\n\n")
cv2_imshow(contraharmonic_mean(sp_05, (3,3), 0.5))

Результирующее изображение, полученное в результате применения Контрагармонического среднего фильтра на изображении с шумом соли и перца, показано ниже. При сравнении с исходным изображением в оттенках серого мы видим, что оно воспроизводит почти то же самое изображение, что и исходное. Его интенсивность/уровень яркости одинаковы, и он также выделяет яркие пятна на розе. Таким образом, мы можем сделать вывод, что контрагармонический средний фильтр очень эффективен в борьбе с шумом соли и перца.

Выход Контрагармонического Среднего фильтра:

изображение без шума через контрагармонический фильтр

Теперь, когда мы нашли лучший фильтр для восстановления исходного изображения из шумного, мы можем перейти к следующему приложению.

#2: Обнаружение краев с помощью детектора Canny Edge

Изображение розы, которое мы использовали до сих пор, имеет постоянный фон, то есть черный, поэтому мы будем использовать другое изображение для этого приложения, чтобы лучше показать возможности алгоритма. Причина в том, что если фон постоянен, это делает задачу обнаружения границ довольно простой, а мы этого не хотим.

Ранее в этом уроке мы говорили о классификаторе cat, давайте рассмотрим этот пример и посмотрим, как обработка изображений играет в этом важную роль.

В алгоритме классификации изображение сначала сканируется на наличие “объектов”, то есть когда вы вводите изображение, алгоритм находит все объекты на этом изображении, а затем сравнивает их с признаками объекта, который вы пытаетесь найти. В случае классификатора кошек он будет сравнивать все объекты, найденные на изображении, с признаками изображения кошки, и если совпадение будет найдено, он сообщит нам, что входное изображение содержит кошку.

Поскольку мы используем кошку, классифицированную как пример, будет справедливо, если мы будем использовать образ кошки в будущем. Ниже приведено изображение, которое мы будем использовать:

Изображение, используемое для обнаружения краев:

изображение, используемое для обнаружения краев
import cv2
import numpy as np
from matplotlib import pyplot as plt

# Declaring the output graph's size
plt.figure(figsize=(16, 16))

# Convert image to grayscale
img_gs = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imwrite('gs.jpg', img_gs)

# Apply canny edge detector algorithm on the image to find edges
edges = cv2.Canny(img_gs, 100,200)

# Plot the original image against the edges
plt.subplot(121), plt.imshow(img_gs)
plt.title('Original Gray Scale Image')
plt.subplot(122), plt.imshow(edges)
plt.title('Edge Image')

# Display the two images
plt.show()

Выход обнаружения края:

выход обнаружения края

Как вы можете видеть, часть изображения, содержащая объект, который в данном случае является кошкой, была пунктирно/разделена с помощью обнаружения краев. Теперь вы, должно быть, задаетесь вопросом, что такое Canny Edge Detector и как это произошло; так что давайте обсудим это сейчас.

Чтобы понять вышесказанное, необходимо обсудить три ключевых шага. Во-первых, он выполняет шумоподавление изображения аналогично тому, что мы обсуждали ранее. Во-вторых, он использует первую производную в каждом пикселе для поиска ребер. Логика этого заключается в том, что в точке, где существует ребро, происходит резкое изменение интенсивности, которое вызывает всплеск значения первой производной, следовательно, делая этот пиксель “краевым пикселем”.

В конце концов, он выполняет гистерезисное пороговое значение; мы сказали выше, что есть всплеск значения первой производной на краю, но мы не указали, “насколько высоким” должен быть всплеск, чтобы его можно было классифицировать как край – это называется порогом! Ранее в этом уроке мы обсуждали, что такое простое пороговое значение. Гистерезисное пороговое значение является улучшением этого, оно использует два пороговых значения вместо одного. Причина этого заключается в том, что если пороговое значение слишком велико, мы можем пропустить некоторые фактические ребра (истинные отрицательные значения), а если значение слишком низкое, мы получим множество точек, классифицированных как ребра, которые на самом деле не являются ребрами (ложные положительные значения). Одно пороговое значение устанавливается высоким, а другое – низким. Все точки, которые находятся выше “высокого порогового значения”, идентифицируются как ребра, затем оцениваются все точки, которые находятся выше низкого порогового значения, но ниже высокого порогового значения; точки, которые находятся близко или являются соседями точек, которые были идентифицированы как ребра, также оцениваются.

Это основные понятия/методы, которые алгоритм Canny Edge Detector использует для идентификации ребер в изображении.

Вывод

В этой статье мы узнали, как установить OpenCV, самую популярную библиотеку для обработки изображений на Python, на различные платформы, такие как Windows, macOS и Linux, а также как проверить, что установка прошла успешно.

Далее мы обсудили, что такое Обработка изображений и как она используется в области машинного обучения компьютерного зрения. Мы говорили о некоторых распространенных типах шума и о том, как мы можем удалить его из наших изображений с помощью различных фильтров, прежде чем использовать изображения в наших приложениях.

Кроме того, мы узнали, как обработка изображений играет важную роль в таких высокотехнологичных приложениях, как обнаружение или классификация объектов. Обратите внимание, что эта статья была лишь верхушкой айсберга, а цифровая обработка изображений имеет гораздо больше в магазине, что невозможно охватить в одном учебнике. Прочитав это, вы сможете погрузиться глубже и узнать о других передовых концепциях, связанных с обработкой изображений. удачи!