Изображение – это массив пикселей. На данный момент есть множество задач для выполнения которых требуется выбирать пиксель выше (ниже, между) определенного порогового значения. Для решения подобных задач применяем функцию cvThreshold().
Если значение пикселя больше порогового значения, ему присваивается одно значение (может быть белым), иначе ему присваивается другое значение (может быть черным). Используемая функцию равна порогу. Первый аргумент – это исходное изображение, которое должно быть полутоновым изображением. Второй аргумент - это пороговое значение, которое используется для классификации значений пикселей. Третий аргумент - maxVal|, который представляет значение, которое должно быть задано, если значение пикселя больше (иногда меньше) порогового значения. OpenCV предоставляет разные стили порога и определяется четвертым параметром функции. Различные типы:
cv.THRESH_BINARY
cv.THRESH_BINARY_INV
cv. THRESH_TRUNC
cv. THRESH_TOZERO
cv. THRESH_TOZERO_INV
cv. THRESH_OTSU
Документация четко объясняет, для чего предназначен каждый тип.
Ниже представлен код:
import cv2 as cv import numpy as np
from matplotlib import pyplot as plt img = cv.imread('gradient.png',0)
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV) ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC) ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO) ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
titles = ['OriginalImage','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV'] images = [img, thresh1, thresh2, thresh3, thresh4, thresh5] for i in xrange(6): plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
Рисунок 11 – Методы бинаризации изображения
Если изображение имеет различные условия освещения в разных
областях. В этом случае мы идем на адаптивное пороговое значение. При этом алгоритм вычисляет порог для небольших областей изображения. Таким образом, мы получаем разные пороговые значения для разных областей одного и того же изображения, и это дает нам лучшие результаты для изображений с различным освещением. Он имеет три «специальных» входных параметра и только один выходной аргумент.
Адаптивный метод. Он определяет, как вычисляется пороговое значения.
cv.ADAPTIVE_THRESH_MEAN_C: пороговое значение является
средним значением области окрестности.
cv.ADAPTIVE_THRESH_GAUSSIAN_C: пороговое значение
представляет собой взвешенную сумму значений окрестности, где веса
являются гауссовым окном.
BlockSize - размер окрестности (в пикселях), которая используется для
расчёта порогового значения.
C - это просто константа, которая вычитается из среднего или
взвешенного среднего значения.
Пример кода:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('sudoku.png',0)
img = cv.medianBlur(img,5)
ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\ cv.THRESH_BINARY,11,2)
th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\ cv.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in xrange(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
В глобальном пороговом значении используется произвольное значение для порогового значения. Для того что бы определить насколько хорошо выбран порог необходимо сделать несколько итераций по выбранному порогу. Но если рассмотреть бимодальное изображение (бимодальное изображение - изображение, гистограмма которого имеет два пика). Для этого изображения возможно приблизительно выбрать значение в середине этих пиков как пороговое значение. Это то, что делает бинаризация Оtsu. Таким образом он автоматически вычисляет пороговое значение из гистограммы изображения для бимодального изображения. (Для изображений, которые не являются бимодальными, бинаризация не будет точной.) Для этого используется функция cv.threshold(), но с дополнительным флагом cv.THRESH_OTSU. Для порогового значения будет выполнен ноль. Затем алгоритм находит оптимальное пороговое значение и возвращает в качестве второго выхода retVal. Если порог Otsu не используется, retVal будет таким же, как и пороговое значение, которое использовалось изначально.
Пример бинаризации методом Оцу изображен на рисунке 12. Входное изображение - шумное изображение. В первом случае применено глобальное пороговое значение для значения 127. Во втором случае применен порог Otsu напрямую. В третьем случае отфильтровано изображение с 5х5 гауссовым ядром, чтобы удалить шум, а затем применен порог Otsu.
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('noisy2.png',0)
# global thresholding
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
'Original Noisy Image','Histogram',"Otsu's Thresholding",
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in xrange(3):
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray') plt.title(titles[i*3]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256) plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([]) plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray') plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([]) plt.show()