OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

OpenCV Thresholding i Python med cv2.threshold()

Beskrivning

Tröskelvärde är en enkel och effektiv teknik för att utföra grundläggande segmentering i en bild, och att binarisera den (förvandla den till en binär bild) där pixlar är antingen 0 or 1 (eller 255 om du använder heltal för att representera dem).

Vanligtvis kan du använda tröskelvärde för att utföra enkel bakgrunds-förgrundssegmentering i en bild, och det kokar ner till varianter av en enkel teknik för varje pixel:

if pixel_value > threshold:
    pixel_value = MAX
else:
    pixel_value = 0

Denna väsentliga process är känd som Binär tröskel. Nu – det finns olika sätt du kan justera den här allmänna idén, inklusive att invertera operationerna (växling av > skylt med a < tecken), ställa in pixel_value till threshold i stället för ett maxvärde/0 (känd som trunkering), behåller du pixel_value själv om det är över threshold eller om det är under threshold.

Alla dessa har bekvämt implementerats i OpenCV som:

  • cv2.THRESH_BINARY
  • cv2.THRESH_BINARY_INV
  • cv2.THRESH_TRUNC
  • cv2.THRESH_TOZERO
  • cv2.THRESH_TOZERO_INV

… respektive. Det här är relativt "naiva" metoder eftersom de är ganska enkla, inte tar hänsyn till sammanhang i bilder, har kunskap om vilka former som är vanliga, etc. För dessa egenskaper – skulle vi behöva använda mycket mer beräkningsmässigt dyrare och kraftfullare tekniker.

Nu, även med de "naiva" metoderna – några heuristik kan sättas på plats för att hitta bra trösklar, och dessa inkluderar Otsu-metoden och Triangelmetoden:

  • cv2.THRESH_OTSU
  • cv2.THRESH_TRIANGLE

Notera: OpenCV-tröskelvärde är en rudimentär teknik och är känslig för ljusförändringar och gradienter, färgheterogenitet, etc. Det är bäst att applicera på relativt rena bilder, efter att de har suddats ut för att minska brus, utan större färgvariationer i de objekt du vill segmentera.

Ett annat sätt att övervinna några av problemen med grundläggande tröskelvärde med ett enda tröskelvärde är att använda adaptiv tröskel som tillämpar ett tröskelvärde på varje liten region i en bild, snarare än globalt.

Enkel tröskelvärde med OpenCV

Tröskelvärde i OpenCV:s Python API görs via cv2.threshold() metod – som accepterar en bild (NumPy-matris, representerad med heltal), tröskelvärdet, maximivärdet och tröskelmetoden (hur threshold och maximum_value används):

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

img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)


blurred = cv2.GaussianBlur(img, (7, 7), 0)

ret, img_masked = cv2.threshold(blurred, 220, 255, cv2.THRESH_BINARY)

Returkoden är bara den tillämpade tröskeln:

print(f"Threshold: {ret}") 

Här, eftersom tröskeln är 220 och vi har använt THRESH_BINARY metod – varje pixelvärde ovan 220 kommer att ökas till 255, medan varje pixelvärde nedan 220 kommer att sänkas till 0, skapa en svartvit bild med en "mask" som täcker förgrundsobjekten.

Varför 220? Genom att veta hur bilden ser ut kan du göra några ungefärliga gissningar om vilken tröskel du kan välja. I praktiken vill du sällan ställa in en manuell tröskel, och vi kommer att täcka automatiskt val av tröskel på ett ögonblick.

Låt oss plotta resultatet! OpenCV-fönster kan vara lite kräsna, så vi plottar originalbilden, suddig bild och resultat med Matplotlib:

fig, ax = plt.subplots(1, 3, figsize=(12, 8))
ax[0].imshow(img)
ax[1].imshow(blurred)
ax[2].imshow(img_masked)

Tröskelmetoder

Som nämnts tidigare finns det olika sätt du kan använda tröskelvärdet och maxvärdet i en funktion. Vi har först tittat på den binära tröskeln. Låt oss skapa en lista med metoder och tillämpa dem en efter en, och rita resultaten:

methods = [cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO, cv2.THRESH_TOZERO_INV]
names = ['Binary Threshold', 'Inverse Binary Threshold', 'Truncated Threshold', 'To-Zero Threshold', 'Inverse To-Zero Threshold']

