Kuvien käsittely pythonilla, osa 1

Neurokuvatreenien yhteydessä nousee yhtenään esille, että siinä on kyseessä uusi paradigma käsitellä ja generoida kuvia. Tässä sarjassa katsotaan sitä ”vanhaa” mallia, jossa käydään suoraan käsiksi kuvan pikseleihin, jota kaiken aikaa tarvitaan myös neurokuvanteossa. Käytännössä melkeinpä enemmän näitä kuin sitä syväoppimista.

Käytämme python-ohjelmointikieltä ja opencv-kirjastoa. Kuten neurokuvatreenit, tämäkään ei ole pythonin peruskurssi. Esittelen miten hommat toimivat ja käytän siinä pythonia ja opencv:tä esimerkkinä.

Lähdetään siitä että meillä on kansiossa kuvatiedosto, vaikkapa test4.png. Avaan python-tulkin, luen opencv-kirjastolla kuvan ja katsotaan mitä se on syönyt.

>>> import cv2
>>> im = cv2.imread("test4.png")
>>> im.shape
(480, 640, 3)
>>> im.min()
1
>>> im.max()
252
>>> im[0,0]
array([118, 163, 224], dtype=uint8)

Mitä tapahtui? Luimme kuvan muuttujaan im, näemme että sen mitat ovat 480x640x3, mitkä vastaavat kuvan korkeutta ja leveyttä, ja 3 vastaa kuvan kolmea värikanavaa, RGB eli punainen, vihreä ja sininen. Katsomme tuossa vielä, että kuvassamme värikanavien arvot ovat välillä 1…252.

Kukin pikseli esitetään siis kolmella värikanavalla, joiden arvot ovat kokonaislukuja välillä 0..255, juuri se mikä kahdeksalla bitillä voidaan esittää.

Lopuksi katsomme oikeassa ylänurkassa olevan pikselin arvon: 118, 163, 224. Tässä kohtaa pitää varoittaa: opencv:ssä värikanavien järjestys on BGR, eli tuossa siis punainen on kirkkain, ei sininen.

Voisimme muuttaa tuon pikselin arvon yksinkertaisesti näin. Talletamme sen myös levylle jotta näemme miten kävi. Tosin yhden pikselin muutosta ei kovin selvästi taida huomata.

>>> im[0,0] = (0, 0, 255)
>>> cv2.imwrite("test4b.png", im)
True

Muutetaan kerralla isompi alue jostain kuvan keskivaiheilta:

>>> im[200:250,300:360] = (0, 0, 255)
>>> cv2.imwrite("test4c.png", im)
True

Ja nyt kun katsomme mitä tiedostosta löytyy, on sinne kuvaan todella ilmaantunut punainen suorakulmio.

Luetaanpa toinenkin kuva ja kokeilla laittaa kuvat päällekkäin. Huomataan että toinen kuva on eri kokoinen, joten leikataan siitä sopiva pala.

>>> im2 = cv2.imread("test.png")
>>> im2.shape
(1000, 871, 3)
>>> h = 480
>>> w = 640
>>> im2b = im2[200:200+h, 100:100+w]
>>> im2b.shape
(480, 640, 3)

Lasketaan sitten kuvien keskiarvo, siis kuvat pikseleittäin yhteen ja jaetaan kahdella. Tässä nyt tulee kuitenkin rajoja vastaan… useiden pikselien summa nousee yli ylärajan 255 ja kun se vielä jaetaan kahdella, lopputulos ei koskaan nouse yli 128:n kirkkaat sävyt leikkautuvat pois ja kuvasta tulee tummasävyinen. Kokeillaan kuitenkin, kokeilemalla löytää usein mielenkiintoisia efektejä. Eli tuossa vasemmalla ensimmäinen kuva, sitten toisesta kuvast rajaamamme palanen, ja lopuksi laskutoimituksemme tulos. Ei hassumpi.

Tuo voidaan välttää tekemällä jakolasku ennen summausta. Periaatteessa siinä menetetään tarkkuutta, mutta kokeillaan. Kaksi peräkkäistä jakomerkkiä tuossa tarkoittaa että lasketaan kokonaisluvuilla, haluamme tuloksenkin kokonaislukuna.

>>> im9b = im//2 + im2b//2
>>> cv2.imwrite("tulos9b.png", im9b)
True

Ja nyt saammekin tämmöisen, mikä riittää meille tässä vaiheessa. Käytännössä tässä siirryttäisiin laskennan ajaksi liukulukuihin ja lopputulos muunnettaisiin sitten taas kokonaisluvuksi. Mutta ei mennä siihen vielä.

Tässä osassa siis olemme lukeneet kuvatiedostoja levyltä, löytäneet kuvan pikselit taulukkona ja kokeilleet muuttaa niitä ja sitten taas tallettaneet muunnetun kuvan levylle. Näin se kuvankäsittely siis menee. Katsotaan jatkossa lisää.

Comments are closed