Billedbehandling OpenCV

Billedbehandling Opencv



Vi vil studere billedbehandlingsmetoderne i denne artikel. Vi vil undersøge nogle grundlæggende, men kritiske emner inden for computervision og maskinlæring. Disse grundlæggende billedbehandlingsteknikker kan løse komplekse problemer, såsom datasæt. Som et resultat er der seks grundlæggende trin i billedbehandling, som er anført nedenfor:
  1. Billedoversættelse
  2. Billedrotation
  3. Billedregning
  4. Billedvender
  5. Billedbeskæring
  6. Ændring af billedstørrelse

Nu vil vi forklare alle de ovennævnte billedbehandlingsemner i detaljer.

1. Billedoversættelse

Billedoversættelse er en billedbehandlingsmetode, der hjælper os med at flytte billedet langs x- og y-aksen. Vi kan flytte billedet op, ned, til højre, til venstre eller en hvilken som helst kombination.







Vi kan definere oversættelsesmatrixen med symbolet M, og vi kan repræsentere den i matematisk form, som vist nedenfor:





Vi kan forstå konceptet med oversættelsesbilledet gennem dette program.





Python kode: Vi beholder følgende programs navn som translate.py .

# importer nødvendige pakker

importere nusset som for eksempel.

importere argparse

importere imutil

importere cv2

# vi implementerer argumentparseren

ap_obj = argparse. ArgumentParser ( )

ap_obj. add_argument ( '-k' , '--billede' , påkrævet = Sand ,

Hjælp = 'placering af billedfilen' )

args = hvis ( ap_obj. parse_args ( ) )

# indlæs billedet og vis det på skærmen

billede = cv2. imread ( args [ 'billede' ] )

cv2. imshow ( 'Original_image' , billede )

# Oversættelsen af ​​billedet er en NumPy-matrix, som er givet nedenfor:

# [[1, 0, shiftX], [0, 1, shiftY]]

# Vi vil bruge ovenstående NumPy-matrix til at flytte billederne langs

# x-akse og y-akse retninger. Til dette skal vi blot videregive pixelværdierne.

# I dette program flytter vi billedet 30 pixels til højre

# og 70 pixels mod bunden.

translation_mat = for eksempel. flyde 32 ( [ [ 1 , 0 , 30 ] , [ 0 , 1 , 70 ] ] )

billedoversættelse = cv2. warpAffine ( billede , translation_mat ,

( billede. form [ 1 ] , billede. form [ 0 ] ) )

cv2. imshow ( 'Billedoversættelse ned og til højre' , billedoversættelse )

# nu skal vi bruge ovenstående NumPy-matrix til at flytte billederne langs

# x-akse (venstre) og y-akse (op) retninger.

# Her skal vi flytte billederne 50 pixels til venstre

# og 90 pixels opad.

translation_mat = for eksempel. flyde 32 ( [ [ 1 , 0 , - halvtreds ] , [ 0 , 1 , - 90 ] ] )

billedoversættelse = cv2. warpAffine ( billede , translation_mat ,

( billede. form [ 1 ] , billede. form [ 0 ] ) )

cv2. imshow ( 'Billedoversættelse op og til venstre' , billedoversættelse )

cv2. ventenøgle ( 0 )

Linje 1 til 5: Vi importerer alle de nødvendige pakker til dette program, såsom OpenCV, argparser og NumPy. Bemærk venligst, at der er et andet bibliotek, som er imutils. Dette er ikke en pakke med OpenCV. Dette er blot et bibliotek, der nemt viser den samme billedbehandling.



Bibliotekets imutils vil ikke blive inkluderet automatisk, når vi installerer OpenCV. Så for at installere imutilerne skal vi bruge følgende metode:

pip install imutils

Linje 8 til 15: Vi oprettede vores agrparser og indlæste vores billede.

Linje 24 til 25: Denne programsektion er der, hvor oversættelsen finder sted. Oversættelsesmatrixen fortæller os, hvor mange pixels billedet vil blive flyttet op eller ned eller til venstre eller højre. Fordi OpenCV kræver, at matrixværdien er i et floating-point-array, tager oversættelsesmatrixen værdier i floating-point-arrays.

Oversættelsesmatrixens første række ser således ud:

Denne række af matrixen er for x-aksen. Værdien af ​​t x vil afgøre, om billedet skal flyttes til venstre eller højre side. Hvis vi passerer en negativ værdi, betyder det, at billedet vil blive flyttet til venstre side, og hvis værdien er positiv, betyder det, at billedet vil blive flyttet til højre side.

Vi vil nu definere den anden række af matricen som følger:

Denne række af matrixen er for y-aksen. Værdien af ​​t Y vil afgøre, om billedet skal flyttes op eller ned. Hvis vi passerer en negativ værdi, betyder det, at billedet vil blive forskudt til opsiden, og hvis værdien er positiv, betyder det, at billedet vil blive forskudt til nedadgående.

I det foregående program på linje 24 definerer vi t x = 30 og t Y = 70. Så vi flytter billedet 30 pixels mod højre side og 70 pixels nedad.

Men den vigtigste billedoversættelsesproces foregår på linje 25, hvor vi definerer oversættelsesmatrixen cv2.warpAffine . I denne funktion sender vi tre parametre: den første parameter er billedet, den anden parameter er oversættelsesmatrixen, og den tredje parameter er billeddimensionen.

Linje 27: Linje 27 viser resultatet i outputtet.

Nu vil vi implementere en anden oversættelsesmatrix til venstre og opad. Til dette skal vi definere værdierne i negative.

