Osebe v Picasi
Naloga
Program Picasa v vsakem direktoriju s slikami naredi (skrito) datoteko z imenom .picasa.ini
, v katero shranjuje podatke o slikah (filtre in druge transformacije, ki jih uporabimo na sliki, imena oseb na sliki in podobno). Njena vsebina je lahko videti, recimo, takole:
V prvih, preprostejših nalogah bomo predpostavili, da s slikami nismo počeli nič drugega, kot da smo Picasi povedali, katere osebe so na njej. Tedaj je datoteka takšne oblike.
faces=
. Temu sledi seznam oseb, ločen s podpičji. Na dveh slikah je le ena oseba, na drugi pa sta dve; prva je opisana z rect64(acb64583d1eb84cb),2623af3d8cb8e040
in druga z rect64(58bf441388df9592),d85d127e5c45cdc2
. Opis osebe je sestavljen iz dveh podatkov, ki sta ločena z vejico: prvi nas bo zanimal le pri rešitvi za oceno 10 in ga tu ne bomo opisovali, drugi pa predstavlja identifikacijsko številko osebe.
Katera identifikacijska številka ustreza kateri osebi, vidimo v datoteki contacts.xml
, ki jo Picasa shrani v C:\Users\janez\AppData\Local\Google\Picasa2\contacts\
(pri čemer namesto "janez" lahko piše ana, branka, cene, dani, eva ali francka; imena ostalih direktorijev so nekoliko drugačna v starejših različicah Windowsov). Vsebina contacts.xml
je takšna.
Tisto, kar vidimo pod id
, je identifikacijska številka, pod name
pa ime osebe. (Če vam brskalnik prelomi vrstice: v resnici je vsak contact
ves v eni vrstici.)
Naloge
Naloga je sestavljena iz več delov, ki vam prinesejo različne ocene. Sistem za oddajo nalog si zapomni le zadnjo oddano datoteko; če boste oddali več nalog, jih zazipajte ali pa dajte rešitve v isto datoteko .py.
- Za oceno 6: Napiši program, ki bere datoteko
.picasa.ini
in kopira slike v nove datoteke, katerih imena so enaka identifikacijskim številkam oseb na teh slikah (npr. 8ff985a43603dbf8.jpg). Če je na isti sliki več oseb, naredi več kopij. Če se ista oseba pojavi na več slikah, naj kasnejše kopije slike povozile prejšnje; četudi se oseba 8ff985a43603dbf8 morda pojavi na več slikah, bo obstajala bo le ena datoteka s tem imenom. Pri tem predpostavi, da imamo preprosto datoteko.picasa.ini
(glej priloženo datoteko). V gornji, preprosti.picasa.ini
bi skopiralimg_8538.jpg
vd5a2d2f6f0d7ccbc.jpg
,img_8551.jpg
v2623af3d8cb8e040.jpg
ind85d127e5c45cdc2.jpg
(ker sta na njej dva obraza) terimg_8555.jpg
v8ff985a43603dbf8.jpg
. - Za oceno 7: Kot za 6, vendar naj bodo imena datotek enaka imenom oseb, pri čemer presledke zamenjaš s podčrtaji. Namesto
8ff985a43603dbf8.jpg
bo torej pisaloAndrej_Brodnik.jpg
, saj namcontacts.xml
pove, da številka 8ff985a43603dbf8 odgovarja Andreju Brodniku. (Priznam, da ga nisem vprašal, ali mu ta številka res odgovarja, vendar predpostavljam, da mu.) Tako kot prej kasnejše slike povozijo prejšnje; na koncu imamo le eno datotekoAndrej_Brodnik.jpg
, čeprav se Andrej Brodnik morda pojavi na več slikah. V gornji.picasa.ini
bi skopiralimg_8538.jpg
vFranc_Solina.jpg
,img_8551.jpg
vRok_Rupnik.jpg
inIgor_Kononenko.jpg
(ker sta na njej dva obraza) terimg_8555.jpg
vAndrej_Brodnik.jpg
. - Za oceno 8: Kot za 7, vendar dodaj kasnejšim kopijam zaporedne številke, tako da ne povoziš slik osebe z istim imenom. Če bi bil Andrej Brodnik na štirih slikah, bi te imele imena
Andrej_Brodnik.jpg
,Andrej_Brodnik_0001.jpg
,Andrej_Brodnik_0002.jpg
inAndrej_Brodnik_0003.jpg
. Predpostaviš lahko, da je bila posamezna oseba slikana največ 10000-krat. - Za oceno 9: Spremeni program tako, da bo znal prebrati tudi
.picasa.ini
, ki ima poleg teh še druge informacije (glej priloženo.picasa-tezji.ini
. (Motivacija: rešitev naloge za 9 je v bistvu lažja od te za 8.) - Za oceno 10: Kot prej, vendar naj ne kopira slik takšnih kot so, temveč le obraze, ki se nahajajo na njih. Rezultat so torej datoteke z imeni
Andrej_Brodnik.jpg
,Andrej_Brodnik_0001.jpg
,Andrej_Brodnik_0002.jpg
... na katerih je samo obraz Andreja Brodnika. (Motivacija: sploh ni tako težko, rešitev obsega približno 30 vrstic, brez kakih posebnih trikov in tlačenja). Datoteke, ki jih naredi program, morajo biti takšne, kot v tem arhivu. Edit: Tudi program za oceno 10 mora znati brati "polno" datoteko .picasa.ini, sa pravi takšno, kot jo imate v arhivu pod imenom.picasa-tezji.ini
Vaša rešitev mora biti pravilna. Če rešujete nalogo za oceno 10 in niste prepričani, da je rešitev pravilna, raje rešitev še nalogo za oceno 9 in/ali nižjo ter oddajte vse skupaj v enem samem .zip-u.
Roki
Nalogo je potrebno oddati do 26. novembra. Za reševanje imate torej dva tedna časa.Pomoč
- Za oceno 6:
- Datoteko
.picasa.ini
berite v zankiwhile True:
in za branje uporabljajtef.readline()
(če jef
datoteka). Zanko prekinete, ko preberete prazno vrstico. Znotraj vsake iteracije zanke boste trikrat napisalireadline
, da boste prebrali vse tri vrstice, ki se nanašajo na posamezno sliko. Namesto tega lahko uporabite tudireadlines()
, ki prebere vse vrstice, in telovadite z njimi. - Vrstice, ki se začnejo s faces, najprej razdelite (
split
) glede na podpičja, nato glede na vejice. - Datoteko lahko skopirate tako, da jo odprete kot binarno datoteko, preberete v niz, odprete binarno datoteko z novim imenom in vanjo shranite prebrani niz. (Gre pa tudi hitreje, a ni potrebno.)
- Datoteko
- Za oceno 7:
- Ko berete
contacts.xml
, vas zanimajo le vrstice, ki se začnejo (startswith
) z "<contacts>
" (ne spreglejte presledka na začetku!). Računate lahko na to, da je identifikacijska številka vedno od 14. do 30. znaka v vrstici, ime pa od 38. do dva znaka predtem, ko se v vrstici pojavi (find
) podniz "display
". (Če bi šlo zares, ne bi smeli delati tako mazaško, temveč bi uporabili Pythonov modul za branje datotek v obliki .xml. Če znate, ga smete uporabiti tudi pri reševanju naloge.) - Pare identifikacijska številka - ime osebe je najbolj praktično shranjevati v slovar. O njem se bomo učili naslednji teden. Gre pa tudi brez.
- Ko berete
- Za oceno 8:
- Funkcija
os.path.exists(ime_datoteke)
pove, ali datoteka z danim imenom že obstaja. Če obstaja, poskusite ali obstaja tudi datoteka z dodano številko 0001. Če obstaja, poskusite z 0002 in tako naprej, dokler je treba.
- Funkcija
- Za oceno 9:
- Datoteko beri kar v zanki for. Ko naletiš na vrstico, ki se začne in konča z oglatim oklepajem, ti pove ime datoteke. Ko naletiš na vrstico, ki se začne s
faces=
, ti pove, kateri obrazi so na datoteki, katere ime si nazadnje videl.
- Datoteko beri kar v zanki for. Ko naletiš na vrstico, ki se začne in konča z oglatim oklepajem, ti pove ime datoteke. Ko naletiš na vrstico, ki se začne s
- Za oceno 10:
- Za to oceno pa je potrebno pokazati zmožnost samostojnega iskanja dokumentacije po spletu. Namestite si modul PIL in poglejte dokumentacijo zanj. Ne bo težko: potrebujete le funkcijo
Image.open
ter metodicrop
insave
ter lastnostsize
. - Kako prebrati koordinate, je nekdo lepo opisal (npr. http://www.facebook.com/topic.php?uid=2483740875&topic=12994 ):
1) If there are less than 16 characters, add 0's to the beginning. 2) If the picasa code is 0123456789ABCDEF, then the upper left corner of the face tag is at (0123,4567) and the lower right corner is at (89AB,CDEF) 3) The upper left corner of the photo is always (0000,0000) while the lower right is always (FFFF,FFFF). 4)The resolution of the photo doesn't matter. To the face tagging software, every photo is FFFF wide and FFFF tall, which equates to 65535 x 65535 (about 4,295 MP.. wow!) So, if your tag is in the center of the photo, the center of your tag would be at (32767,32767) which is (7FFF,7FFF). For example, the center of my [upper right] tag from my earlier post (cfff 0000 ffff 4000) is ((ffff-cfff),(4000-0000)) which comes to (3000,4000).
Niz, v katerem je zapisano šestnajstiško število, pretvorite v int tako, da funkcijiint
dodate argument 16, npr.int("f00d", 16)
. Naprej se znajdite sami - desetko bo potrebno zaslužiti. :)
- Za to oceno pa je potrebno pokazati zmožnost samostojnega iskanja dokumentacije po spletu. Namestite si modul PIL in poglejte dokumentacijo zanj. Ne bo težko: potrebujete le funkcijo
Rešitev za 7
Rešitev za 6 zahteva predvsem, da znamo prebrati in razkosati datoteko .picasa.ini
. Od reševalca zahteva, da zna delati z datotekami (odpiranje, branje, kopiranje), predvsem pa gre za veliko telovadbo z metodo split
in seznami.
Naloga za 7 zahteva branje datoteke contacts.xml
, kar z nekaj iznajdljivosti ni težko. Od reševalca se pričakuje tudi, da bo znal uporabiti slovar, saj je to najhitrejši, najpreprostejši, najnaravnejši, da si zabeležimo, kateri številki pripada katero ime osebe.
Začnimo s tem, drugim, branjem contacts.xml
in shranjevanjem v slovar.
Nič hudega nam ni bilo: najprej sestavimo prazen slovar. Nato po vrsticah beremo contacts.xml
. Če se vrstica ne začne s <contact id=
, nas ne zanima in rečemo le continue
(lahko pa bi obrnili pogoj... kar vam je ljubše). Sicer iz nje poberemo id, ki je vedno od 14. do 30. znaka in ime, ki se začne pri 38. znaku in konča dva znaka pred besedo display
. To shranimo v slovar.
contact
in iz vsakega pobere atributa id
in name
ter ju doda v slovar. Pri takšnem branju predpostavljamo le, da bodo kontakti vedno zapisani v elementu z imenom contact
in da bosta identifikacijska številka v atributih id
in name
. Vse ostalo pa lahko Google spreminja, kakor hoče.
Videl sem nekaj takšnih rešitev. Ob predpostavki, da njihovi avtorji v resnici sami vedo za parserje za XML: pohvalno.
Glavni problem drugega dela je, kako brati vsako tretjo vrstico datoteke in eno za njo, ono, ki še ostane, pa izpustiti. Ena možna rešitev je ta:
Datoteko beremo z readline
, ki jih ponavljamo v neskončni zanki - po tri v vsakem krogu zanke. Ko preberemo povsem prazno vrstico, zanko prekinemo z break
. Sicer pa je prva prebrana vrstica ime slike - brez prvega in zadnjega znaka, ki sta zaklepaja, druga vrstica pa so obrazi. Vrstico z obrazi razkosamo po podpičjih, da dobimo posamezne osebe; for osebe in obraz.split(";")
. Opis vsake osebe, naprej, razkosamo po vejici. Dobimo seznam z dvema elementoma. Prvi pove, kje na sliki se nahaja obraz osebe; tega ignoriramo. Drugi je id osebe, s katerim iz slovarja dobimo ime. Ostane le še kopiranje datoteke s primernimi imeni.
Drug, prav tako simpatičen način branja datoteke, je ta, da preberemo kar vse vrstice, potem pa z zanko jemljemo vsako tretjo...
Tudi kopiramo lahko hitreje: uvozimo modul shutil
in uporabimo njegovo funkcijo copy
. Zadnji vrstici zamenjamo z
Rešitev za 8
Za 8 je potrebno le še popaziti na ime datoteke. Ime sestavimo, nato v zanki preverjamo, ali že obstaja in v tem primeru dodeljujemo novega. Recimo tako:
Rešitev za 9
Za oceno 9 je bilo potrebno znati brati datoteke .picasa.ini
, ki vsebujejo tudi več informacij, torej ni več nujno, da je v vsaki tretji vrstici nova slika in da ji tako sledijo obrazi. Branje napišemo s kar preprosto logiko: datoteko beremo po vrsticah, z običajno zanko for
(s čimer se mimogrede izognemo tudi potrebi po tem, da bi preverjali, ali je vrstica prazna in v tem primeru prekinjali branje z break
. Če se vrstica začne z oglatim oklepajem, vemo, da gre za ime slike - zapomnimo si ga. Če naletimo na vrstico, ki se začne s faces
pa vemo, da gre za seznam oseb, ki ga razkosamo tako kot prej.
Skratka, "bralni" del se spremeni v
Rešitev za 10
Celotna rešitev za oceno 10 je takšna: