Bildefiltrering i Python

Har du noen gang kommet over et støyende bilde? Jeg mener et bilde som ikke var så klart når du så på det? Jeg tror vi kommer over slike bilder veldig ofte, spesielt når mange bilder i dag tas av våre mobiltelefonkameraer eller digitale kameraer med lav oppløsning.

Hvis du bare hadde det støyende bildet som betyr noe for deg, men problemet er at det ikke kan sees på riktig måte, ville det være en løsning å gjenopprette fra slik støy?

Dette er hvor bildefiltrering kommer til spill, og dette er hva jeg skal beskrive i denne opplæringen. La oss komme i gang!

Bildefiltrering

Bildefiltrering er et populært verktøy som brukes i bildebehandling. På slutten av dagen bruker vi bildefiltrering for å fjerne støy og uønskede funksjoner fra et bilde, og skape en bedre og en forbedret versjon av bildet. To typer filtre eksisterer: lineær og ikke-lineær. Eksempler på lineære filtre er gjennomsnittlige og Laplacian filtre. Ikke-lineære filtre utgjør filtre som median, minimum, maksimum og Sobel-filtre.

Hver av disse filtrene har et bestemt formål, og er utformet for å enten fjerne støy eller forbedre noen aspekter i bildet. Men hvordan går det med filtrering? Dette er hva vi vil se i neste avsnitt.

Hvordan utfører vi bildefiltrering?

For å utføre en bildefiltreringsprosess trenger vi en filter, også kalt a maske. Dette filteret er vanligvis et todimensjonalt firkantet vindu, det er et vindu med lik dimensjoner (bredde og høyde). 

Filteret vil inkludere tall. Disse tallene kalles koeffisienter, og de er det som faktisk bestemmer filterets effekt og hva utgangsbildet vil se ut. Figuren under viser et eksempel på a 3x3 filter, med ni verdier (koeffisienter).

For å bruke filteret, skal 3x3 vinduet glir over bildet. Denne prosessen med å skyve et filtervindu over et bilde kalles konvolusjon i det romlige domenet. Vinduet vil bli plassert på hver piksel (dvs. tenk på det som en celle i en matrise) i bildet, hvor sentrum av filteret skal overlappe det pikselet. 

Når denne overlappingen skjer, blir pikslene i underbildet som filteret er på toppen multiplisert med de korresponderende koeffisientene til filteret. I dette tilfellet vil vi ha en ny matrise med nye verdier som ligner filterets størrelse (dvs.. 3x3). Endelig vil den sentrale pikselverdien bli erstattet av en ny verdi ved å bruke en spesifikk matematisk ligning, avhengig av hvilken type filter som brukes (dvs. medianfilter).

Jeg vet at ovennevnte avsnitt er litt wordy. La oss ta et eksempel for å vise hvordan et bildefilter brukes i handling. Anta at vi har følgende underbilde der vårt filter overlappes (Jeg og j referer til pikselplasseringen i underbildet, og Jeg refererer til bildet):

Konvolusjonen av filteret som vises i den første figuren med ovenstående underbilde, vil se som vist nedenfor, hvor I_new (i, j) representerer resultatet på stedet (I, j).

(I-1, j + 1) + v2 x I (i-1, j) + v3 x I (i-1, j + 1) + v4 x I (i, j-1) + v5 x I (i, j) + v6 x I (i, j + 1) + v7 x I (i + 1, j-1) + v8 x I (i + 1, j) + v9 x I (i + 1, j + 1) 

Prosessen gjentas for hver piksel i bildet, inkludert pikslene ved grensen til bildet. Men som du kan gjette, vil en del av filteret ligge utenfor bildet når du plasserer filteret ved grensepikselene. I dette tilfellet utfører vi padding

Denne prosessen betyr ganske enkelt at vi legger inn nye pikselverdier i underbildet under delen av filteret som kommer utenfor bildet før konvolusjonsprosessen, siden den delen tilsynelatende ikke inneholder noen pikselverdier. Det er utenfor bildet! De polstrede pikslene kan være nuller eller en konstant verdi. Det finnes andre metoder for å angi polstringsverdiene, men disse er utenfor omfanget av denne opplæringen.

Jeg tror det er nok teori for nå, så la oss gå videre og få våre hender skitne med koding! I denne opplæringen vil jeg forklare medianfilteret (dvs. ikke-lineært) og det gjennomsnittlige filteret (dvs. lineært) og hvordan vi kan implementere dem i Python. 

Median Filter

I medianfilteret velger vi et skyvevindu som vil bevege seg over alle bildepikselene. Det vi gjør her er at vi samler pikselverdiene som kommer under filteret og tar medianen av disse verdiene. Resultatet blir tildelt sentrumspiksel. 

Si oss 3x3 filteret hadde følgende verdier etter å ha plassert det på et underbilde:

La oss se hvordan du skal beregne medianen. Medianen, i sin essens, er den midten nummer på en sortert liste over tall. For å finne medianen for det ovennevnte filteret, sorterer vi derfor tallene fra laveste til høyeste, og midten av tallene vil være vår medianverdi. Sortere verdiene i vår 3x3 vinduet vil gi oss følgende:

17 29 43 57 59 63 65 84 98

For å finne mellomtallet (medianen), teller vi bare antall verdier vi har, legger til 1 til det nummeret, og deles med 2. Dette gir oss plasseringen av mellomverdien i vinduet, som er vår medianverdi. Så vil medianverdien være på stedet 9 + 1/2 = 5, som er 59. Denne verdien blir den nye verdien av pikselet under sentrum av vår 3x3 vindu.

