5.19. Tonkorrigeringar

Tonkorrigeringar ändrar hur ljusstyrka och färg fördelas i en infångad bild – de korrigeringar en applikation tillämpar när en bildruta är för mörk, för ljus, för platt eller skev mot fel färg.

Korrigeringarna tillhör två familjer: justeringar av ljusstyrka och kontrast som omfördelar ljusstyrkan, och färgjusteringar som ändrar vilken färg varje pixel tolkas som. Båda har motsvarigheter i sensorns ISP, som korrigerar varje bildruta på väg in; metoderna här tillämpas på en redan infångad Image, i efterhand, för de fall där bildrutan behöver mer korrigering än vad ISP:n gav.

5.19.1. Histogramutjämning

Den enklaste kontraststräckningsoperationen är histogramutjämning. Tanken är att omforma pixelvärden så att histogrammet för utdata blir så platt som möjligt – varje värde förekommer ungefär lika ofta. Den visuella effekten är att en bild med låg kontrast (en vars histogram är koncentrerat till ett smalt band) blir en bild med hög kontrast vars pixlar täcker hela intervallet 0255.

histeq() kör utjämningen:

img.histeq()

Mekaniken är direkt. Den kumulativa fördelningsfunktionen (CDF) för källans histogram beräknas; varje indatapixels värde mappas till sin position i CDF:en, skalad till utdataintervallet. Där pixlarna redan var jämnt spridda ligger mappningen nära identiteten; där pixlarna var hopade vid en viss ljusstyrka sprider mappningen ut dem genom att sträcka den ljusstyrkan över ett bredare intervall av utdatavärden.

Resultatet är dramatiskt på scener med låg kontrast – skillnaden mellan ett dunkelt inomhusfotografi och samma fotografi efter histeq är ofta skillnaden mellan ”oläsbart” och ”perfekt läsbart”. Avvägningen är att operationen förstärker allt, inklusive sensorbrus. På en scen med verkliga detaljer med låg kontrast att återskapa är histeq rätt svar; på en ren, väl exponerad scen som helt enkelt inte behöver det introducerar histeq synligt brus.

5.19.2. CLAHE: adaptiv utjämning

Histogramutjämning är global: den använder en CDF beräknad från hela bilden och tillämpar den överallt. Det fungerar på bilder vars ljusstyrkeintervall är ungefär jämnt, men misslyckas på scener med lokalt mörka och ljusa områden – CDF:en dras mot den sida som har flest pixlar, och den motsatta sidan överkorrigeras.

Den adaptiva varianten är Contrast Limited Adaptive Histogram Equalisation, vanligtvis kallad CLAHE. Istället för en global CDF beräknar CLAHE en separat CDF för varje liten ruta i bilden, utjämnar varje ruta mot sin egen CDF och blandar samman rutgränserna. Resultatet är att ljusstyrkejusteringar sker lokalt – det skuggade hörnet får sin egen utjämning utan att det ljusa hörnet drar det åt fel håll.

Flaggan adaptive=True växlar histeq() till CLAHE-läge:

img.histeq(adaptive=True, clip_limit=10)

Parametern clip_limit är den del av CLAHE som ordet ”contrast limited” i namnet syftar på. Lokal utjämning kan överförstärka brus i platta områden där CDF:en har väldigt få distinkta värden; klippgränsen begränsar hur aggressivt en enskild låda kan omfördelas, vilket förhindrar brusförstärkningen samtidigt som kontraststräckningen tillåts där den spelar roll. Ett värde runt 10 är en rimlig utgångspunkt; större värden låter CLAHE arbeta hårdare till priset av mer synligt brus, mindre värden gör den mildare.

CLAHE är dyrare än den globala histeq, men ger renare resultat på scener där ljusstyrkan är ojämnt fördelad – vilket de flesta verkliga scener är.

5.19.3. Gamma, kontrast och ljusstyrka

Histogramutjämning är det datadrivna sättet att omforma ljusstyrka. Det dataoberoende sättet är att tillämpa en vald kurva, parametriserad av några lättjusterade rattar. gamma() tillhandahåller tre:

