Skip to content

Binarizzare un’immagine con Python, NumPy, OpenCV

Python

Questo articolo descrive come binarizzare un’immagine in bianco e nero con una soglia.

Ci sono due modi: uno è usare la funzione OpenCV cv2.threshold() e l’altro è elaborare ndarray con un’operazione di base di NumPy. OpenCV non è necessario in quest’ultimo caso.

  • Binarizzazione delle immagini con OpenCV:cv2.threshold()
  • Soglia automatica dell’immagine (metodo di Otsu, ecc.)
  • Binarizzazione delle immagini con NumPy (senza OpenCV)
    • Per immagini in scala di grigi
    • Per immagine a colori

Nel codice di esempio seguente, la versione di OpenCV è 4.2. Si noti che il comportamento potrebbe essere diverso con versioni diverse. È possibile ottenere la documentazione ufficiale di ciascuna versione al seguente.

Binarizzazione delle immagini con OpenCV:cv2.threshold()

Prendi l’immagine seguente come esempio.

import cv2

im = cv2.imread('data/src/lena_square_half.png')

lena

Puoi binarizzare un’immagine con cv2.threshold().

Se type è impostato su cv2.THRESH_BINARY, valore maggiore della soglia thresh viene sostituito con maxval e gli altri valori vengono sostituiti con 0.

Nel caso di immagini a colori, ogni colore (canale) viene elaborato separatamente. Se vuoi immagini in bianco e nero, convertile prima in scala di grigi come nell’esempio di cv2.THRESH_OTSU più avanti.

th, im_th = cv2.threshold(im, 128, 255, cv2.THRESH_BINARY)

print(th)
# 128.0

cv2.imwrite('data/dst/opencv_th.jpg', im_th)

lena Soglia OpenCV THRESH_BINARY

Viene restituita una tupla di soglia utilizzata e matrice elaborata (immagine di output). Può essere memorizzato in ogni variabile come nell’esempio sopra.

Quando type è impostato su cv2.THRESH_TOZERO, il valore maggiore della soglia Thresh rimane lo stesso e gli altri valori vengono sostituiti con 0.

th, im_th_tz = cv2.threshold(im, 128, 255, cv2.THRESH_TOZERO)

print(th)
# 128.0

cv2.imwrite('data/dst/opencv_th_tz.jpg', im_th_tz)

lena OpenCV soglia THRESH_TOZERO

Vedere la documentazione ufficiale di seguito per i valori che è possibile specificare per il tipo.

maxval non viene utilizzato con cv2.THRESH_TOZERO e thresh non viene utilizzato con cv2.THRESH_OTSU e cv2.THRESH_TRIANGLE descritti in seguito, ma non possono essere omessi.

Soglia automatica dell’immagine (metodo di Otsu, ecc.)

Quando type è impostato su cv2.THRESH_OTSU, la soglia viene selezionata automaticamente dal metodo di Otsu, e se è impostato su cv2.THRESH_TRIANGLE, la soglia viene selezionata automaticamente dal metodo del triangolo.

Si noti che cv2.THRESH_OTSU e cv2.THRESH_TRIANGLE supportano solo immagini a canale singolo a 8 bit a partire dalla versione 4.2.0. Si verificherà un errore se viene specificata un’immagine a colori (array tridimensionale).

# th, im_th_otsu = cv2.threshold(im, 128, 192, cv2.THRESH_OTSU)
# error: OpenCV(4.2.0) /tmp/opencv-20200105-17262-cwpzm4/opencv-4.2.0/modules/imgproc/src/thresh.cpp:1529: error: (-215:Assertion failed) src.type() == CV_8UC1 in function 'threshold'

Converti in scala di grigi e quindi usa cv2.threshold().

im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

th, im_gray_th_otsu = cv2.threshold(im_gray, 128, 192, cv2.THRESH_OTSU)

print(th)
# 117.0

cv2.imwrite('data/dst/opencv_th_otsu.jpg', im_gray_th_otsu)

lena OpenCV soglia THRESH_OTSU

I valori maggiori della soglia selezionata vengono automaticamente sostituiti con maxval e gli altri valori vengono sostituiti con 0. Nell’esempio precedente, maxval è impostato su 192 per la spiegazione. Se vuoi eseguire la binarizzazione in bianco e nero, puoi impostarlo su 255.

Binarizzazione delle immagini con NumPy (senza OpenCV)

Se vuoi solo eseguire il binarizzazione in bianco e nero con valori di soglia, puoi farlo con le operazioni NumPy di ​​base.

Per immagini in scala di grigi

Come semplice esempio, binarizza un’immagine in scala di grigi.

import numpy as np
from PIL import Image

im_gray = np.array(Image.open('data/src/lena_square_half.png').convert('L'))
print(type(im_gray))
# 

Qui, ad esempio senza OpenCV, l’immagine viene letta da Pillow e convertita in ndarray.

Naturalmente, non ci sono problemi a leggere le immagini con OpenCV. Nota che l’ordine dei colori è diverso quando leggi un’immagine a colori con OpenCV.