Linje 33 til 34: I det foregående program på linje 33 definerer vi t x = -50 og t Y = -90. Så vi flytter billedet 50 pixels mod venstre side og 90 pixels opad. Men den vigtigste billedoversættelsesproces foregår på linje 34, hvor vi definerer oversættelsesmatrixen cv2.warpAffine .

Linje 36 : Linjen 36 vil vise resultatet som vist i outputtet.

For at køre den forrige kode skal vi angive stien til billedet som angivet nedenfor.

Produktion: python translate.py –image squirrel.jpg

Nu vil vi implementere det samme billedoversættelsesprogram ved hjælp af imutil bibliotek. Dette bibliotek er meget nemt at bruge til billedbehandling. I dette bibliotek behøver vi ikke tænke på cv2.warpAffine fordi dette bibliotek tager sig af dette. Så lad os implementere dette billedoversættelsesprogram ved hjælp af imutils-biblioteket.

Python kode: Vi beholder følgende programs navn som translate_imutils.py .

# importer de nødvendige pakker

importere nusset som for eksempel.

importere argparse

importere imutil

importere cv2

# Denne funktion implementerer billedoversættelsen og

# returnerer det oversatte billede til den kaldende funktion.

def Oversætte ( billede , x , Y ) :

translation_matrix = for eksempel. flyde 32 ( [ [ 1 , 0 , x ] , [ 0 , 1 , Y ] ] )

billedoversættelse = cv2. warpAffine ( billede , translation_matrix ,

( billede. form [ 1 ] , billede. form [ 0 ] ) )

Vend tilbage billedoversættelse

# konstruer argumentparseren og pars argumenterne

ap = argparse. ArgumentParser ( )

ap. add_argument ( '-jeg' , '--billede' , påkrævet = Sand , Hjælp = 'Sti til billedet' )

args = hvis ( ap. parse_args ( ) )

# indlæs billedet og vis det på skærmen

billede = cv2. imread ( args [ 'billede' ] )

cv2. imshow ( 'Original_image' , billede )

billedoversættelse = imutil. Oversætte ( billede , 10 , 70 )

cv2. imshow ( 'Billedoversættelse til højre og nedadgående' ,

billedoversættelse )

cv2. ventenøgle ( 0 )

Linje 9 til 13: Denne del af programmet er, hvor oversættelsen sker. Oversættelsesmatrixen fortæller os, hvor mange pixels billedet vil blive flyttet op eller ned eller til venstre eller højre.

Disse linjer er allerede blevet forklaret, men nu skal vi bygge en funktion kaldet translate () og sende tre forskellige parametre ind i den. Selve billedet fungerer som den første parameter. Oversættelsesmatrixens x- og y-værdier svarer til den anden og tredje parameter.

Bemærk : Der er ingen grund til at definere denne oversættelsesfunktion inde i programmet, fordi den allerede er inkluderet i imutils bibliotekspakke. Jeg har brugt det i programmet af hensyn til ligetil forklaring. Vi kan kalde denne funktion direkte med imutilerne, som vist i linje 24.

Linje 24: Det forrige program vil vise, at vi ved linje 24 definerer tx = 10 og ty = 70. Så vi flytter billedet 10 pixels mod højre side og 70 pixels nedad.

I dette program er vi ligeglade med nogen cv2.warpAffine-funktioner, fordi de allerede er inde i imutils-bibliotekspakken.

For at køre den forrige kode skal vi angive stien til billedet, som angivet nedenfor:

Produktion:

python imutils. py --billede egern. jpg

2. Billedrotation

Vi gennemgik, hvordan man oversætter (dvs. flytter) et billede op, ned, til venstre og til højre i den forrige lektion (eller en hvilken som helst kombination). Dernæst vil vi diskutere rotation, som det vedrører billedbehandling.

Et billede roteres med en vinkel, theta, i en proces kendt som rotation. Vinklen, som vi roterer billedet med, vil blive repræsenteret af theta. Derudover vil jeg efterfølgende levere den roterende bekvemmelighedsfunktion for at gøre roterende billeder enklere.

I lighed med translation, og måske ikke overraskende, rotation med en vinkel, bestemmes theta ved at bygge en matrix M i følgende format:

Denne matrix kan rotere en vektor theta grader (mod uret) omkring den givne oprindelse (x, y) - kartesisk plan. Normalt, i dette scenarie, ville oprindelsen være midten af ​​billedet, men i virkeligheden kan vi udpege et hvilket som helst tilfældigt (x, y) punkt som vores rotationscenter.

Det roterede billede R skabes derefter ud fra det originale billede I ved hjælp af ligetil matrixmultiplikation: R = IM

OpenCV, på den anden side, tilbyder desuden kapaciteten til (1) at skalere (dvs. ændre størrelse på) et billede og (2) tilbyde et vilkårligt rotationscenter til at udføre rotationen rundt.

Vores modificerede rotationsmatrix M er vist nedenfor:

Lad os starte med at åbne og generere en ny fil kaldet rotate.py :

# importerer de nødvendige pakker

importere nusset som for eksempel.

importere argparse

importere imutil

importere cv2

# oprettelse af argumentparser-objektet og parsing-argumentet

apobj = argparse. ArgumentParser ( )

apobj. add_argument ( '-k' , '--billede' , påkrævet = Sand , Hjælp = 'billedsti' )

argumenter = hvis ( apobj. parse_args ( ) )

billede = cv2. imread ( argumenter [ 'billede' ] )

cv2. imshow ( 'Original_image' , billede )

