[OpenCV-Python] 15 umbral de imagen

OpenCV-Python: Procesamiento de imágenes IV en OpenCV

15 Umbral de imagen

Objetivos
  • En esta sección, aprenderá umbrales simples, umbrales adaptativos, binarización de Otsu, etc.
  • Las funciones que se aprenderán incluyen cv2.threshold, cv2.adaptiveThreshold, etc.

15.1 Umbral simple

Como el nombre, este método es muy simple. Pero cuando el valor del píxel es mayor que el umbral, le damos a este píxel un nuevo valor (tal vez blanco), de lo contrario le damos otro color (tal vez negro). Esta función es cv2.threshhold (). El primer parámetro de esta función es la imagen original, que debería ser una imagen en escala de grises. El segundo parámetro es el umbral utilizado para clasificar los valores de los píxeles. El tercer parámetro es el nuevo valor de píxel que debe asignarse cuando el valor de píxel es más alto (y en ocasiones más bajo) que el umbral. OpenCV proporciona una variedad de métodos de umbral diferentes, que están determinados por el cuarto parámetro. Estos incluyen:
  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV
en el mapa extracto de "Aprendiendo OpenCV" versión en chino, de hecho, estos documentos se describen en el documento. directamente.
Esta función tiene dos valores de retorno, el primero es retVal, lo explicaremos más adelante. La segunda es la imagen resultante después del umbral.

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('gradient.png',0)
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

titles = ['Original Image','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()

Nota: Para mostrar varias imágenes en una ventana al mismo tiempo, usamos la función plt.subplot (). Puede consultar la documentación de Matplotlib para obtener más detalles.
Los resultados son los siguientes:

img

15.2 Umbral adaptativo

En la parte anterior, usamos el umbral global y toda la imagen usa el mismo número que el umbral. En ese momento, este método no era adecuado para todas las situaciones, especialmente cuando diferentes partes de la misma imagen tenían diferente brillo. En este caso, necesitamos utilizar un umbral adaptativo. El umbral en este momento es calcular el umbral correspondiente a cada área pequeña de la imagen. Por lo tanto, se utilizan diferentes umbrales en diferentes áreas de la misma imagen, de modo que podamos obtener mejores resultados en diferentes condiciones de brillo.
Este método requiere que especifiquemos tres parámetros y solo un valor de retorno.
  • Método adaptativo: especifique el método para calcular el umbral.
  - Cv2.ADPTIVE_THRESH_MEAN_C: El umbral se toma del valor medio de las áreas adyacentes - cv2.ADPTIVE_THRESH_GAUSSIAN_C: El umbral se toma
  como la suma ponderada de las áreas adyacentes y el peso es una ventana gaussiana.
  • Tamaño del bloque: el tamaño del vecindario (el tamaño del área utilizada para calcular el umbral).
  • C: es una constante y el umbral es igual al promedio o promedio ponderado menos esta constante.
Usamos el siguiente código para mostrar la diferencia entre un umbral simple y un umbral adaptativo:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('dave.jpg',0)
img = cv2.medianBlur(img,5)

ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.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()

resultado:

Umbral adaptativo

15.3 Binarización de Otsu

Mencionamos retVal en la primera parte, que se utilizará cuando usemos la binarización de Otsu. Entonces, ¿qué es esto exactamente?
  Cuando usamos el umbral global, simplemente damos un número aleatorio como umbral Entonces, ¿cómo sabemos si el número que elegimos es bueno o malo? La respuesta es seguir intentándolo. ¿Qué pasa si es una imagen bimodal (en términos simples, una imagen bimodal se refiere a la presencia de dos picos en el histograma de la imagen)? ¿No deberíamos elegir un valor en el valle entre los dos picos como umbral? Esto es lo que hace la binarización de Otsu. En pocas palabras, se calcula automáticamente un umbral para un par de imágenes bimodales en función de su histograma. (Para imágenes no bimodales, los resultados obtenidos por este método pueden ser insatisfactorios).
La función utilizada aquí sigue siendo cv2.threshold (), pero se debe pasar un parámetro más (marca) en: cv2.THRESH_OTSU. En este momento, establezca el umbral en 0. Luego, el algoritmo encontrará el umbral óptimo, que es el valor de retorno retVal. Si no se usa la binarización de Otsu, el valor de retVal devuelto es igual al umbral establecido.
  En el siguiente ejemplo, la imagen de entrada es una imagen ruidosa. En el primer método, establecemos 127 como el umbral global. En el segundo método, usamos directamente la binarización de Otsu. En el tercer método, primero usamos un kernel gaussiano de 5x5 para eliminar el ruido y luego usamos la binarización de Otsu. Vea cuánto ruido tiene la eliminación de los resultados.

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('noisy2.png',0)

# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5),0)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.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()

[Error en la transferencia de la imagen del enlace externo. El sitio de origen puede tener un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-GOu08fsr-1611975237177) (http: //opencv-python-tutroals.readthedocs. io / en / latest / _images /otsu.jpg)]

15.4 ¿Cómo funciona la binarización de Otsu?

En esta parte, demostraremos cómo usar Python para implementar el algoritmo de binarización de Otsu, a fin de decirle cómo funciona. Si no está interesado, puede omitir esta sección. Debido a que es un gráfico bimodal, el algoritmo de Otsu es encontrar un umbral (t) que minimice la varianza ponderada de la misma clase, y debe satisfacerse la siguiente relación:

entre ellos:

De hecho, se trata de encontrar un umbral t entre los dos picos, separar los dos picos y minimizar la varianza dentro de cada pico. El código de Python para implementar este algoritmo es el siguiente:

img = cv2.imread('noisy2.png',0)
blur = cv2.GaussianBlur(img,(5,5),0)

# find normalized_histogram, and its cumulative distribution function
hist = cv2.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.max()
Q = hist_norm.cumsum()

bins = np.arange(256)

fn_min = np.inf
thresh = -1

for i in xrange(1,256):
    p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
    q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
    b1,b2 = np.hsplit(bins,[i]) # weights

    # finding means and variances
    m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2
    v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2

    # calculates the minimization function
    fn = v1*q1 + v2*q2
    if fn < fn_min:
        fn_min = fn
        thresh = i

# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
prin(thresh,ret)

(Hay algunas funciones nuevas aquí, hablaremos de ellas en capítulos posteriores)

Para obtener más información, preste atención a la cuenta oficial:
img

Supongo que te gusta

Origin blog.csdn.net/yegeli/article/details/113418371
Recomendado
Clasificación