towards new pix2pos calibration part 1

This commit is contained in:
2022-07-19 10:13:35 +02:00
parent 1696328a53
commit 7209243f2f
2 changed files with 193 additions and 60 deletions

View File

@@ -7,6 +7,10 @@
# *-----------------------------------------------------------------------*
'''
coordinate systems, optical center, xray axis, pixel sizes etc.
ppm= pixel per mm
update_pix2pos
'''
import logging
import numpy as np
@@ -27,41 +31,84 @@ class geometry:
# this coordinate represents also the origin of other coordinates
pass
def zoom2pixsz(self,zoom):
# this returns the pixel size at a given zoom level
def interp_zoom(self,zoom):
# this calculates the interpoated pix2pos coordinate transformation matrix
# the returned value is a 2x2 matrix:
# [pxx pxy]
# [pyx pyy] which is interpolated out of a lookup table
#
# [pxx pxy] [nx]
# [pyx pyy]*[ny] results in a vector in meter of a vector [nx,ny] pixels in x and y direction
pass
# [a b] [mx] [px]
# [ ]*[ ]=[ ]
# [c d] [my] [py]
def set_zoom2pixsz(self,meas):
K,AA=self._lut_pix2pos
pix2pos=self._pix2pos=np.asmatrix(np.ndarray((2,2),np.float))
pix2pos[0,0]=np.interp(zoom,K,AA[:,0,0])
pix2pos[0,1]=np.interp(zoom,K,AA[:,0,1])
pix2pos[1,0]=np.interp(zoom,K,AA[:,1,0])
pix2pos[1,1]=np.interp(zoom,K,AA[:,1,1])
_log.debug('interpolation array:{}'.format(tuple(pix2pos.ravel())))
def update_pix2pos(self,meas):
#calculates _lut_z2p out of measurements
# the _lut_z2p is dictionaty a lookuptable
# zoom {1,200,400,600,800,1000}
#[pxx pxy]
#[pyx pyy]
self._lut_z2p=_lut_z2p={
'zoom': np.array((1,200,400,600,800,1000),dtype=np.float32),
'pixsz': np.array(
#((pxx,pxy),(pyx,pyy)), # zoom n
((( 1,0),(0, 1)), # zoom 1
(( 2,0),(0, 2)), # zoom 200
(( 4,0),(0, 4)), # zoom 400
(( 6,0),(0, 6)), # zoom 600
(( 8,0),(0, 8)), # zoom 800
((10,0),(0,10))), # zoom 1000
dtype=np.float32)}
#
# [a b] [mx] [px]
# [ ]*[ ]=[ ]
# [c d] [my] [py]
#
# [a*mx1 b*my1] [px1]
# [ ... ... ] [...]
# [a*mxn b*myn] =[pxn]
# [c*mx1 d*my1] [py1]
# [ ... ... ] [...]
# [c*mxn d*myn] [pyn]
#
# [mx1 my1 0 0 ] [a] [px1]
# [... .. 0 0 ] [b] [...]
# [mxn myn 0 0 ]*[c]=[pxn]
# [ 0 0 mx1 my1] [d] [py1]
# [ 0 0 ... .. ] [...]
# [ 0 0 mxn myn] [pyn]
#
# A *aa = y
n=len(meas)
zoom =np.ndarray(shape=n,dtype=np.float32)
pixsz=np.ndarray(shape=(n,2,2),dtype=np.float32)
# https://de.wikipedia.org/wiki/Methode_der_kleinsten_Quadrate
for i,(k,v) in enumerate(meas):
pass
self._lut_z2p={ 'zoom': zoom, 'pixsz': pixsz}
# r= A*aa-y
# mit aa=(A.T*A)^-1*A.T*y
# A=np.zeros((d.shape[0]*2,d.shape[1]))
# A[:d.shape[1]-1,:2]=A[d.shape[1]-1:,2:]=d[:,:2]
#
# y=d[:,2:].T.ravel()
# y=np.asmatrix(y).T
#
# A=np.asmatrix(A)
# aa=(A.T*A).I*A.T*y
# a,b,c,d=aa
# a,b,c,d=np.asarray(aa).ravel()
#
# aa=aa.reshape(2,-1)
AA=np.ndarray((len(meas),2,2),np.float)
K=np.array(tuple(meas.keys()),np.float)
self._lut_pix2pos=(K,AA)
for i,(k,v) in enumerate(meas.items()):
m=np.array(v) # measurements
d=m[1:]-m[0] # distances
A=np.zeros((d.shape[0]*2,d.shape[1]),np.float)
A[:d.shape[1]-1,:2]=A[d.shape[1]-1:,2:]=d[:,:2]
y=d[:,2:].T.ravel()
y=np.asmatrix(y).T
A=np.asmatrix(A)
aa=(A.T*A).I*A.T*y
AA[i]=aa.reshape(2,-1)
#bx_coefs = np.polyfit(nbx[0], nbx[1], 3)
#np.poly1d(bx_coefs)
_log.debug('least square data:\nK:{}\nAA:{}'.format(K,AA))
def autofocus(self):
# cam camera object
@@ -75,12 +122,16 @@ class geometry:
def pix2pos(self,p,zoom=None):
# returns the position m(x,y) in meter relative to the optical center at a given zoom level of the pixel p(x,y)
# if zoom=None, the last zoom value is used
pass
if zoom is not None:
self.interp_zoom(zoom)
return np.asarray(self._pix2pos*np.mat(p).T).ravel()
def pos2pix(self,p,zoom=None):
# returns the pixel p(x,y) of the position m(x,y) in meter relative to the optical center at a given zoom level
# if zoom=None, the last zoom value is used
pass
if zoom is not None:
self.interp_zoom(zoom)
return np.asarray(self._pix2pos.I*np.mat(p).T).ravel()
def optctr2xray(self):
# returns the vector m(x,y) of the optical center to the xray
@@ -130,16 +181,48 @@ if __name__ == "__main__":
1000:{'x': (+0.1 , ( 121, 632),(1044, 592)),
'y': (+0.08 , ( 593, 883),( 570, 145))},
}
measure={
1: [(-3.0 , -7.6 , 116.99110193046, 632.5463827525),
(-2.0 , -7.6 , 934.07501517856, 600.7926167715),
(-2.0 , -7.1 , 916.54131238102, 191.0366615002),
(-3.0 , -7.1 , 103.74668003329, 226.2150231456)],
200: [(-3.1 , -7.3 , 113.66321353086, 824.9041423107),
(-2.3 , -7.3 , 1065.97386092697, 792.2851118419),
(-2.3 , -6.7 , 1033.68452410347, 74.0336610693),
(-3.1 , -6.7 , 84.62681572700, 116.6832971512)],
400: [(-3.4 , -6.7 , 155.00053674203, 601.3838942136),
(-3.0 , -6.7 , 957.95919656052, 573.0827012272),
(-3.2 , -6.5 , 541.08684037200, 187.9171307943),
(-3.2 , -6.8 , 564.32152887203, 789.1146957326)],
600: [(-3.3 , -6.8 , 328.27244399903, 509.5061192017),
(-3.1 , -6.8 , 992.78996735279, 488.0323963092),
(-3.2 , -6.9 , 672.03111567934, 832.4122409755),
(-3.2 , -6.7 , 645.70960116180, 164.2534779331)],
800: [(-3.2 , -6.7 , 639.52253576449, 53.4455632943),
(-3.2 , -6.85, 671.47023245203, 882.6335091391),
(-3.3 , -6.75, 105.12470026379, 361.3051859197),
(-3.1 , -6.75, 1195.96864609255, 313.1068618673)],
1000:[(-3.25, -6.75, 195.05641095116, 353.3492286375),
(-3.15, -6.75, 1117.27204644084, 314.9636405871),
(-3.2 , -6.8 , 675.10991143017, 790.3040145281),
(-3.2 , -6.72, 638.98580653116, 59.3803912957)]}
import numpy as np
np.set_printoptions(suppress=True)
np.set_printoptions(linewidth=196)
obj=geometry()
obj.calc_zoom2pixsz(measure)
obj.update_pix2pos(measure)
obj.interp_zoom(1)
obj.interp_zoom(200)
obj.interp_zoom(100)
print(np.asarray(obj._pix2pos*np.mat((1,0)).T).ravel())
print(obj._pix2pos*np.mat((0,1)).T)
print(obj._pix2pos*np.mat((2,.1)).T)