5.13. Lineaire filters en omgevingsfilters¶
De pixelwiskunde-bewerkingen eerder in dit hoofdstuk combineerden twee afbeeldingen punt voor punt. Filters doen verwant werk op een andere manier: ze berekenen de waarde van elke uitvoerpixel op basis van een kleine omgeving van invoerpixels rond de overeenkomstige positie. De uitvoer op (x, y) is een of andere statistiek – het gemiddelde, de mediaan, de meest voorkomende waarde – van de invoerpixels in een klein vak met (x, y) als middelpunt.
Die kleine verschuiving in benadering – van één pixel tegelijk naar een venster van pixels tegelijk – is wat een hele familie nuttige bewerkingen laat werken. Een eenvoudig gemiddelde over een klein venster strijkt sensorruis glad. De mediaan over hetzelfde venster verwijdert losse pixelvlekjes zonder de randen evenveel te verzachten. Een bilateraal gemiddelde weigert te middelen over sterke contrastgrenzen heen, waardoor de randen van objecten behouden blijven terwijl de texturen erbinnen worden opgeschoond. De omgeving is de werkeenheid; de keuze van de statistiek bepaalt wat het filter doet.
5.13.1. De kernelgrootte¶
Elk omgevingsfilter neemt een size-parameter die de straal van het venster in pixels instelt. Het venster zelf is vierkant en beslaat (2 * size + 1) pixels per zijde – dus size=1 betekent een omgeving van 3 bij 3, size=2 betekent 5 bij 5, size=3 betekent 7 bij 7, enzovoort.
De omgeving schuift één pixel tegelijk over de afbeelding, van linksboven naar rechtsonder. Elke uitvoerpixel is het resultaat van het toepassen van de statistiek van het filter op de invoeromgeving met die pixel als middelpunt.¶
Grotere afmetingen betekenen grotere omgevingen, wat een vloeiendere (of agressievere) filtering betekent. De kosten groeien met de oppervlakte van het venster, dus een size=3-filter doet ongeveer negen keer zoveel werk per pixel als een size=1-filter. De praktische standaard voor het meeste opschoonwerk is size=1 of size=2; grijp pas naar grotere afmetingen wanneer kleine omgevingen niet volstaan om het kenmerk te onderdrukken dat de toepassing probeert te onderdrukken.
5.13.2. Het gemiddeldefilter¶
mean() vervangt elke pixel door het rekenkundig gemiddelde van zijn omgeving. Het resultaat strijkt de variatie van pixel tot pixel glad over de grootte van het venster, wat het de goedkoopste manier maakt om sensorruisvlekjes te onderdrukken: hoogfrequente variatie middelt uit, laagfrequente inhoud blijft behouden.
De afweging is dat randen en andere scherpe kenmerken ook worden uitgemiddeld. Een heldere rand die vóór het filter één pixel breed was, is na een size=1-gemiddeldefilter twee of drie pixels breed, met de helderheid die aan de flanken afloopt. Voor pure ruisreductie op een textuurarme afbeelding (een schone muur, de binnenkant van een gekleurde marker) is de afweging prima. Voor een drukke scène waarin randen ertoe doen, past meestal een van de volgende filters beter.
img.mean(1) # 3x3 box average -- fast, gentle smoothing
img.mean(2) # 5x5 box average -- stronger, slower
5.13.3. Mediaan, modus, middelpunt¶
De andere drie statistische omgevingsfilters ruilen het eenvoudige rekenkundige gemiddelde in voor iets dat robuuster is tegen uitschieters.
median() retourneert de mediaan van de omgeving – de waarde die in het midden van de gesorteerde lijst van venstervpixels terechtkomt. Een enkele zeer heldere of zeer donkere pixel in het venster trekt de mediaan niet mee; deze wordt gewoon een van de weggegooide uitersten. Het praktische effect is dat mediaanfiltering losse pixelvlekjes en zout-en-peperruis verwijdert zonder de randen zo te verzachten als mean doet. De kosten zijn meer rekenwerk per pixel – een venster sorteren is trager dan het middelen ervan – en het resultaat is niet strikt een gemiddelde, wat soms van belang is voor verdere berekeningen.
Een percentile-parameter (standaard 0.5) verschuift de gekozen waarde weg van de strikte mediaan. percentile=0.0 retourneert het minimum van de omgeving, percentile=1.0 het maximum; tussenliggende waarden kiezen proportioneel daartussenin in het gesorteerde venster. Dat geeft median de mogelijkheid om donkere of heldere delen van de omgeving te benadrukken zonder de uitschieter-robuustheid van de ordestatistiek te verliezen.
mode() retourneert de meest voorkomende waarde in de omgeving. Nuttig wanneer het ruismodel is “de meeste pixels zijn juist, een paar zijn in verschillende mate beschadigd geraakt”, waarbij het juiste antwoord is welke waarde het vaakst voorkomt – wat de mediaan kan missen wanneer de beschadigde waarden zich aan één kant van het gesorteerde venster opstapelen.
midpoint() retourneert een gewogen combinatie van het minimum en het maximum van de omgeving – bias=0.5 geeft het middelpunt daartussen, bias=0.0 geeft het minimum, bias=1.0 geeft het maximum. Minder vaak gebruikt dan de andere, maar het is goed om te kennen wanneer het doel specifiek is om donkere of heldere kenmerken te extraheren.
5.13.4. Bilateraal, de randbehoudende versie¶
bilateral() is het omgevingsfilter dat het meest de moeite waard is om goed te begrijpen. Het levert het gladstrijkende effect van mean(), maar met een extra beperking: hoe meer een omgevingspixel verschilt van de centrumpixel, hoe minder deze meetelt in het gemiddelde. Het resultaat strijkt de binnenkant van elke uniforme regio glad zonder uit te lopen over de randen die ze van elkaar scheiden, wat precies is wat de meeste toepassingen werkelijk willen.
Twee parameters bepalen hoe agressief het filter pixels afwaardeert:
color_sigmabepaalt hoe kleurverschil de weging beïnvloedt. Kleinere waarden betekenen dat het filter strenger is in het afwaarderen van pixels die van het centrum verschillen.space_sigmabepaalt hoe ruimtelijke afstand de weging beïnvloedt. Kleinere waarden geven meer gewicht aan pixels dicht bij het centrum.
De standaardwaarden (color_sigma=0.1, space_sigma=1.0) zijn redelijke uitgangspunten; ze afstemmen is meestal een kwestie van het filter op een voorbeeldframe uitvoeren en bijstellen totdat de randen scherp zijn en de binnenkanten schoon.
Bilateraal is duurder dan median() en aanzienlijk duurder dan mean(), dus het is de moeite waard om er alleen naar te grijpen wanneer het randbehoudende gedrag is wat de toepassing nodig heeft.
5.13.5. Adaptieve drempelwaarde-bepaling¶
De filters voor gemiddelde, mediaan, modus en middelpunt dragen allemaal hetzelfde paar trefwoordargumenten dat hun uitvoer omzet in een binaire drempelwaarde:
threshold=Trueschakelt het filter over naar drempelwaardemodus.offset=Nverschuift de lokale drempel metNeenheden vóór de vergelijking.
Het mechanisme bouwt rechtstreeks voort op het gewone gedrag van het filter. Zonder threshold=True berekent het filter zijn statistiek over de omgeving en schrijft die statistiek naar de uitvoerpixel. Met threshold=True berekent het filter dezelfde statistiek, vergelijkt vervolgens de bronpixel op dezelfde positie met de statistiek plus de offset, en schrijft de maximumwaarde van het formaat als de bron groter is, anders nul.
Het resultaat is een binaire afbeelding waarvan de drempel meebeweegt met de lokale helderheid over het frame. Heldere regio’s krijgen een hoge drempel, schemerige regio’s krijgen een lage drempel, en een voorgrondpixel die lokaal helderder is dan zijn buren matcht ongeacht of deze in een heldere of schemerige regio zit – wat precies het gedrag is dat één enkele globale drempelwaarde niet kon produceren op een ongelijkmatig belichte afbeelding.
img.mean(3, threshold=True, offset=5)
De offset-parameter is waar de toepassing bepaalt hoe streng de test is. Een kleine positieve offset eist dat de bronpixel meetbaar helderder is dan zijn buren voordat deze als match telt, wat sensorruis-vals-positieven onderdrukt ten koste van het laten vallen van zwakke voorgrond. Een kleine negatieve offset vangt zwakke voorgrond op ten koste van het doorlaten van wat ruis. De keuze hangt af van wat de rest van de pipeline met de binaire uitvoer gaat doen.
Bij ongelijkmatige belichting kan één enkele globale drempelwaarde de voorgrond niet op elke positie beschrijven. Een omgevingsfilter dat met threshold=True wordt uitgevoerd, produceert een drempel die meebeweegt met de lokale helderheid en de voorgrond correct classificeert over het hele frame.¶
De filterfamilie voert de adaptieve drempelwaarde uit, dus het kiezen van het juiste filter is van belang: mean() voor de goedkoopste adaptieve drempelwaarde, median() wanneer de invoer zout-en-peperruis bevat die het filter zou moeten verwerpen voordat de lokale drempel wordt berekend.