Dans la conversion de coordonnées dans le traitement d'image, il est courant d'obtenir les coordonnées de l'image d'origine correspondant à l'indice de (i, j) de l'image convertie en utilisant la conversion inverse et interpoler par un procédé tel que bilinéaire.
En C et C ++ etc., je n'avais pas d'autre choix que de faire pivoter les doubles boucles, mais en Numpy et Python je ne voulais pas utiliser pour les boucles autant que possible, j'ai donc écrit un code qui semble efficace [une page sur Github]( Je l'ai trouvé sur https://github.com/NitishMutha/equirectangular-toolbox/blob/master/nfov.py), alors je l'ai changé pour moi-même.
Inutile de dire que dans le cas de la conversion Affine ou par projection, il est plus rapide d'utiliser la librairie OpenCV dédiée.
Créez un tableau qui enregistre l'indice de coordonnées de (i, j) avant la conversion. Si vous créez un tableau à l'aide d'un tableau et que vous le superposez à l'aide d'une mosaïque ou d'une répétition, vous pouvez le faire en un rien de temps.
Dans l'exemple suivant, il est soustrait du centre de l'image cx, cy, normalisé, puis multiplié par le rapport de circonférence pour le convertir en coordonnées polaires sphériques, mais c'est la même chose.
xline = (np.arange(wid)-cx)*2*pi/wid
yline = -(np.arange(hei)-cy)*pi/hei
Xsline = np.tile(xline,hei)
Ysline = yline.repeat(wid,axis=0)
Il ne vous reste plus qu'à appliquer diverses transformations non linéaires à ces séquences. Des fonctions simples telles que sinus cosinus et logarithme sont préparées dans numpy, donc si vous les passez au tableau telles quelles, elles seront toutes traitées de manière uniforme et c'est beaucoup plus rapide que d'écrire une instruction for.
Les valeurs de pixels correspondant aux coordonnées obtenues précédemment sont interpolées et finalement remodelées dans la forme de l'image.
Dans le code ci-dessous, si les valeurs maximale et minimale de l'indice de pixel sont dépassées, il est mis en boucle, mais en général, il est préférable de compléter avec une valeur telle que 0.
def _bilinear_interpolation_loop(frame, screen_coord):
''' Calculate
input: frame and its subpixel coordinate [x,y]
'''
frame_height,frame_width,frame_channel =frame.shape
#uf = np.mod(screen_coord[0],1) * frame_width # long - width
#vf = np.mod(screen_coord[1],1) * frame_height # lat - height
x0 = np.floor(screen_coord[0]).astype(int) # coord of pixel to bottom left
y0 = np.floor(screen_coord[1]).astype(int)
uf = screen_coord[0] # long - width
vf = screen_coord[1] # lat - height
x2 = np.add(x0, np.ones(uf.shape).astype(int)) # coords of pixel to top right
y2 = np.add(y0, np.ones(vf.shape).astype(int))
# Assume Loop
x2 = np.where(x2 > frame_width-1, 0, x2)
y2 = np.where(y2 > frame_height-1, 0, y2)
base_y0 = np.multiply(y0, frame_width)
base_y2 = np.multiply(y2, frame_width)
A_idx = np.add(base_y0, x0)
B_idx = np.add(base_y2, x0)
C_idx = np.add(base_y0, x2)
D_idx = np.add(base_y2, x2)
flat_img = np.reshape(frame, [-1, frame_channel])
#print(flat_img.shape)
A = np.take(flat_img, A_idx, axis=0)
B = np.take(flat_img, B_idx, axis=0)
C = np.take(flat_img, C_idx, axis=0)
D = np.take(flat_img, D_idx, axis=0)
wa = np.multiply(x2 - uf, y2 - vf)
wb = np.multiply(x2 - uf, vf - y0)
wc = np.multiply(uf - x0, y2 - vf)
wd = np.multiply(uf - x0, vf - y0)
#print(wa,wb,wc,wd)
# interpolate
AA = np.multiply(A.astype(np.float32), np.array([wa, wa, wa]).T)
BB = np.multiply(B.astype(np.float32), np.array([wb, wb, wb]).T)
CC = np.multiply(C.astype(np.float32), np.array([wc, wc, wc]).T)
DD = np.multiply(D.astype(np.float32), np.array([wd, wd, wd]).T)
out = np.reshape(np.round(AA + BB + CC + DD).astype(np.uint8), [frame_height, frame_width, 3])
return out
Dans le blog suivant, j'ai créé une image lorsque la caméra tout-ciel était virtuellement tournée en fonction de l'image de la projection cylindrique à distance régulière.
https://ossyaritoori.hatenablog.com/entry/2019/12/10/RICOH_THETA_SC%E3%81%A7%E5%A4%9A%E9%87%8D%E9%9C%B2%E5%85%89%E3%83%BB%E5%90%88%E6%88%90%E3%82%92%E3%81%97%E3%81%A6Pixel4%E3%81%BF%E3%81%9F%E3%81%84%E3%81%AB%E3%82%AF%E3%83%AA%E3%82%A2%E3%81%AA