# Beregn billedets centrum ved hjælp af billedets dimensioner.

( højde , bredde ) = billede. form [ : 2 ]

( centerX , centerY ) = ( bredde / 2 , højde / 2 )

# Nu, ved hjælp af cv2, vil vi rotere billedet 55 grader til

# bestem rotationsmatricen ved hjælp af getRotationMatrix2D()

rotationsMatrix = cv2. getRotationMatrix2D ( ( centerX , centerY ) , 55 , 1.0 )

roteret billede = cv2. warpAffine ( billede , rotationsMatrix , ( bredde , højde ) )

cv2. imshow ( 'Roterede billedet 55 grader' , roteret billede )

cv2. ventenøgle ( 0 )

# Billedet vil nu blive roteret med -85 grader.

rotationsMatrix = cv2. getRotationMatrix2D ( ( centerX , centerY ) , - 85 , 1.0 )

roteret billede = cv2. warpAffine ( billede , rotationsMatrix , ( bredde , højde ) )

cv2. imshow ( 'Roterede billedet med -85 grader' , roteret billede )

cv2. ventenøgle ( 0 )

Linje 1 til 5: Vi importerer alle de nødvendige pakker til dette program, såsom OpenCV, argparser og NumPy. Bemærk venligst, at der er et andet bibliotek, som er imutils. Dette er ikke en pakke med OpenCV. Dette er blot et bibliotek, der nemt vil blive brugt til at vise den samme billedbehandling.

Bibliotekets imutils vil ikke blive inkluderet automatisk, når vi installerer OpenCV. OpenCV installerer imutils. Vi skal bruge følgende metode:

pip install imutils

Linje 8 til 14: Vi oprettede vores agrparser og indlæste vores billede. I denne argparser bruger vi kun ét billedargument, som vil fortælle os stien til billedet, som vi vil bruge i dette program til at demonstrere rotationen.

Når vi roterer et billede, skal vi definere rotationens omdrejningspunkt. Det meste af tiden vil du rotere et billede om dets centrum, men OpenCV giver dig mulighed for at vælge et hvilket som helst tilfældigt punkt i stedet. Lad os simpelthen rotere billedet rundt om dets centrum.

Linje 17 til 18 tag billedets henholdsvis bredde og højde, og divider derefter hver dimension med to for at etablere billedets centrum.

Vi konstruerer en matrix til at rotere et billede på samme måde, som vi definerede en matrix til at oversætte et billede. Vi ringer bare til cv2.getRotationMatrix2D funktion på linje 22 i stedet for manuelt at oprette matrixen ved hjælp af NumPy (hvilket kan være lidt besværligt).

Det cv2.getRotationMatrix2D funktion kræver tre parametre. Det første input er den ønskede rotationsvinkel (i dette tilfælde midten af ​​billedet). Theta bruges derefter til at angive, hvor mange (mod uret) grader vi vil rotere billedet. Her roterer vi billedet 45 grader. Den sidste mulighed er relateret til billedets størrelse.

Uanset det faktum, at vi endnu ikke har diskuteret skalering af et billede, kan du angive et flydende kommatal her med 1,0, der angiver, at billedet skal bruges i dets oprindelige proportioner. Men hvis du indtastede en værdi på 2,0, ville billedet fordobles i størrelse. Et tal på 0,5 reducerer billedets størrelse sådan.

Linje 22 til 23: Efter at have modtaget vores rotationsmatrix M fra cv2.getRotationMatrix2D funktion, roterer vi vores billede ved hjælp af cv2.warpAffine teknik på linje 23. Funktionens første input er det billede, som vi ønsker at rotere. Herefter defineres bredden og højden af ​​vores outputbillede sammen med vores rotationsmatrix M. På linje 23 roteres billedet så 55 grader.

Du kan bemærke, at vores billede er blevet roteret.

Linje 28 til 30 udgør den anden rotation. Linje 22-23 i koden er identiske, bortset fra at vi denne gang roterer med -85 grader i modsætning til 55.

Vi har simpelthen roteret et billede omkring dets centrum indtil dette punkt. Hvad hvis vi ønskede at rotere billedet omkring et tilfældigt punkt?

Lad os starte med at åbne og generere en ny fil kaldet rotate.py:

# importerer de nødvendige pakker

importere nusset som for eksempel.

importere argparse

importere imutil

importere cv2

# oprettelse af argumentparser-objektet og parsing-argumentet

ap_obj = argparse. ArgumentParser ( )

ap_obj. add_argument ( '-k' , '--billede' , påkrævet = Sand , Hjælp = 'billedsti' )

argument = hvis ( ap_obj. parse_args ( ) )

# indlæs billedet og vis det på skærmen

billede = cv2. imread ( argument [ 'billede' ] )

cv2. imshow ( 'Original_image' , billede )

# Beregn billedets centrum ved hjælp af billedets dimensioner.

( højde , bredde ) = billede. form [ : 2 ]

( centerX , centerY ) = ( bredde / 2 , højde / 2 )

# Nu, ved hjælp af cv2, vil vi rotere billedet 55 grader til

# bestem rotationsmatricen ved hjælp af getRotationMatrix2D()

rotationsMatrix = cv2. getRotationMatrix2D ( ( centerX , centerY ) , 55 , 1.0 )

roteret billede = cv2. warpAffine ( billede , rotationsMatrix , ( bredde , højde ) )

cv2. imshow ( 'Roterede billedet 55 grader' , roteret billede )

cv2. ventenøgle ( 0 )

# Billedet vil nu blive roteret med -85 grader.