def thresh(img_path, method, index):
    img = cv2.imread(img_path)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    blurred = cv2.GaussianBlur(img, (7, 7), 0)
    ret, img_masked = cv2.threshold(blurred, 220, 255, method)

    fig, ax = plt.subplots(1, 3, figsize=(12, 4))
    fig.suptitle(names[index], fontsize=18)
    ax[0].imshow(img)
    ax[1].imshow(blurred)
    ax[2].imshow(img_masked)
    plt.tight_layout()

for index, method in enumerate(methods):
    thresh('coins.jpeg', method, index)

THRESH_BINARY och THRESH_BINARY_INV är omvända till varandra och binarisera en bild mellan 0 och 255, tilldela dem till bakgrunden respektive förgrunden, och vice versa.

THRESH_TRUNC binariserar bilden mellan threshold och 255.

THRESH_TOZERO och THRESH_TOZERO_INV binarisera mellan 0 och det aktuella pixelvärdet (src(x, y)). Låt oss ta en titt på de resulterande bilderna:

OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Kolla in vår praktiska, praktiska guide för att lära dig Git, med bästa praxis, branschaccepterade standarder och medföljande fuskblad. Sluta googla Git-kommandon och faktiskt lära Det!

OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Dessa metoder är intuitiva nog - men hur kan vi automatisera ett bra tröskelvärde, och vad betyder ens ett "bra tröskelvärde"? De flesta av resultaten hittills hade icke-ideala masker, med märken och fläckar i dem. Detta händer på grund av skillnaden i de reflekterande ytorna på mynten – de är inte jämnt färgade på grund av skillnaden i hur åsar reflekterar ljus.

Vi kan till viss del bekämpa detta genom att hitta en bättre global tröskel.

Automatisk/optimerad tröskelvärde med OpenCV

OpenCV använder två effektiva globala tröskelsökningsmetoder – Otsus metod och Triangelmetoden.

Otsus metod förutsätter att den fungerar bimodal bilder. Bimodala bilder är bilder vars färghistogram bara innehåller två toppar (dvs. har bara två distinkta pixelvärden). Med tanke på att var och en av topparna tillhör en klass som "bakgrund" och "förgrund" - är den idealiska tröskeln mitt emellan dem.

OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
Image Credit: https://scipy-lectures.org/

Du kan göra vissa bilder mer bi-modala med gaussisk oskärpa, men inte alla.

En alternativ, ofta bättre presterande algoritm är triangelalgoritmen, som beräknar avståndet mellan maximum och minimum för grånivåhistogrammet och ritar en linje. Den punkt där den linjen är maximalt långt borta från resten av histogrammet väljs som tröskel:

OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Båda dessa förutsätter en gråskalebild, så vi måste konvertera ingångsbilden till grå via cv2.cvtColor():

img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (7, 7), 0)

ret, mask1 = cv2.threshold(blurred, 0, 255, cv2.THRESH_OTSU)
ret, mask2 = cv2.threshold(blurred, 0, 255, cv2.THRESH_TRIANGLE)

masked = cv2.bitwise_and(img, img, mask=mask1)

Låt oss köra igenom bilden med båda metoderna och visualisera resultatet:

methods = [cv2.THRESH_OTSU, cv2.THRESH_TRIANGLE]
names = ['Otsu Method', 'Triangle Method']