lena grigio

Confrontare l’operatore di su un array NumPy ndarray confronta un ndarray booleano che confronta ogni elemento dell’array.

thresh = 128

im_bool = im_gray > thresh
print(im_bool)
# [[ True  True  True ...  True  True False]
#  [ True  True  True ...  True  True False]
#  [ True  True  True ...  True False False]
#  ...
#  [False False False ... False False False]
#  [False False False ... False False False]
#  [False False False ... False False False]]

Poiché True è considerato 1 e False è considerato 0, moltiplicato per 255 che è il valore massimo di uint8, True diventa 255 (bianco) e False diventa 0 (nero).

maxval = 255

im_bin = (im_gray > thresh) * maxval
print(im_bin)
# [[255 255 255 ... 255 255   0]
#  [255 255 255 ... 255 255   0]
#  [255 255 255 ... 255   0   0]
#  ...
#  [  0   0   0 ...   0   0   0]
#  [  0   0   0 ...   0   0   0]
#  [  0   0   0 ...   0   0   0]]

Image.fromarray(np.uint8(im_bin)).save('data/dst/numpy_binarization.png')

binarizzazione lena NumPy THRESH_BINARY

L’esempio precedente corrisponde a cv2.threshold() con cv2.THRESH_BINARY.

Se si moltiplica il valore booleano ndarray del risultato del confronto per l’originale ndarray, il valore in pixel di True rimane originale e il valore in pixel di False è 0 (nero), che corrisponde a cv2.THRESH_TOZERO.

im_bin_keep = (im_gray > thresh) * im_gray
print(im_bin_keep)
# [[162 161 156 ... 169 169   0]
#  [162 161 156 ... 169 169   0]
#  [164 155 159 ... 145   0   0]
#  ...
#  [  0   0   0 ...   0   0   0]
#  [  0   0   0 ...   0   0   0]
#  [  0   0   0 ...   0   0   0]]

Image.fromarray(np.uint8(im_bin_keep)).save('data/dst/numpy_binarization_keep.png')

binarizzazione lena NumPy THRESH_TOZERO

Per immagine a colori

Applicando valori diversi a ciascun colore RGB, puoi creare un’immagine colorata.

Genera un ndarray vuoto tridimensionale con np.empty() e memorizza i risultati della moltiplicazione di ogni colore (ogni canale) per ciascun valore.

La dimensione (altezza, larghezza) ottenuta da shape viene decompressa da * e specificata in np.empty().

im_bool = im_gray > 128
im_dst = np.empty((*im_gray.shape, 3))
r, g, b = 255, 128, 32

im_dst[:, :, 0] = im_bool * r
im_dst[:, :, 1] = im_bool * g
im_dst[:, :, 2] = im_bool * b

Image.fromarray(np.uint8(im_dst)).save('data/dst/numpy_binarization_color.png')

colore di binarizzazione lena NumPy

È anche possibile applicare l’operatore di negazione ~ al booleano ndarray.

im_bool = im_gray > 128
im_dst = np.empty((*im_gray.shape, 3))
r, g, b = 128, 160, 192

im_dst[:, :, 0] = im_bool * r
im_dst[:, :, 1] = ~im_bool * g
im_dst[:, :, 2] = im_bool * b

Image.fromarray(np.uint8(im_dst)).save('data/dst/numpy_binarization_color2.png')

lena NumPy binarizzazione color2

Si noti che quando si salva un’immagine con la funzione OpenCV cv2.imwrite(), è necessario impostare la sequenza di colori su BGR.

Finora, è elaborato in base all’immagine in scala di grigi, ma è anche possibile elaborare l’immagine a colori come cv2.threshold() con la stessa idea dell’esempio sopra.

Genera un ndarray vuoto e memorizza ogni risultato in ogni colore (ogni canale). Poiché l’originale è un’immagine a colori (array tridimensionale), viene utilizzato np.empty_like().

im = np.array(Image.open('data/src/lena_square_half.png'))

im_th = np.empty_like(im)

thresh = 128
maxval = 255

for i in range(3):
    im_th[:, :, i] = (im[:, :, i] > thresh) * maxval

Image.fromarray(np.uint8(im_th)).save('data/dst/numpy_binarization_from_color.png')

binarizzazione di lena NumPy da colore

È possibile un’elaborazione più flessibile rispetto a cv2.threshold(), come la modifica del valore di soglia o la modifica del valore di sostituzione per ciascun colore. Puoi scrivere in modo ordinato usando una lista (o una tupla) e zip().

l_thresh = [64, 128, 192]
l_maxval = [64, 128, 192]

for i, thresh, maxval in zip(range(3), l_thresh, l_maxval):
    im_th[:, :, i] = (im[:, :, i] > thresh) * maxval

Image.fromarray(np.uint8(im_th)).save('data/dst/numpy_binarization_from_color2.png')

binarizzazione di lena NumPy da color2