rotationsMatrix = cv2. getRotationMatrix2D ( ( centerX , centerY ) , - 85 , 1.0 )

roteret billede = cv2. warpAffine ( billede , rotationsMatrix , ( bredde , højde ) )

cv2. imshow ( 'Roterede billedet med -85 grader' , roteret billede )

cv2. ventenøgle ( 0 )

# billedrotation fra et vilkårligt punkt, ikke fra midten

rotationsMatrix = cv2. getRotationMatrix2D ( ( centerX - 40 , centerY - 40 ) , 55 , 1.0 )

roteret billede = cv2. warpAffine ( billede , rotationsMatrix , ( bredde , højde ) )

cv2. imshow ( 'Billedretation fra vilkårlige punkter' , roteret billede )

cv2. ventenøgle ( 0 )

Linje 34 til 35: Nu burde denne kode virke ret almindelig til at rotere et objekt. For at rotere billedet omkring et punkt 40 pixels til venstre og 40 pixels over dets centrum, instruerer vi cv2.getRotationMatrix2D funktion for at være opmærksom på dens første parameter.

Billedet, der produceres, når vi anvender denne rotation, er vist nedenfor:

Vi kan tydeligt se, at centrum af rotationen nu er (x, y)-koordinaten, som er 40 pixels til venstre og 40 pixels over det beregnede centrum af billedet.

3. Billedregning

Faktisk er billedaritmetik kun matrixtilsætning med et par yderligere begrænsninger på datatyper, som vi vil dække senere.

Lad os tage et øjeblik på at gennemgå nogle ret grundlæggende principper for lineær algebra.

Overvej at kombinere de næste to matricer:

Hvilket resultat ville matrixadditionen give? Det enkle svar er summen af ​​matrixindtastningerne, element for element:

Simpelt nok, ikke?

Vi forstår alle de grundlæggende funktioner i addition og subtraktion på dette tidspunkt. Vi skal dog være opmærksomme på de begrænsninger, som vores farverum og datatype pålægger, mens vi arbejder med billeder.

Pixels i RGB-billeder falder for eksempel mellem [0, 255]. Hvad sker der, hvis vi forsøger at tilføje 10 til en pixel med en intensitet på 250, mens vi ser på den?

Vi ville nå frem til en værdi på 260, hvis vi anvendte standard aritmetiske principper. 260 er ikke en gyldig værdi, da RGB-billeder er repræsenteret som 8-bit heltal uden fortegn.

Så hvad burde der ske? Skal vi køre et tjek for at sikre, at ingen pixel er uden for området [0, 255], idet vi beskærer hver pixel til at have en værdi mellem 0 og 255?

Eller 'vikler vi os rundt' og udfører en moduloperation? I overensstemmelse med modulreglerne ville tilføjelse af 10 til 255 blot resultere i en værdi på 9.

Hvordan skal tilføjelser og subtraktioner til billeder uden for området [0, 255] håndteres?

Sandheden er, at der ikke er nogen rigtig eller forkert teknik; det hele afhænger af, hvordan du arbejder med dine pixels, og hvad du håber at opnå.

Men husk at der er forskel på addition i OpenCV og addition i NumPy. Modulus aritmetik og 'wrap around' vil blive udført af NumPy. I modsætning hertil vil OpenCV udføre klipning og sørge for, at pixelværdier aldrig forlader området [0, 255].

Lad os starte med at oprette en ny fil kaldet aritmetic.py og åbner den:

# python arithmetic.py --image squirrel.jpg

# importerer de nødvendige pakker

importere nusset som for eksempel.

importere argparse

importere imutil

importere cv2

# oprettelse af argumentparser-objektet og parsing-argumentet

apObj = argparse. ArgumentParser ( )

apObj. add_argument ( '-k' , '--billede' , påkrævet = Sand , Hjælp = 'billedsti' )

argumenter = hvis ( apObj. parse_args ( ) )

billede = cv2. imread ( argumenter [ 'billede' ] )

cv2. imshow ( 'Original_image' , billede )

'''

Værdierne af vores pixels vil være i området [0, 255]

da billeder er NumPy-arrays, som er gemt som usignerede 8-bit heltal.

Når du bruger funktioner som cv2.add og cv2.subtract, vil værdier blive klippet

til dette interval, selvom de lægges til eller trækkes fra uden for

[0, 255] område. Her er en illustration:

'''


Print ( 'maksimalt 255: {}' . format ( str ( cv2. tilføje ( for eksempel. uint8 ( [ 201 ] ) ,

for eksempel. uint8 ( [ 100 ] ) ) ) ) )

Print ( 'minimum af 0: {}' . format ( str ( cv2. trække fra ( for eksempel. uint8 ( [ 60 ] ) ,

for eksempel. uint8 ( [ 100 ] ) ) ) ) )

'''

Når du udfører aritmetiske operationer med disse arrays ved hjælp af NumPy,

værdien vil ombrydes i stedet for at blive klippet til

[0, 255]område. Når du bruger billeder, er det vigtigt at beholde dette

i tankerne.

'''


Print ( 'vikle om: {}' . format ( str ( for eksempel. uint8 ( [ 201 ] ) + f.eks. uint8 ( [ 100 ] ) ) ) )

Print ( 'vikle om: {}' . format ( str ( for eksempel. uint8 ( [ 60 ] ) - for eksempel. uint8 ( [ 100 ] ) ) ) )