def thresh(img_path, method, index):
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (7, 7), 0)

    ret, img_masked = cv2.threshold(blurred, 0, 255, method)
    print(f"Threshold: {ret}")

    fig, ax = plt.subplots(1, 3, figsize=(12, 5))
    fig.suptitle(names[index], fontsize=18)
    ax[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    ax[1].imshow(cv2.cvtColor(gray, cv2.COLOR_BGR2RGB))
    ax[2].imshow(cv2.cvtColor(img_masked, cv2.COLOR_BGR2RGB))

for index, method in enumerate(methods):
    thresh('coins.jpeg', method, index)

OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Här överträffar triangelmetoden Otsus metod, eftersom bilden inte är bi-modal:

import numpy as np

img = cv2.imread('coins.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (7, 7), 0)

histogram_gray, bin_edges_gray = np.histogram(gray, bins=256, range=(0, 255))
histogram_blurred, bin_edges_blurred = np.histogram(blurred, bins=256, range=(0, 255))

fig, ax = plt.subplots(1, 2, figsize=(12, 4))

ax[0].plot(bin_edges_gray[0:-1], histogram_gray)
ax[1].plot(bin_edges_blurred[0:-1], histogram_blurred)

OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Det är dock tydligt hur triangelmetoden kunde arbeta med bilden och ge ett mer tillfredsställande resultat.

Begränsningar för OpenCV Thresholding

Tröskelvärde med OpenCV är enkelt, enkelt och effektivt. Ändå är det ganska begränsat. Så fort du introducerar färgglada element, ojämna bakgrunder och ändrade ljusförhållanden – blir global tröskel som koncept för stel.

Bilder är vanligtvis för komplexa för att en enskild tröskel ska räcka, och detta kan delvis åtgärdas adaptiv tröskel, där många lokala trösklar tillämpas istället för en enda global. Även om den är begränsad, är adaptiv tröskelvärde mycket mer flexibel än global tröskel.

Slutsats

Under de senaste åren har binär segmentering (som vad vi gjorde här) och multi-label segmentering (där du kan ha ett godtyckligt antal klasser kodade) framgångsrikt modellerats med djupinlärningsnätverk, som är mycket kraftfullare och mer flexibla. Dessutom kan de koda globala och lokala sammanhang i bilderna de segmenterar. Nackdelen är – du behöver data för att träna dem, såväl som tid och expertis.

För enkla tröskelvärden i farten kan du använda OpenCV. För korrekt segmentering på produktionsnivå bör du använda neurala nätverk.

Going Further – Praktisk djupinlärning för datorseende

Din nyfikna natur gör att du vill gå längre? Vi rekommenderar att du kollar in vår Kurs: "Praktisk djupinlärning för datorseende med Python".

OpenCV Thresholding i Python med cv2.threshold() PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Ännu en kurs i datorseende?

Vi kommer inte att göra klassificering av MNIST-siffror eller MNIST-mode. De tjänade sin del för länge sedan. Alltför många inlärningsresurser fokuserar på grundläggande datamängder och grundläggande arkitekturer innan de låter avancerade blackbox-arkitekturer bära bördan av prestanda.

Vi vill fokusera på avmystifiering, praktiskhet, förståelse, intuition och riktiga projekt. Vill lära sig hur du kan göra skillnad? Vi tar dig med på en tur från hur våra hjärnor bearbetar bilder till att skriva en klassificerare för djupinlärning för bröstcancer i forskningsklass till nätverk för djupinlärning som "hallucinerar", lär dig principer och teorier genom praktiskt arbete, och utrustar dig med kunskap och verktyg för att bli expert på att tillämpa djupinlärning för att lösa datorseende.

Vad är inuti?

  • De första principerna för syn och hur datorer kan läras att "se"
  • Olika uppgifter och tillämpningar av datorseende
  • Branschens verktyg som gör ditt arbete enklare
  • Hitta, skapa och använda datauppsättningar för datorseende
  • Teorin och tillämpningen av Convolutional Neural Networks
  • Hantera domänskifte, samtidig förekomst och andra fördomar i datamängder
  • Överför Lärande och utnyttja andras träningstid och beräkningsresurser till din fördel
  • Bygga och träna en toppmodern klassificerare för bröstcancer
  • Hur man applicerar en hälsosam dos av skepsis på mainstream idéer och förstår implikationerna av allmänt använda tekniker
  • Visualisera ett ConvNets "konceptutrymme" med t-SNE och PCA
  • Fallstudier av hur företag använder datorseendetekniker för att uppnå bättre resultat
  • Korrekt modellutvärdering, latent rumsvisualisering och identifiering av modellens uppmärksamhet
  • Utföra domänforskning, bearbeta dina egna datamängder och upprätta modelltester
  • Banbrytande arkitekturer, utvecklingen av idéer, vad som gör dem unika och hur man implementerar dem
  • KerasCV – ett WIP-bibliotek för att skapa toppmoderna pipelines och modeller
  • Hur man analyserar och läser uppsatser och implementerar dem själv
  • Välja modeller beroende på din applikation
  • Skapa en komplett maskininlärningspipeline
  • Landskap och intuition på objektdetektering med snabbare R-CNN, RetinaNets, SSD och YOLO
  • Instans och semantisk segmentering
  • Objektigenkänning i realtid med YOLOv5
  • Träning av YOLOv5-objektdetektorer
  • Arbeta med transformatorer med KerasNLP (industristarkt WIP-bibliotek)
  • Integrering av Transformers med ConvNets för att generera bildtexter
  • DeepDream
  • Deep Learning-modelloptimering för datorseende

Tidsstämpel:

Mer från Stackabuse