Heb je ooit een beeld met veel ruis gezien? Ik bedoel een beeld dat niet zo duidelijk was tijdens het bekijken ervan? Ik denk dat we dergelijke afbeeldingen heel vaak tegenkomen, vooral wanneer tegenwoordig veel foto's worden genomen door onze mobiele telefooncamera's of digitale camera's met een lage resolutie.
Als je alleen die ruisende afbeelding had die iets voor je betekent, maar het probleem is dat het niet goed kan worden bekeken, zou er een oplossing zijn om van dergelijke ruis te herstellen?
Dit is waar beeldfiltering in het spel komt, en dit is wat ik in deze tutorial zal beschrijven. Laten we beginnen!
Beeldfiltering is een populair hulpmiddel dat wordt gebruikt bij beeldverwerking. Aan het einde van de dag gebruiken we afbeeldingsfiltering om ruis en ongewenste elementen uit een afbeelding te verwijderen, waardoor een betere en verbeterde versie van die afbeelding wordt gemaakt. Er zijn twee soorten filters: lineair en niet-lineaire. Voorbeelden van lineaire filters zijn gemiddelde en Laplace-filters. Niet-lineaire filters vormen filters zoals mediaan, minimum, maximum en Sobel-filters.
Elk van deze filters heeft een specifiek doel en is ontworpen om ruis te verwijderen of bepaalde aspecten in de afbeelding te verbeteren. Maar hoe wordt filteren uitgevoerd? Dit is wat we in de volgende paragraaf zullen zien.
Om een beeldfilterproces uit te voeren, hebben we een filter, ook wel a masker. Dit filter is meestal een tweedimensionaal vierkant venster, dat is een venster met gelijke afmetingen (breedte en hoogte).
Het filter bevat nummers. Die nummers worden gebeld coëfficiënten, en zij zijn wat feitelijk het effect van het filter bepaalt en hoe het uitvoerbeeld eruit zal zien. De onderstaande figuur toont een voorbeeld van een 3x3
filter, met negen waarden (coëfficiënten).
Voor het toepassen van het filter, de 3x3
venster wordt over de afbeelding geschoven. Dit proces waarbij een filtervenster over een afbeelding wordt geschoven, wordt aangeroepen convolutie in het ruimtelijke domein. Het venster wordt op elke pixel geplaatst (d.w.z. zie het als een cel in een matrix) in de afbeelding, waar het midden van de filter die pixel moet overlappen.
Zodra deze overlapping optreedt, worden de pixels in de subafbeelding waarop het filter zich bevindt, vermenigvuldigd met de bijbehorende coëfficiënten van het filter. In dit geval hebben we een nieuwe matrix met nieuwe waarden die vergelijkbaar zijn met de grootte van het filter (d.w.z.. 3x3
). Ten slotte wordt de centrale pixelwaarde vervangen door een nieuwe waarde met behulp van een specifieke wiskundige vergelijking, afhankelijk van het type filter dat wordt gebruikt (zoals het mediaanfilter).
Ik weet dat de bovenstaande paragraaf een beetje omslachtig is. Laten we een voorbeeld nemen om te laten zien hoe een afbeeldingsfilter in actie wordt toegepast. Stel dat we de volgende subafbeelding hebben waar ons filter overlapt (ik
en j
verwijs naar de pixellocatie in de subafbeelding, en ik
verwijst naar de afbeelding):
De convolutie van ons filter in de eerste afbeelding met de bovenstaande subafbeelding ziet er zoals hieronder uit, waarbij I_new (i, j)
vertegenwoordigt het resultaat op locatie (I, j)
.
I_new (i, j) = v1 x I (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)
Het proces wordt herhaald voor elke pixel in de afbeelding, inclusief de pixels aan de rand van de afbeelding. Maar zoals u wel kunt raden, zal een deel van het filter zich buiten de afbeelding bevinden wanneer het filter op de grenspixels wordt geplaatst. In dit geval doen we het vulling.
Dit proces betekent eenvoudigweg dat we nieuwe pixelwaarden invoegen in de subafbeelding onder het deel van het filter dat buiten de afbeelding komt vóór het convolutieproces, omdat dat deel blijkbaar geen pixelwaarden bevat. Het staat buiten het beeld! Die opgevulde pixels kunnen nullen of een constante waarde zijn. Er zijn andere methoden voor het instellen van de opvullingswaarden, maar deze vallen buiten het bereik van deze zelfstudie.
Ik denk dat dit voor nu voldoende theorie is, dus laten we doorgaan en onze handen vies maken met codering! In deze tutorial zal ik het mediaan filter (dat wil zeggen niet-lineair) en het gemiddelde filter (dat wil zeggen lineair) uitleggen en hoe we het in Python kunnen implementeren..
In het mediaanfilter kiezen we een schuifvenster dat over alle beeldpixels beweegt. Wat we hier doen, is dat we de pixelwaarden verzamelen die onder het filter vallen en de mediaan van die waarden bepalen. Het resultaat wordt toegewezen aan de middelste pixel.
Zeg onze 3x3
filter had de volgende waarden na plaatsing op een subafbeelding:
Laten we eens kijken hoe we de mediaan berekenen. De mediaan, in wezen, is de midden- nummer van een gesorteerde lijst met nummers. Om dus de mediaan voor het bovenstaande filter te vinden, sorteren we eenvoudig de getallen van het laagste naar het hoogste, en het midden van die getallen zal onze mediaanwaarde zijn. De waarden sorteren in onze 3x3
venster geeft ons het volgende:
17 29 43 57 59 63 65 84 98
Om het middelste getal (mediaan) te vinden, tellen we eenvoudig het aantal waarden dat we hebben, voegen we 1 toe aan dat getal en delen we met 2. Dit geeft ons de locatie van de middelste waarde in het venster, wat onze mediaanwaarde is. De mediaanwaarde is dus op locatie 9 + 1/2 = 5
, welke is 59
. Deze waarde is de nieuwe waarde van de pixel onder het midden van ons 3x3
venster.
Dit type filter wordt gebruikt voor het verwijderen van ruis en werkt het beste met afbeeldingen die lijden zout en peper lawaai. De onderstaande afbeelding toont een voorbeeld van een afbeelding die lijdt aan dergelijke ruis:
Laten we nu een Python-script schrijven dat het mediaanfilter op de bovenstaande afbeelding toepast. Voor dit voorbeeld zullen we de OpenCV-bibliotheek gebruiken. Controleer alstublieft Installeer OpenCV-Python in Windows en installeer OpenCV 3.0 en Python 2.7+ op Ubuntu om OpenCV te installeren.
Om het mediaanfilter toe te passen, gebruiken we eenvoudigweg OpenCV's cv2.medianBlur ()
functie. Ons script kan er dus als volgt uitzien:
import cv2 import argparse # maak de argument-parser en ontleed de argumenten ap = argparse.ArgumentParser () ap.add_argument ('- i', '--image', required = True, help = 'Pad naar de invoerafbeelding') args = vars (ap.parse_args ()) # lees de afbeeldingsafbeelding = cv2.imread (args ['image']) # pas het 3x3 mediaanfilter toe op de afbeelding processed_image = cv2.medianBlur (afbeelding, 3) # toon afbeelding cv2. imshow ('Median Filter Processing', processed_image) # afbeelding opslaan op schijf cv2.imwrite ('processed_image.png', processed_image) # pauzeer de uitvoering van het script totdat een toets op het toetsenbord wordt ingedrukt cv2.waitKey (0)
Merk op dat ik heb gebruikt argparse
, aangezien het een goede gewoonte is om hier flexibel te zijn en de opdrachtregel te gebruiken om de afbeelding waarop we de mediaanfilter willen toepassen, door te geven als argument voor ons programma.
Nadat we onze afbeelding hebben doorgegeven als een opdrachtregelargument, lezen we die afbeelding met de cv2.imread ()
functie. Vervolgens passen we het mediaanfilter toe met behulp van de medianBlur ()
functie, het doorgeven van onze afbeelding en filtergrootte als parameters. De afbeelding wordt weergegeven met behulp van de cv2.imshow ()
functie en wordt op de schijf opgeslagen met cv2.imwrite ()
.
Het resultaat van het bovenstaande script is als volgt:
Nou, wat denk jij? Heel mooi - een mooie en schone afbeelding zonder ruis.
Je kunt de bovenstaande code downloaden van mijn mediaan-filterrepository op GitHub.
Het gemiddelde filter is een voorbeeld van een lineair filter. Het vervangt in principe elke pixel in het uitvoerbeeld door de gemiddelde (gemiddelde) waarde van de buurt. Dit heeft het effect van het effenen van de afbeelding (het verminderen van de hoeveelheid intensiteitsvariaties tussen een pixel en de volgende), het verwijderen van ruis uit de afbeelding en het oplichten van de afbeelding.
Dus bij gemiddelde filtering wordt elke pixel van de afbeelding vervangen door de gemiddelde waarde van de buren, inclusief de pixel zelf. De 3x3
kernel die wordt gebruikt voor gemiddelde filtering is zoals weergegeven in de onderstaande afbeelding, hoewel andere kernelgroottes kunnen worden gebruikt (bijvoorbeeld 5x5):
Wat de bovenstaande kernel ons eigenlijk probeert te vertellen is dat we alle elementen onder de kernel optellen en het gemiddelde (gemiddelde) van de totale kern nemen.
Een belangrijk punt om hier te noemen is dat alle elementen van de gemiddelde kernel:
Laten we een voorbeeld nemen om de dingen duidelijker te maken. Stel dat we de volgende subafbeelding hebben:
Bij het toepassen van de gemiddelde filter, zouden we het volgende doen:
(7 + 9 + 23 + 76 + 91 + 7 + 64 + 90 + 32) / 9 = 44
Het exacte resultaat is 44.3
, maar ik heb het resultaat afgerond naar 44
. Dus de nieuwe waarde voor de middelste pixel is 44
in plaats van 91
.
Nu naar het codeerdeel. Laten we zeggen dat we de volgende afbeelding met veel ruis hebben:
Wat we op dit punt willen doen, is het gemiddelde filter toepassen op de bovenstaande afbeelding en de effecten bekijken van het toepassen van zo'n filter.
De code voor het uitvoeren van deze bewerking is als volgt:
import cv2 import numpy as np import argparse # maak de argument-parser en ontleed de argumenten ap = argparse.ArgumentParser () ap.add_argument ('- i', '--image', required = True, help = 'Pad naar de invoer afbeelding ') args = vars (ap.parse_args ()) # lees de afbeeldingsafbeelding = cv2.imread (args [' afbeelding ']) # pas het 3x3 gemiddelde filter toe op de afbeeldings-kernel = np.ones ((3,3) , np.float32) / 9 processed_image = cv2.filter2D (image, -1, kernel) # display image cv2.imshow ('Mean Filter Processing', processed_image) # sla afbeelding op naar schijf cv2.imwrite ('processed_image.png', processed image pauzeer de uitvoering van het script totdat een toets op het toetsenbord wordt ingedrukt cv2.waitKey (0)
Bericht van de code die we hebben gebruikt a 3x3
kernel voor onze gemiddelde filter. We hebben ook het filter2D ()
functie om het gemiddelde filter toe te passen. De eerste parameter van deze functie is ons invoerbeeld, de tweede is de gewenste diepte van het uitvoerbeeld ddepth
, en de derde parameter is onze kernel. toewijzen -1
voor de ddepth
parameter betekent dat het uitvoerbeeld de dezelfde diepte als het ingevoerde beeld.
Na het uitvoeren van de code op onze lawaaierige afbeelding, was dit het resultaat dat ik behaalde:
Als u het uitvoerbeeld observeert, kunnen we zien dat het vloeiender is dan het beeld met ruis. Missie gedaan!
Je kunt de bovenstaande code downloaden van mijn gemene filterrepository op GitHub.
Zoals we in deze tutorial hebben gezien, stelt Python ons in staat om geavanceerde taken zoals beeldfiltering uit te voeren, vooral via de OpenCV-bibliotheek, op een eenvoudige manier.
Aarzel niet om te zien wat we te koop aanbieden en om te studeren op de markt, en aarzel niet om vragen te stellen en uw waardevolle feedback te geven met behulp van de onderstaande feed.