'''

Lad os gange lysstyrken af ​​hver pixel i vores billede med 101.

For at gøre dette genererer vi et NumPy-array af samme størrelse som vores matrix,

fyldt med enere, og gange det med 101 for at frembringe et array fyldt

med 101s. Til sidst slår vi de to billeder sammen.

Du vil bemærke, at billedet nu er 'lysere'.

'''


Matrix = for eksempel. dem ( billede. form , dtype = 'uint8' ) * 101

image_added = cv2. tilføje ( billede , Matrix )

cv2. imshow ( 'Tilføjet billedresultat' , image_added )

#På en lignende måde kan vi gøre vores billede mørkere ved at tage

# 60 væk fra alle pixels.

Matrix = for eksempel. dem ( billede. form , dtype = 'uint8' ) * 60

billede_fratrukket = cv2. trække fra ( billede , Matrix )

cv2. imshow ( 'Fratrukket billedresultat' , billede_fratrukket )

cv2. ventenøgle ( 0 )

Linje 1 til 16 vil blive brugt til at udføre vores normale proces, som indebærer at importere vores pakker, konfigurere vores argumentparser og indlæse vores billede.

Husk, hvordan jeg tidligere diskuterede forskellen mellem OpenCV og NumPy addition? Nu hvor vi har dækket det grundigt, lad os se på en specifik sag for at sikre, at vi forstår den.

To 8-bit usignerede heltal NumPy-arrays er defineret på linje 26 . En værdi på 201 er det eneste element i det første array. Selvom kun ét medlem er i det andet array, har det en værdi på 100. Værdierne tilføjes derefter ved hjælp af OpenCVs cv2.add funktion.

Hvad forventer du at resultatet bliver?

I overensstemmelse med konventionelle aritmetiske principper bør svaret være 301. Men husk, at vi har at gøre med 8-bit heltal uden fortegn, som kun kan være i området [0, 255]. Fordi vi bruger cv2.add metoden, håndterer OpenCV klipning og sikrer, at tilføjelsen kun returnerer et maksimalt resultat på 255.

Den første linje i listen nedenfor viser resultatet af at køre denne kode:

aritmetik. py

maksimum af 255 : [ [ 255 ] ]

Summen gav faktisk et tal på 255.

Efter det, linje 26 bruger cv2.subtract til at udføre en subtraktion. Endnu en gang definerer vi to 8-bit usignerede heltal NumPy-arrays med et enkelt element i hver. Værdien af ​​det første array er 60, mens værdien af ​​det andet array er 100.

Vores aritmetik dikterer, at subtraktionen skal resultere i en værdi på -40, men OpenCV håndterer klipningen for os endnu en gang. Vi opdager, at værdien er blevet trimmet til 0. Vores resultat nedenfor viser dette:

aritmetik. py

minimum af 0 : [ [ 0 ] ]

Træk 100 fra 60 ved hjælp af cv2, træk værdien 0.

Men hvad sker der, hvis vi bruger NumPy i stedet for OpenCV til at udføre beregningerne?

Linje 38 og 39 løse dette problem.

Først defineres to 8-bit usignerede heltals NumPy-arrays med et enkelt element hver. Værdien af ​​det første array er 201, hvorimod værdien af ​​det andet array er 100. Vores addition ville blive trimmet, og en værdi på 255 ville blive returneret, hvis vi brugte cv2.add-funktionen.

NumPy, på den anden side, 'ombrydes' og laver modulo-aritmetik i stedet for klipning. NumPy ombrydes til nul, når en værdi på 255 er nået, og genoptager derefter optællingen, indtil 100 trin er nået. Dette bekræftes af den første linje af output, som er vist nedenfor:

aritmetik. py
vikle om: [ Fire, fem ]

Derefter defineres yderligere to NumPy-arrays, den ene med en værdi på 50 og den anden med 100. Denne subtraktion vil blive trimmet ved cv2.subtract-metoden for at returnere et resultat på 0. Men vi er klar over, at i stedet for at klippe, udfører NumPy modulo aritmetik. I stedet går modulo-procedurerne rundt og begynder at tælle bagud fra 255, når 0 er nået under subtraktionen. Vi kan se dette fra følgende output:

aritmetik. py

vikle om: [ 207 ]

Endnu en gang demonstrerer vores terminaloutput forskellen mellem at klippe og pakke rundt:

Det er afgørende at have dit ønskede resultat i tankerne, når du udfører heltalsregning. Ønsker du, at nogen værdier uden for området [0, 255] skal klippes? Brug derefter OpenCVs indbyggede billedregningsteknikker.

Ønsker du, at værdier skal ombrydes, hvis de er uden for området for [0, 255] og aritmetiske moduloperationer? NumPy-arrayerne tilføjes derefter og trækkes fra som normalt.

Linje 48 definerer et endimensionelt NumPy-array med de samme dimensioner som vores billede. Endnu en gang sikrer vi, at vores datatype er 8-bit heltal uden fortegn. Vi multiplicerer blot vores matrix med et-cifrede værdier med 101 for at fylde den med værdier på 101 i stedet for 1. Til sidst bruger vi cv2.add-funktionen til at tilføje vores matrix på 100s til det originale billede. Dette øger hver pixels intensitet med 101, samtidig med at det sikrer, at alle værdier, der forsøger at overstige 255, klippes til området [0, 255].

Se, hvordan billedet er mærkbart lysere og fremstår mere 'udvasket' end originalen. Dette skyldes, at vi driver pixels mod lysere farver ved at hæve deres pixelintensitet med 101.

For at trække 60 fra hver pixelintensitet i billedet etablerer vi først et andet NumPy-array på linje 54, der er fyldt med 60'erne.