Denne typen filter brukes til å fjerne støy, og fungerer best med bilder som lider av salt og pepper bråk. Bildet nedenfor viser et eksempel på et bilde som lider av slik lyd:

La oss nå skrive et Python-skript som vil bruke medianfilteret til bildet ovenfor. For dette eksempelet bruker vi OpenCV-biblioteket. Vennligst sjekk Installer OpenCV-Python i Windows og installer OpenCV 3.0 og Python 2.7+ på Ubuntu for å installere OpenCV.

For å bruke medianfilteret bruker vi bare OpenCVs cv2.medianBlur () funksjon. Vårt skript kan således se ut som følger:

importer cv2 import argparse # opprett argumentet parser og analyser argumentene ap = argparse.ArgumentParser () ap.add_argument ('- i', '--image', required = True, help = 'Path to the input image') args = vars (ap.parse_args ()) # les bildet image = cv2.imread (args ['image']) # bruk 3x3 medianfilter på bildet processed_image = cv2.medianBlur (image, 3) # display image cv2. imshow ('Median Filter Processing', processed_image) # lagre bilde på disk cv2.imwrite ('processed_image.png', processed_image) # pause utførelsen av manuset til en tast på tastaturet er trykket cv2.waitKey (0)

Legg merke til at jeg har brukt argparse, som det er en god praksis å være fleksibel her, og bruk kommandolinjen til å passere bildet vi vil bruke medianfilteret på som et argument til vårt program. 

Etter å ha bestått bildet vårt som et kommandolinjearument, leser vi bildet ved hjelp av cv2.imread () funksjon. Vi bruker deretter medianfilteret ved hjelp av medianBlur () funksjon, passerer bilde og filterstørrelse som parametere. Bildet vises med cv2.imshow () funksjon, og lagres på disken ved hjelp av cv2.imwrite ().

Resultatet av det ovennevnte skriptet er som følger:

Vel, hva synes du? Veldig vakkert - et fint og rent bilde uten støy.

Du kan laste ned koden ovenfor fra mittmedian-filterarkivet på GitHub.

Gjennomsnittlig filter

Det gjennomsnittlige filteret er et eksempel på et lineært filter. Det erstatter i utgangspunktet hver piksel i utgangsbildet med gjennomsnittlig (gjennomsnittlig) verdi av nabolaget. Dette gjør at bildet utjevnes (reduserer intensitetsvariasjonene mellom en piksel og den neste), fjerner støy fra bildet og lyser bildet.

Dermed vil i gjennomsnitt filtrering, hver piksel av bildet bli erstattet med middelverdien av naboene, inkludert selve pikselet. De 3x3 kjernen som brukes til gjennomsnittlig filtrering er som vist i figuren under, selv om andre kjernestørrelser kunne brukes (dvs. 5x5):

Hva den ovennevnte kjernen faktisk prøver å fortelle oss er at vi summerer alle elementene under kjernen og tar middelverdien av (gjennomsnittet) av totalen.

Et viktig poeng å nevne her er at alle elementene i middelkjernen skal:

  • sum til 1
  • vær den samme

La oss ta et eksempel for å gjøre tingene mer klare. Si at vi har følgende underbilde:

Ved bruk av det gjennomsnittlige filteret, ville vi gjøre følgende:

(7 + 9 + 23 + 76 + 91 + 7 + 64 + 90 + 32) / 9 = 44

Det nøyaktige resultatet er 44,3, men jeg avrundet resultatet til 44. Så er den nye verdien for midten piksel 44 i stedet for 91.

Nå til kodingsdelen. La oss si at vi har følgende støyende bilde:

Det vi vil gjøre på dette punktet, gjelder det gjennomsnittlige filteret på bildet ovenfor og se effekten av å bruke et slikt filter.

Koden for å gjøre denne operasjonen er som følger:

import cv2 import numpy som np import argparse # opprett argumentet parser og analyser argumentene ap = argparse.ArgumentParser () ap.add_argument ('- i', '--image', required = True, help = 'Sti til inngangen bilde) args = vars (ap.parse_args ()) # les bildet image = cv2.imread (args ['image']) # bruk 3x3 middelfilter på bildekjernen = np.ones ((3,3) , np.float32) / 9 processed_image = cv2.filter2D (bilde, -1, kjernen) # vise bilde cv2.imshow ('Mean Filter Processing', processed_image) # lagre bilde på disk cv2.imwrite ('processed_image.png' processed_image) # pause utførelsen av manuset til en tast på tastaturet er trykket cv2.waitKey (0)

Legg merke til koden vi har brukt a 3x3 kjernen for vårt gjennomsnittlige filter. Vi har også brukt filter2D () funksjon for å bruke gjennomsnittlig filter. Den første parameteren til denne funksjonen er vårt inngangsbilde, det andre er ønsket dybde for utdatabildet ddepth, og den tredje parameteren er kjernen vår. tildele -1 for ddepth parameter betyr at utgangsbildet vil ha samme dybde som inngangsbilde.

Etter å ha kjørt koden på vårt støyende bilde, var dette resultatet jeg fikk:

Hvis du ser utgangsbildet, kan vi se at det er jevnere enn det støyende bildet. Oppdrag gjort!

Du kan laste ned koden ovenfor fra mitt gjennomsnittlige filterlager på GitHub.

Konklusjon

Som vi har sett i denne opplæringen, tillater Python oss å utføre avanserte oppgaver som bildefiltrering, spesielt gjennom sitt OpenCV-bibliotek, på en enkel måte.

I tillegg, ikke nøl med å se hva vi har tilgjengelig for salg og for studier på markedet, og ikke nøl med å stille spørsmål og gi din verdifulle tilbakemelding ved hjelp av feedet under.