<< | #254 ; Mirakloj de OpenCV kaj Harris Corner |
>> |
Por nia grava projekto 3D-fotilo estas esence por trovi specialaj unikaj lokoj en la du fotoj de 3D-fotilo, bonaj lokaj fotaj trajtoj, relative malgrandaj anguloj en la fotoj. Eblas akurate lokigi angulon kaj horizontale kaj vertikale. Esence estas ke koloroj en la 2D -foto estas multe aliaj ĉirkaŭ la anguloj. Angulo estas pli bona ol rando ĉar simila rando povus esti en multaj lokoj en la foto, sed bona angulo estas en nur unu loko.
Oni nuntempe ofte uzas metodon SIFT por trovi tiaj anguloj, sed bedaŭrinde ĝi ne laboris en OpenCV -muntado de mia apude fotita RPi4 4GB, pro ia problemo kun la memoro. Nu, eble la malutilo tamen ne estas granda. Ĉiuokaze mia projekto estas kiel eble plej pura Raspberry Pi -projekto.
Avantaĝo de SIFT (Scale Invariant Feature Transform) estas ke ĝi estas imuna por la skalo de foto. Tamen en la 3D-fotilo la du fotiloj ja estas samaj, la objektivoj estas samaj, la pozo de fotiloj estas la sama kaj la distanco al detaloj de celo el ambaŭ fotiloj estas proksimume la sama. Tial la skalo en la du fotoj estas proksimume la sama, nenia granda diferenco inter ili, nenia signifa rotacio inter la fotoj.
Do mi pensas ke la simpla metodo Harris Corner estas egale bona metodo por trovi anguloj por miaj intencoj. Malgrandaj solvoj estas bonaj. Nia nacio Mueleja Insulo ja estas malgranda kaj ni favoras ekonomiaj, malpezaj solvoj. Simpla estas bona. Troa komplikeco ne utilas. Ekzistas multe da teoria informo pri la metodo Harris Corner Detector sed en praktiko ni ja volas uzi programojn.
Certe ekzistas por la 3D-fotilo ankaŭ la semantika problemo: "Kiuj punktoj de foto reprezentas kion objekton?", sed tion ni traktu poste aparte. Niaj propraj rezultoj ne bezonas esti ĉie rekonataj. Universitato mian laboron ne akceptas, sed mi ne bezonas universitaton. Ni havas nian propran vivon.
Do la principa ideo por la programo de 3D-fotilo estas unue por trovi bonaj anguloj kaj sekve por identigi la samaj anguloj en iom nesimilaj du fotoj kiuj prezentas la saman objekton el iom nesamaj vidpunktoj. Sekve oni povus utiligi Epipolar Geometry por tiuj gravaj punktoj. Poste mi eble povus kalkuli distancojn de tiuj punktoj kaj eble konkludi la distancon de grava objekto en la fotoj.
Mi selektis novan malnovan foton el stacidomo de Kurikka por testi la metodon. La apuda foto prezentas kredeble biciklon por brava vilaĝa muzikisto por transporti sian gravan instrumenton, harmonikon, eble origine el 1940-aj jaroj? Kredeble ekzistas multaj bonaj anguloj en la foto.
Mi tamen devas tuj konfesi ke la situacio de programo estas ankoraŭ iom implika. Mi devas multe pli labori por trovi bonajn solvojn. Jen iom da Python programo kun OpenCV. Unue ni simple rekte marku per ruĝa koloro tiuj punktoj de foto por kiuj la metodo Harris Corner rakontas ke ie ĉirkaŭ tio punkto estas bona angulo en la foto.
import cv2 # OpenCV import numpy as np filename = '/home/pi/Kuvat/i4014.jpg' img = cv2.imread(filename) print ( img.shape ) # (200, 300, 3) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # gray = np.float32(gray) print ( gray.shape ) # ( 200, 300) dst = cv2.cornerHarris(gray, 2, 3, 0.04) print ( dst.size ) # 60000 print ( dst.min(), dst.max() ) # -0.004989784 0.006724929 dst = cv2.dilate(dst, None) # Por iom pligrandigi la intervalon print ( dst.min(), dst.max() ) # -0.002261328 0.006724929 img[dst > 0.05*dst.max()] = [0, 0, 255] # Ruĝa koloro por punkto kie la valoro estas pli ol 5% de plej granda # Ordo de koloroj: BGR ; Blue, Green, Red (Esperante: blua, verda, ruĝa) dstmax = dst.max() lkm = 0 for i in range(200): for j in range(300): if (dst[i, j] > 0.05*dstmax): lkm = lkm + 1 print ('Sume:', lkm) # Sume: 2764 cv2.imshow('rezulto', img) cv2.imwrite('/home/pi/Kuvat/rezulto.jpg', img)
La metodo Harris Corner kalkulas la valorojn por la tabelo dst
el la "nigra kaj blanka" vario de foto. La tabelo havas same multe da nombroj kiel la foto havas punktoj, 200 * 300 = 60000. Ĉi tie mi ja montras nur la koloran foton, sed la metodo fakte uzas nur la "nigran kaj blankan" foton, nomo en programo: gray
.
Mi bontrove decidis ke tiuj punktoj prezentu proksiman angulon en la foto kie la valoro estas pli ol 5% de plej granda valoro kaj la programo markis tiuj punktoj per ruĝa punkto por la apuda kolora foto. Kredeble estas la plej proksimaj punktoj por la plej fortaj anguloj en la foto. Estis sume 2764 da tiaj punktoj, kion la supra programo kalkulis.
Iom multe da punktoj, proksimaj al io forta angulo. Mi apenaŭ volas selekti ĉiuj tiuj punktoj. Estas grupoj da punktoj. Kiam la punktoj estas tre proksimaj unu al la alia, oni kredeble povus selekti tian ortangulon el la foto ke ĝi enhavas plejparton de tiuj punktoj. Granda valoro por punkto ja signifas ke ie proksime ĉirkaŭ tio punkto ekzistas forta angulo en la foto. La angulo ja ne povas esti en nur unu rastrunuo de foto. La angulo certe bezonas multaj rastrunuoj (pixel).
Mi provas kalkuli la grupojn de ruĝaj punktoj en la foto. Nu, iom malfacile por kalkuli mem ... eble proksimume 100 grupoj da ruĝaj punktoj?
Grando de rastrunuo en la foto estas grava afero. La fotiloj havas milionoj da pixel sed ni povas foti ekzemple per iom malgranda disiga kapablo 640 px * 480 px, nur 0,3 megapixel. Por proksima objekto tio tamen estas relative bone, eblas disigi relative malgrandaj detaloj.
Certe ekzistas pli bonaj metodoj, sed mi provizore kredas ke mi povus simple selekti proksimume 100 malgrandaj ortanguloj, grando ekzemple 5*5 punktoj (ekzistas centra punkto kiam la nombroj estas neparaj), el la foto por prezenti la plej fortaj anguloj en la foto. Simplaj solvoj ofte estas sufiĉe bonaj. Ekzistas tamen problemo: kio estus la centra punkto de ortangulo kiam estas multaj alternativoj? La centraj punktoj de ortanguloj ĉirkaŭ anguloj devus esti la samaj en la du fotoj de sama objekto por ke la 3D-fotilo bone laboru.
Rastrunuo estas principe la plej malgranda parto de foto. Eble oni tamen povus atingi eĉ pli bonan precizecon? Ekzistas nome rimedoj por tio. Mi utiligas programon kion mi trovis en la komputila reto:
import cv2 import numpy as np from matplotlib import pyplot as plt filename = '/home/pi/Kuvat/i4014.jpg' img = cv2.imread(filename) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # Harris corners gray = np.float32(gray) dst = cv2.cornerHarris(gray, 2, 3, 0.04) dst = cv2.dilate(dst, None) ret, dst = cv2.threshold(dst, 0.05*dst.max(), 255, 0) dst = np.uint8(dst) print ('ret:', ret) # ret: 1421734.2000000002 print ( dst.shape ) # (200, 300) print ('max:', dst.max()) # max: 255 # centroids ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst) print ('ret:', ret) # ret: 115 print (labels) #[[0 0 0 ... 0 0 0] # [0 0 0 ... 0 0 0] # ... # [0 0 0 ... 0 0 0]] print (stats) #[[ 0 0 300 200 57236] # [ 77 11 5 5 22] # ... # [ 188 197 4 3 11]] img[dst > 0.05*dst.max()] = [255, 255, 255] - img[dst > 0.05*dst.max()] # Aliaj koloroj por la bonaj angulaj punktoj en la kolora foto criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001) corners = cv2.cornerSubPix(gray, np.float32(centroids), (5,5), (-1,-1), criteria) print ( 'centers:', centroids.shape ) # centers: (115, 2) print ( 'corners:', corners.shape ) # corners: (115, 2) print ( corners ) # [[151.17497 99.26604 ] # [ 77.243675 11.164596 ] # ... # [190.88435 196.60349 ]] centroids = np.uint8(centroids) for i in range(centroids.shape[0]): img = cv2.rectangle(img, ((centroids[i,0]-3), (centroids[i,1]-3)), ((centroids[i,0]+3), (centroids[i,1]+3)), (0,255,0), 1) # Ortangulo 7*7 en verda koloro corners = np.uint8(corners) for i in range(corners.shape[0]): img = cv2.rectangle(img, ((corners[i,0]-3), (corners[i,1]-3)), ((corners[i,0]+3), (corners[i,1]+3)), (255,0,255), 1) # Ortangulo 7*7 en lila koloro res = np.hstack((centroids, corners)) res = np.int0(res) print ( "res:", res.shape ) # res: (115, 4) lkm = 0 for i in range(res.shape[0]): if ( ( res[i,0] != res[i,2] ) & ( res[i,1] != res[i,3] ) ): print ( i, ":", res[i], centroids[i], corners[i] ) lkm = lkm + 1 # 1 : [78 13 77 11] [78 13] [77 11] # 4 : [73 26 76 27] [73 26] [76 27] # ... # 114 : [189 198 190 196] [189 198] [190 196] print ( "Sume:", lkm ) # Sume: 41 # BGR? RGB? img[res[:,1], res[:,0]] = [255, 255, 255] # punktoj en blanka koloro img[res[:,3], res[:,2]] = [0, 255, 0] # punktoj en verda koloro cv2.imwrite('/home/pi/Kuvat/subpix.jpg', img) plt.imshow(img, cmap='gray') plt.show()
Mi devas ankoraŭ pensi, eksperimenti kaj lerni por kompreni la programon. La rezultoj estas iom konfuzaj kaj surprizaj.
Kaj jen sube maldekstre la nova OpenCV -foto kion la supra programo fine skribis, en la pli ekonomiema .JPG formato, anstataŭ .PNG. La formato .JPG eble perdas kelkaj punktoj. La ortanguloj tamen estas pli gravaj.
Ĉu la ordo de koloroj en la tabulo estas BGR aŭ RGB? Por OpenCV la ordo de koloroj ŝajnas BRG sed por Matplotlib la ordo estas alia: RGB. Tamen la RGB koloro [0, 255, 0] estas la sama verda kiel BGR koloro [0, 255, 0] kaj la RGB koloro [255, 0, 255] estas la sama lila koloro kiel BGR koloro [255, 0, 255].
Konfuze. Mi devas pli bone lerni por uzi OpenCV. Certe la forta OpenCV estas la laborilo plej konvena por komputila vidkapablo. Provizore mi tamen ne tute komprenas kiel eblus utiligi la rezulton por selekti konvenaj anguloj en la foto. Certe la mezuroj de ortanguloj devus esti la samaj por ke oni ilin povus bone kompari.
Do, nun mi estas konsterniĝita. Plue, la sekvanta foto rekte per Matplotlib estas iom alia. Mi ree malgrandigis la foton kaj aliigis la formaton de rezulto al mia favorita pli ekonomiema formato .JPG. Principe la sama foto, sed aliaj koloroj. La ortanguloj tamen havas la samaj koloroj.
Nu certe komputila vidkapablo plejparte uzas nur "nigraj kaj blankaj" (diversaj tonoj de griza) fotoj kaj tial eble estas iom strange por provi uzi koloraj fotoj por la rezulto. Mi tamen esperas ke la fotoj estas perobjektivaj.
Klare mi estis tro optimisma kun la programa parto de projekto 3D-fotilo. La projekto postulas pli da tempo, pli da energio, pli da cerbo. Mi devas konfesi ke la solvo por anguloj en la fotoj ankoraŭ ne estas preta. Ni tamen progresu forte kaj insiste.
La kvalito de fotoj certe ne estas kiel eble plej bona ... sed estas nur eksperimento. Mi ne volas malŝpari centoj da miloj da bajtoj por ioj simplaj testaj fotoj. Ni lernos kaj ni batalos.
... laboro kontinuas ...
Kaj certe fine ..........
NI VENKOS!
La Ambasadoro en Pori de sendependa nacio Mueleja Insulo |