Resultaterne af denne subtraktion er afbildet i følgende billede:

Genstandene omkring os fremstår betydeligt mørkere, end de gjorde tidligere. Dette skyldes, at ved at trække 60 fra hver pixel flytter vi pixels i RGB-farverummet ind i de mørkere områder.

4. Billedvendt

I lighed med rotation er det en anden mulighed, som OpenCV tilbyder at vende et billede hen over dets x- eller y-akse. Selvom vippeoperationer ikke bruges så ofte, er det utroligt gavnligt at kende dem af forskellige årsager, du måske ikke umiddelbart ser.

Vi er ved at udvikle en maskinlæringsklassifikator til en lille nystartet virksomhed, der søger at identificere ansigter i billeder. For at vores system kan 'lære' hvad et ansigt er, ville vi have brug for en slags datasæt med prøveansigter. Desværre har virksomheden kun givet os et lille datasæt på 40 ansigter, og vi er ikke i stand til at samle flere oplysninger.

Hvad gør vi så?

Da et ansigt forbliver et ansigt, uanset om det er spejlet eller ej, er vi i stand til at vende hvert billede af et ansigt vandret og bruge de spejlede versioner som ekstra træningsdata.

Dette eksempel kan virke dumt og kunstigt, men det er det ikke. Flipping er en bevidst strategi, der bruges af stærke deep-learning-algoritmer til at producere mere data under træningsfasen.

Det fremgår tydeligt af det foregående, at de billedbehandlingsmetoder, du lærer i dette modul, fungerer som grundlaget for større computervisionssystemer.

Mål:

Bruger cv2.flip funktion, lærer du at spejlvende et billede både vandret og lodret i denne session.

Flipping er den næste billedmanipulation, vi vil studere. Et billedes x- og y-akser kan vendes eller endda begge. Før vi dykker ned i kodningen, er det bedst først at se på resultaterne af en billedvending. Se et billede, der er blevet vendt vandret på følgende billede:


Bemærk, hvordan vores originale billede er til venstre, og hvordan billedet er blevet spejlet vandret til højre.

Lad os begynde med at oprette en ny fil kaldet flipping.py .

Du har set et eksempel på en billedvending, så lad os undersøge koden:

# python flipping.py --image quirrel.jpg

# importerer de nødvendige pakker

importere argparse

importere cv2

# oprettelse af objektet for argumentparser og parse argumentet

apObj = argparse. ArgumentParser ( )

apObj. add_argument ( '-jeg' , '--billede' , påkrævet = Sand , Hjælp = 'billedsti' )

argument = hvis ( apObj. parse_args ( ) )

billede = cv2. imread ( argument [ 'billede' ] )

cv2. imshow ( 'Original' , billede )

# vend billedet vandret

billedvendt = cv2. vende ( billede , 1 )

cv2. imshow ( 'Vendt billede vandret' , billedvendt )

# vend billedet lodret

billedvendt = cv2. vende ( billede , 0 )

cv2. imshow ( 'Vendt billede lodret' , billedvendt )

# billede vend langs begge akser

billedvendt = cv2. vende ( billede , - 1 )

cv2. imshow ( 'Vendt vandret og lodret' , billedvendt )

cv2. ventenøgle ( 0 )

De trin, vi tager for at importere vores pakker, analysere vores input og indlæse vores billede fra disken, håndteres i l ines 1 til 12 .

Ved at aktivere cv2.flip-funktionen Linje 15 , er det nemt at vende et billede vandret. Billedet, vi søger at vende, og en specifik kode eller flag, der specificerer, hvordan billedet skal vendes, er de to argumenter, der er nødvendige for cv2.flip-metoden.

En flip-kodeværdi på 1 betyder, at vi vil rotere billedet rundt om y-aksen for at vende det vandret ( Linje 15 ). Hvis vi angiver en flip-kode på 0, ønsker vi at rotere billedet om x-aksen ( Linje 19 ). En negativ flip-kode ( Linje 23 ) roterer billedet på begge akser.

Et af de nemmeste eksempler i dette emne er at vende et billede, hvilket er grundlæggende.

Dernæst vil vi diskutere beskæring af billeder og bruge NumPy array skiver til at udtrække specifikke billeddele.

5. Billedbeskæring

Beskæring, som navnet antyder, er processen med at vælge og fjerne interesseregionen (eller blot ROI), som er det område af billedet, der interesserer os.

Ansigtet skal beskæres fra et billede til en ansigtsgenkendelsesapplikation. Derudover, hvis vi lavede et Python-script til at finde hunde i billeder, vil vi måske beskære hunden ud af billedet, når vi finder den.

Mål: Vores hovedmål er at blive fortrolige med og have det let at bruge NumPy array slicing til at beskære områder fra et billede.

Beskæring : Når vi beskærer et billede, er vores mål at fjerne de ydre elementer, der ikke interesserer os. Processen med at vælge vores ROI omtales ofte som at vælge vores område af interesse.

Opret en ny fil kaldet crop.py , åbn den, og tilføj følgende kode:

# python crop.py

# importerer de nødvendige pakker

importere cv2

# billede indlæses og vises på skærmen

billede = cv2. imread ( 'egern.jpg' )

Print ( billede. form )

cv2. imshow ( 'Original' , billede )

# NumPy array skiver bruges til hurtigt at trimme et billede

# vi vil beskære egern-ansigtet fra billedet

egern = billede [ 35 : 90 , 35 : 100 ]

cv2. imshow ( 'egern ansigt' , egern )

cv2. ventenøgle ( 0 )

