{"id":253,"date":"2021-10-11T18:18:25","date_gmt":"2021-10-11T18:18:25","guid":{"rendered":"http:\/\/liipetti.net\/retkia\/?p=253"},"modified":"2021-10-11T18:19:45","modified_gmt":"2021-10-11T18:19:45","slug":"neurokuvatreenit-harj-2-2","status":"publish","type":"post","link":"https:\/\/liipetti.net\/retkia\/neurokuvatreenit-harj-2-2\/","title":{"rendered":"Neurokuvatreenit, harj 2+"},"content":{"rendered":"\n<p>Vaikka k\u00e4sittelemme kuvantekoa ja k\u00e4sittely\u00e4 neuroverkoilla, suuri osa kehittelyst\u00e4 ja koodausty\u00f6st\u00e4 liittyy muuhun kuin itse algoritmiin. Edellisess\u00e4 artikkelissa jo t\u00f6rm\u00e4simme mm. siihen, miten joudutaan muuntamaan kuvia eri esitystapojen v\u00e4lill\u00e4 (esim. 0..1 pikselikuvista -1..1 tensoreiksi), kun haluamme ja on j\u00e4rkev\u00e4\u00e4kin k\u00e4ytt\u00e4\u00e4 valmiita kirjastoja.<br><br>T\u00e4h\u00e4nastisten skriptien varmaankin suurin k\u00e4yt\u00e4nn\u00f6n ongelma on se ett\u00e4 kaikki asetukset ovat koodissa. Esimerkiksi tavoitekuvan nimen on oltava <em>test.png<\/em> ja sen muuttaminen vaatii koodiin koskemista. T\u00e4ss\u00e4 artikkelissa muutammekin koodia niin ett\u00e4 asetukset voidaan antaa komennon yhteydess\u00e4 tyyliin:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">python harj2ii.py --image summer2019\/image0028.jpg --lr 0.002 --imageSize 512 --b 0.3<\/pre>\n\n\n\n<p>T\u00e4ll\u00e4 komennolla otamme tavoitteeksi tietyn kuvan koneeltamme, mist\u00e4 hyv\u00e4ns\u00e4 kansiosta, asetamme koulutustahdin, teemme kuvaa koossa 512x512px ja painotamme vihre\u00e4\u00e4 neli\u00f6t\u00e4 painolla 0.3.<\/p>\n\n\n\n<p>T\u00e4t\u00e4 varten joudumme ensinn\u00e4kin luomaan ns. argumenttiparserin, jossa m\u00e4\u00e4rittelemme mit\u00e4 asetuksia voidaan tai on pakko antaa, mink\u00e4 tyyppisi\u00e4 ne ovat (kokonaisluku, liukuluku, tosi\/ep\u00e4tosi, merkkijono eli raaka teksti) ja annamme niille oletusarvon, ts. mit\u00e4 arvoa k\u00e4ytet\u00e4\u00e4n jos asetusta ei ole annettu.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">import argparse\n\n# use command line parameters\nparser = argparse.ArgumentParser()\n\n# define params and their types with defaults if needed\n\nparser.add_argument('--image', type=str, default=\"test.png\", help='path to image')\nparser.add_argument('--image2', type=str, default=\"\", help='path to optional second image')\nparser.add_argument('--b', type=float, default=0, help='blend factor, 0 for none')\nparser.add_argument('--lr', type=float, default=0.05, help='learning rate')\nparser.add_argument('--niter', type=int, default=150, help='number of iterations')\nparser.add_argument('--name', type=str, default=\"harj2i\", help='basename for storing images')\nparser.add_argument('--show', action=\"store_true\", help='show image in a window')\n\n# get params into opt object, so we can access them like opt.image\n\nopt = parser.parse_args()<\/pre>\n\n\n\n<p>Nyt kaikki em. asetukset ovat ohjelmassa k\u00e4ytett\u00e4viss\u00e4, esim. kuvatiedoston nimi l\u00f6ytyy opt.image:sta. Niinp\u00e4 koodia on nyt muutettava vastaavasti, esimerkkej\u00e4 alla.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">filename = opt.image #\"test.png\"\nimgT = preprocess(Image.open(filename).convert(\"RGB\"))<\/pre>\n\n\n\n<p>Tai vaihtoehtoisesti ihan vain&#8230;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">imgT = preprocess(Image.open(opt.image).convert(\"RGB\"))\nimgT2 = preprocess(Image.open(opt.image2).convert(\"RGB\"))\n\noptimizer = torch.optim.Adam([imgG], lr)<\/pre>\n\n\n\n<p>Ja optimointisilmukan sis\u00e4ll\u00e4<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    # calculate loss\n    loss1 = torch.abs(imgT - imgG).mean()\n\n    # an alternative loss: green target\n    loss2 = torch.abs(imgT2 - imgG).mean()\n    \n    # use opt.b to adjust the effect of the second target image \n\n    loss2 = opt.b * loss2\n    loss = loss1 + loss2\n\n    #...\n\n    # save image with a name given as a parameter\n\n    if (i &lt; 10) or (i % 10 == 0):\n        save_image(imgG, opt.name+\"-\"+str(i)+\".jpg\") \n<\/pre>\n\n\n\n<p>Olemme t\u00e4h\u00e4n asti seuranneet kuvan kehittymist\u00e4 tallennettuja kuvatiedostoja seuraamalla. Usein on k\u00e4tev\u00e4\u00e4 jos voi seurata kuvan kehityst\u00e4 suoraan n\u00e4yt\u00f6ll\u00e4 olevasta ikkunasta. T\u00e4m\u00e4 on t\u00e4ysin mahdollista, vaikka ajammekin ohjelmaa komentorivill\u00e4, kunhan vain olemme itse koneen \u00e4\u00e4ress\u00e4 emmek\u00e4 pelk\u00e4n p\u00e4\u00e4teyhteyden takana. Tehd\u00e4\u00e4n nyt sit\u00e4 varten rutiini. Siihen tarvitaan kirjastot opencv ja numpy, jotka muutenkin kuuluvat keskeiseen ty\u00f6kalupakkiin n\u00e4iss\u00e4 hommissa.<\/p>\n\n\n\n<p>Luomme t\u00e4ss\u00e4 show_on_screen -rutiinin, jolle annetaan kuvan sis\u00e4lt\u00e4v\u00e4 tensori, joka muunnetaan pytorch-maailmasta pythonin kuvank\u00e4sittelymaailmaan ja n\u00e4ytet\u00e4\u00e4n ruudulla omassa ikkunassaan. Ikkunan oletusnimi on out, ja niin kauan kuin nime\u00e4 ei muuteta, kuva p\u00e4ivittyy samassa ikkunassa. Haluttaessa voidaan luoda useampia ikkunoita ja seurata usean kuvan muuttumista. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># import opencv image processing library and numpy\n\nimport cv2\nimport numpy\n\n# define display routine\n\ndef show_on_screen(image_tensor, window=\"out\"):\n    im = image_tensor.detach().numpy()   # convert from pytorch tensor to numpy array\n    \n    # pytorch tensors are (C, H, W), rearrange to (H, W, C)\n    im = im.transpose(1, 2, 0)\n    \n    # adjust range to 0 .. 1\n    im -= im.min()\n    im \/= im.max()\n\n    # show it in a window (this will not work on a remote session)    \n    cv2.imshow(window, im)\n    cv2.waitKey(100)   # display for 100 ms and wait for a keypress (which we ignore here)\n<\/pre>\n\n\n\n<p>Viel\u00e4 ei ole ihan valmista. Teimme vasta rutiinin jolla halutessamme voimme n\u00e4ytt\u00e4\u00e4 kuvia ruudulla. Viel\u00e4 pit\u00e4\u00e4 muuttaa koodia niin ett\u00e4 my\u00f6s k\u00e4yt\u00e4mme sit\u00e4. Sopiva paikka on optimointisilmukan lopussa, jossa my\u00f6s talletamme kuvan levylle.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">    # save image\n    if (i &lt; 10) or (i % 10 == 0):\n        save_image(imgG, opt.name+\"-\"+str(i)+\".jpg\")    \n\n    # show on screen\n    if opt.show:\n        show_on_screen(imgG, opt.name)<\/pre>\n\n\n\n<p>Huomaa my\u00f6s ett\u00e4 kuvaa n\u00e4ytet\u00e4\u00e4n ruudulla vain jos komennossa on asetus &#8211;show mukana. T\u00e4m\u00e4 asetus on sellaista tyyppi\u00e4, johon ei anneta luku- tai muuta arvoa, vaan sen l\u00e4sn\u00e4ololla tehd\u00e4\u00e4n er\u00e4\u00e4nlainen on\/off-ohjaus. Joko n\u00e4yt\u00e4mme kuvaa (&#8211;show) tai emme n\u00e4yt\u00e4.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Vaikka k\u00e4sittelemme kuvantekoa ja k\u00e4sittely\u00e4 neuroverkoilla, suuri osa kehittelyst\u00e4 ja koodausty\u00f6st\u00e4 liittyy muuhun kuin itse algoritmiin. Edellisess\u00e4 artikkelissa jo t\u00f6rm\u00e4simme mm. siihen, miten joudutaan muuntamaan kuvia eri esitystapojen v\u00e4lill\u00e4 (esim. 0..1 pikselikuvista -1..1 tensoreiksi), kun haluamme ja on j\u00e4rkev\u00e4\u00e4kin k\u00e4ytt\u00e4\u00e4 valmiita kirjastoja. T\u00e4h\u00e4nastisten skriptien varmaankin suurin k\u00e4yt\u00e4nn\u00f6n ongelma on se\u2026<\/p>\n<p class=\"continue-reading-button\"> <a class=\"continue-reading-link\" href=\"https:\/\/liipetti.net\/retkia\/neurokuvatreenit-harj-2-2\/\">Continue reading<i class=\"crycon-right-dir\"><\/i><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-253","post","type-post","status-publish","format-standard","hentry","category-neurokuvatreenit"],"_links":{"self":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts\/253","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/comments?post=253"}],"version-history":[{"count":1,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts\/253\/revisions"}],"predecessor-version":[{"id":254,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts\/253\/revisions\/254"}],"wp:attachment":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/media?parent=253"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/categories?post=253"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/tags?post=253"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}