img.gamma(gamma=1.0, contrast=1.0, brightness=0.0)

Varje parameter tillämpar en specifik transformation på varje pixel:

gamma kör varje pixels värde genom potensfunktionen output = input ** (1 / gamma). Standardbetydelsen: värden större än 1.0 ljusar upp bilden och lyfter mellantoner (den klassiska ”monitor gamma”-korrigeringen); värden mindre än 1.0 mörkar ner den. Parametern är icke-linjär – den bevarar svart- och vitpunkterna och omformar endast fördelningen däremellan, vilket är rätt beteende när målet är att återskapa detaljer i skugg- eller högdagerområden utan att krossa de befintliga ytterligheterna.

contrast kör varje pixel genom en rak multiplikation kring mellangråpunkten. Värden större än 1.0 ökar kontrasten (mörkt blir mörkare, ljust blir ljusare, mellangrått förblir detsamma); värden mindre än 1.0 minskar kontrasten.

brightness adderar en konstant till varje pixelvärde. Positiva värden ljusar upp, negativa värden mörkar ner. Förskjutningen är enhetlig – ingenting bevaras – vilket sällan är vad en applikation vill ha för sig självt, men passar väl ihop med en kontrastpassning för att åter centrera resultatet.

De tre parametrarna kombineras: ett enda anrop till gamma() kan tillämpa en gammakurva, sedan en kontrastmultiplikation och sedan en ljusstyrkeförskjutning, allt i en enda passning. Ordningen är gamma först, sedan kontrast, sedan ljusstyrka, vilket matchar den ordning som ger de mest intuitiva resultaten när alla tre avviker från standardvärdena.

5.19.4. Automatisk vitbalans

Färgfamiljen av tonkorrigeringar börjar med automatisk vitbalans. Samma mekanism som sensorns ISP kör som en del av bildbehandlingspipelinen – justering av de relativa förstärkningarna på de röda, gröna och blå kanalerna så att en genomsnittlig gråfärgad fläck tolkas som verkligt grå – finns också tillgänglig som en efterbehandlingsoperation på en färdig Image:

img.awb()

Standardvärdet använder gray-world-algoritmen: medelfärgen i hela bilden antas vara neutralt grå, och förstärkningarna per kanal justeras så att det blir så. Den alternativa formen max=True använder white-patch-algoritmen: de ljusaste pixlarna antas vara neutralt vita, och förstärkningarna justeras så att de blir det. Båda fungerar på RGB565 och på rå Bayer; ingen fungerar på gråskala (där det inte finns någon färg att balansera) eller YUV (där färgrepresentationen inte är vad dessa algoritmer arbetar på).

När man ska ta till efterbehandlingsformen i stället för ISP:ns automatiska vitbalans: när ISP:ns val passade dåligt för just den scenen, när applikationen laddar referensbilder från disk som fångades under andra förhållanden, eller när färgbedömningen är viktig nog att applikationen vill köra om den med sitt eget val av algoritm.

5.19.5. Färgkorrigeringsmatrisen

När färgkorrigeringen bilden behöver inte är den skalning per kanal som vitbalans ger, utan en mer allmän kanalblandning, är operationen att ta till färgkorrigeringsmatrisen. Metoden ccm() tillämpar en 3-gånger-3-matris (eller 3-gånger-4 med offset) som multiplicerar varje pixels (r, g, b)-vektor för att producera en ny (r, g, b)-vektor:

img.ccm([[1.1, -0.05, -0.05],
        [-0.05, 1.1, -0.05],
        [-0.05, -0.05, 1.1]])

Matrisen låter applikationen korrigera överhörning mellan färgkanalerna – där den röda sensorns respons exempelvis inkluderar visst grönt ljus kan matrisen subtrahera en bråkdel av den gröna kanalen från den röda utsignalen för att kompensera. Kombinerat med en offset per kanal låter 3-gånger-4-formen även applikationen nollställa varje kanal på nytt.

Materialet om ISP-pipelinen täcker varför bakom färgkorrigeringsmatriser. Efterbehandlingsformen på Image är bara samma operation, tillämpad i efterhand.