# Og nu, her skal vi beskære hele kroppen

# af egernet

egernlegeme = billede [ 35 : 148 , 23 : 143 ]

cv2. imshow ( 'Egern krop' , egernlegeme )

cv2. ventenøgle ( 0 )

Vi viser beskæring i Python og OpenCV ved hjælp af et billede, som vi indlæser fra disken på Linje 5 og 6 .

Originalt billede, som vi vil beskære

Ved kun at bruge grundlæggende beskæringsteknikker sigter vi efter at adskille egernens ansigt og egernkroppen fra det omkringliggende område.

Vi vil bruge vores forudgående viden om billedet og manuelt levere NumPy-array-skiverne af, hvor kroppen og ansigtet findes. Under normale forhold ville vi generelt anvende maskinlæring og computersynsalgoritmer til at genkende ansigtet og kroppen på billedet. Men lad os holde tingene ligetil indtil videre og undgå at bruge nogen detekteringsmodeller.

Vi kan identificere ansigtet på billedet med kun én linje kode. Linje 13 , For at udtrække en rektangeldel af billedet, startende ved (35, 35), leverer vi NumPy array-slices (90, 100). Det kan virke forvirrende, at vi fodrer afgrøden med indekserne i højde-første og bredde-sekund rækkefølge, som vi gør, men husk på, at OpenCV gemmer billeder som NumPy-arrays. Som et resultat skal vi levere værdierne for y-aksen før x-aksen.

NumPy kræver følgende fire indekser for at udføre vores beskæring:

Start y: Y-koordinaten i begyndelsen. I dette tilfælde begynder vi ved y=35.

Slut y: Y-koordinaten i slutningen. Vores afgrøde stopper, når y = 90.

Start x: Skivens begyndelse x-koordinat. Beskæringen påbegyndes ved x=35.

Slut x: Skivens ende x-aksekoordinat. Ved x=100 er vores skive færdig.

På samme måde beskærer vi regionerne (23, 35) og (143, 148) fra det originale billede for at udtrække hele kroppen fra billedet på Linje 19 .

Du kan se, at billedet er blevet beskåret for kun at vise kroppen og ansigtet.

6. Ændring af billedstørrelse

Processen med at øge eller formindske et billedes bredde og højde er kendt som skalering eller blot ændre størrelse. Størrelsesforholdet, som er forholdet mellem et billedes bredde og dets højde, bør tages i betragtning, når du ændrer størrelsen på et billede. Forsømmelse af billedformatet kan resultere i billeder, der er blevet skaleret, som ser komprimerede og forvrængede ud:

Vores første billede er til venstre. Til højre kan du se to billeder, der er blevet skaleret uden at bevare billedformatet, hvilket forvrænger forholdet mellem billedets bredde og dets højde. Når du ændrer størrelsen på dine billeder, bør du generelt overveje billedformatet.

Interpolationsteknikken, der bruges af vores algoritme til ændring af størrelse, skal også tage hensyn til formålet med interpolationsfunktionen for at bruge disse pixelkvarterer til enten at øge eller mindske billedets størrelse.

Generelt er det langt mere effektivt at formindske størrelsen af ​​billedet. Dette skyldes, at fjernelse af pixels fra et billede er alt, hvad interpolationsfunktionen skal gøre. På den anden side ville interpolationsmetoden skulle 'udfylde hullerne' mellem pixels, der ikke tidligere eksisterede, hvis billedstørrelsen skulle øges.

Vi har vores originale billede til venstre. Billedet er blevet reduceret til halvdelen af ​​sin oprindelige størrelse i midten, men derudover har der ikke været noget tab af billedets 'kvalitet'. Ikke desto mindre er billedets størrelse blevet betydeligt forbedret til højre. Det ser nu ud som 'sprængt' og 'pixeleret.'

Som jeg tidligere har sagt, vil du typisk reducere et billedes størrelse i stedet for at øge det. Ved at reducere billedstørrelsen analyserer vi færre pixels og skal håndtere mindre 'støj', hvilket gør billedbehandlingsalgoritmer hurtigere og mere præcise.

Translation og rotation er de to billedtransformationer, der er behandlet indtil videre. Vi vil nu undersøge, hvordan man ændrer størrelsen på et billede.

Ikke overraskende vil vi ændre størrelsen på vores billeder ved hjælp af cv2.resize-metoden. Som jeg antydede tidligere, skal vi overveje billedets billedformat, når vi bruger denne metode. Men før vi går for dybt ind i detaljerne, tillad mig at give dig en illustration:

# python resize.py --image squirrel.jpg

# importerer de nødvendige pakker

importere argparse

importere cv2

# oprettelse af objektet for argumentparser og parse argumentet

apObj = argparse. ArgumentParser ( )

apObj. add_argument ( '-k' , '--billede' , påkrævet = Sand , Hjælp = 'billedsti' )

argumenter = hvis ( apObj. parse_args ( ) )

# indlæs billedet og vis det på skærmen

billede = cv2. imread ( argumenter [ 'billede' ] )

cv2. imshow ( 'Original' , billede )

# For at forhindre, at billedet fremstår skævt, billedformat

# skal overvejes eller deformeres; derfor finder vi ud af hvad

# det nye billedes forhold til det aktuelle billede.

# Lad os gøre bredden af ​​vores nye billede til 160 pixels.

aspekt = 160,0 / billede. form [ 1 ]

dimension = ( 160 , int ( billede. form [ 0 ] * aspekt ) )

# denne linje vil vise faktiske størrelsesændringsoperationer

ændret størrelse på billede = cv2. ændre størrelse ( billede , dimension , interpolation = cv2. INTER_AREA )

cv2. imshow ( 'Ændret billedbredde' , ændret størrelse på billede )

# Hvad hvis vi ville ændre billedets højde? - bruger

# samme princip, vi kan beregne billedformatet baseret

# på højde frem for bredde. Lad os lave den skalerede

# billedes højde 70 pixels.

aspekt = 70,0 / billede. form [ 0 ]

dimension = ( int ( billede. form [ 1 ] * aspekt ) , 70 )

# udfør størrelsesændringen

ændret størrelse på billede = cv2. ændre størrelse ( billede , dimension , interpolation = cv2. INTER_AREA )

cv2. imshow ( 'Ændret størrelse på billedhøjde' , ændret størrelse på billede )

cv2. ventenøgle ( 0 )

Linje 1-14 , Efter at have importeret vores pakker og konfigureret vores argumentparser, vil vi indlæse og vise vores billede.

Linje 20 og 21: Den relevante kodning begynder i disse linier . Billedets størrelsesforhold skal tages i betragtning, mens størrelsen ændres. Forholdet mellem billedets bredde og højde er kendt som billedformatet.

Højde bredde er billedformatet.

Hvis vi ikke tager højde-bredde-forholdet i betragtning, vil resultaterne af vores størrelsesændring blive forvrænget.

Linje 20 , er den ændrede størrelsesforholdsberegning udført. Vi angiver bredden af ​​vores nye billede som 160 pixels i denne kodelinje. Vi definerer blot vores forhold (aspectratio) som den nye bredde (160 pixels) divideret med den gamle bredde, som vi får adgang til ved hjælp af billede, for at beregne forholdet mellem den nye højde og den gamle højde. form[1].

De nye dimensioner af billedet på Linje 21 kan beregnes nu, hvor vi kender vores forhold. Endnu en gang får det nye billede en bredde på 160 pixels. Efter at have ganget den gamle højde med vores forhold og konverteret resultatet til et heltal, beregnes højden. Vi kan bevare billedets originale billedformat ved at udføre denne handling.

Linje 24 er der, hvor billedet virkelig ændres. Det billede, vi vil ændre størrelsen på, er det første argument, og det andet er de dimensioner, vi har beregnet for det nye billede. Vores interpolationsmetode, som er algoritmen til at ændre størrelsen på det faktiske billede, er den sidste parameter.

Endelig på Linje 25 , viser vi vores skalerede billede.

Vi omdefinerer vores forhold (aspectratio) på Linje 31 . Højden på vores nye billede bliver 70 pixels. Vi dividerer 70 med den oprindelige højde for at få det nye højde-til-oprindelige højdeforhold.

Dernæst fastlægger vi det nye billedes dimensioner. Det nye billede får en højde på 70 pixels, hvilket allerede er kendt. Vi kan igen beholde billedets oprindelige billedformat ved at gange den gamle bredde med forholdet for at producere den nye bredde.

Billedet bliver så reelt tilpasset Linje 35 , og den vises på Linje 36.

Her kan vi se, at vi har reduceret bredden og højden af ​​vores originale billede, mens vi har bevaret billedformatet. Vores billede ville virke forvrænget, hvis billedformatet ikke blev opretholdt.

Konklusion

I denne blog har vi studeret de grundlæggende forskellige billedbehandlingskoncepter. Vi har set billedoversættelse ved hjælp af OpenCV-pakken. Vi har set metoderne til at flytte billedet op, ned, til højre og venstre. Disse metoder er meget nyttige, når vi opretter et datasæt af lignende billeder til at give som et træningsdatasæt, så maskinen vil se forskellige billeder, selvom de er ens. Denne artikel lærte dig også, hvordan du roterer et billede omkring et hvilket som helst punkt i det kartesiske rum ved hjælp af en rotationsmatrix. Så opdagede du, hvordan OpenCV roterer billeder ved hjælp af denne matrix og så et par illustrationer af roterende billeder.

De to grundlæggende (men signifikante) billedaritmetiske operationer addition og subtraktion blev undersøgt i dette afsnit. Som du kan se, er addering og subtraktion af fundamentale matricer alle billedaritmetiske operationer.

Derudover brugte vi OpenCV og NumPy til at undersøge ejendommelighederne ved billedaritmetik. Disse begrænsninger skal huskes, ellers risikerer du at få uventede resultater, når du udfører aritmetiske operationer på dine billeder.

Det er vigtigt at huske, at selvom NumPy udfører en moduloperation og 'omslutter', skærer OpenCV addition og subtraktion værdier ud over området [0, 255] for at passe inden for området. Når du udvikler dine egne computervisionsapplikationer, vil huske dette hjælpe dig med at undgå at jage vanskelige fejl.

Billedvending er uden tvivl en af ​​de enklere ideer, vi vil udforske i dette kursus. Flipping bruges ofte i maskinlæring for at generere flere træningsdataeksempler, hvilket resulterer i mere potente og pålidelige billedklassifikatorer.

Vi lærte også, hvordan man bruger OpenCV til at ændre størrelsen på et billede. Det er afgørende at overveje både den interpolationsmetode, du bruger, og billedformatet af dit originale billede, når du ændrer størrelsen på et, så resultatet ikke ser forvrænget ud.

Endelig er det afgørende at huske, at hvis billedkvaliteten er et problem, er det altid bedst at skifte fra et større til et mindre billede. I de fleste tilfælde skaber forstørrelse af et billede artefakter og forringer dets kvalitet.