%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%22marimo%3E%3D0.23.9%22%2C%20%22numpy%3E%3D2.0%22%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.25.2%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Direct%20Linear%20Transformation%20(DLT)%0A%0A%20%20%20%20%3E%20Marcos%20Duarte%2C%20Renato%20Naville%20Watanabe%3Cbr%3E%0A%20%20%20%20%3E%20%5BLaboratory%20of%20Biomechanics%20and%20Motor%20Control%5D(https%3A%2F%2Fbmclab.pesquisa.ufabc.edu.br%2F)%3Cbr%3E%0A%20%20%20%20%3E%20Federal%20University%20of%20ABC%2C%20Brazil%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20How%20to%20use%20this%20guide%0A%0A%20%20%20%20Two%20cameras%20see%20a%20marker%20at%20different%20pixel%20coordinates.%20How%20do%20those%20two%20images%20become%20one%20three-dimensional%20position%20in%20metres%20or%20millimetres%3F%20We%20will%20calibrate%20a%20projective%20camera%20model%20from%20known%20points%2C%20then%20reconstruct%20an%20unknown%20point.%0A%0A%20%20%20%20First%20work%20through%20homogeneous%20coordinates%20and%20the%20number%20of%20independent%20parameters.%20Run%20the%20preserved%20two-camera%20example%2C%20and%20use%20the%20Exercises%20to%20distinguish%20calibration%20error%2C%20reconstruction%20error%20and%20geometric%20degeneracy.%20The%20Problems%20provide%20final%20answers%20only.%20You%20need%20matrices%20and%20least%20squares.%0A%0A%20%20%20%20**Opening%20challenge.**%20Can%20a%20single%20calibrated%20image%20tell%20whether%20a%20marker%20is%20nearby%20or%20far%20away%20along%20its%20viewing%20ray%3F%20What%20extra%20information%20would%20remove%20the%20ambiguity%3F%0A%0A%20%20%20%20%23%23%20Python%20setup%0A%0A%20%20%20%20NumPy%20supplies%20linear%20algebra.%20This%20file%20contains%20the%20attributed%20DLT%20implementation%20used%20when%20the%20optional%20%60dltx%60%20package%20is%20absent%2C%20so%20no%20installation%20cell%20is%20necessary.%20The%20example%20coordinates%20are%20embedded%20in%20the%20notebook.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Camera%20calibration%20and%20point%20reconstruction%20based%20on%20DLT%0A%0A%20%20%20%20The%20fundamental%20problem%20here%20is%20to%20find%20a%20mathematical%20relationship%20between%20the%20coordinates%20of%20a%203D%20point%20and%20its%20projection%20onto%20the%20image%20plane.%20DLT%20estimates%20a%20homogeneous%20projective%20mapping%20with%20linear%20algebra.%20The%20underlying%20geometric%20assumption%20is%20a%20distortion-free%20pinhole%20camera%3B%20the%20pixel%20coordinates%20require%20division%20by%20a%20depth-dependent%20homogeneous%20scale.%3Cbr%3E%0A%20%20%20%20In%20simplistic%20terms%2C%20using%20a%20pinhole%20camera%20model%2C%20it%20can%20be%20found%20by%20similar%20triangles%20the%20following%20relation%20between%20the%20image%20coordinates%20(u%2Cv)%20and%20the%203D%20point%20(X%2CY%2CZ)%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20s%5Cbegin%7Bbmatrix%7D%20u%20%5C%5C%20v%5C%5C%201%20%5Cend%7Bbmatrix%7D%20%3D%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%20L1%20%26%20%20L2%20%26%20L3%20%26%20L4%20%5C%5C%5C%20L5%20%26%20L6%20%26%20L7%20%26%20L8%20%5C%5C%5C%20L9%20%26%20L10%20%26%20L11%20%26%20L12%20%5Cend%7Bbmatrix%7D%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%20X%20%5C%5C%5C%20Y%20%5C%5C%5C%20Z%20%5C%5C%5C%201%20%5Cend%7Bbmatrix%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20matrix%20%24L%24%20is%20the%20camera%20projection%20matrix.%20The%20scale%20%24s%24%20varies%20from%20point%20to%20point%3A%20divide%20the%20first%20two%20projected%20homogeneous%20coordinates%20by%20the%20third%20to%20recover%20pixel%20coordinates.%20This%20is%20the%20%5Bpinhole%20model%20in%20the%20current%20OpenCV%20documentation%5D(https%3A%2F%2Fdocs.opencv.org%2F4.x%2Fd9%2Fd0c%2Fgroup__calib3d.html).%20For%20a%202D%20point%20(X%2CY)%2C%20this%20matrix%20is%203x3.%20The%20matrix%20is%20determined%20only%20up%20to%20a%20nonzero%20scale%2C%20so%20it%20has%2011%20independent%20parameters%20(8%20for%20planar%20DLT).%20Fixing%20the%20last%20entry%20to%20one%20is%20a%20valid%20normalization%20only%20when%20that%20entry%20is%20nonzero.%0A%0A%20%20%20%20There%20are%20more%20accurate%20(but%20more%20complex)%20algorithms%20for%20camera%20calibration%20that%20also%20consider%20lens%20distortion.%20For%20example%2C%20OpenCV%20and%20Tsai%20softwares%20have%20been%20ported%20to%20Python.%20However%2C%20DLT%20is%20classic%2C%20simple%2C%20and%20effective%20(fast)%20for%20most%20applications.%0A%0A%20%20%20%20DLT%20is%20typically%20used%20in%20two%20steps%3A%201.%20Camera%20calibration.%202.%20Object%20(point)%20reconstruction.%0A%0A%20%20%20%20The%20camera%20calibration%20step%20consists%20in%20digitizing%20points%20with%20known%20coordinates%20in%20the%20real%20space%20and%20find%20the%20camera%20parameters.%3Cbr%3E%0A%20%20%20%20At%20least%204%20points%20are%20necessary%20for%20the%20calibration%20of%20a%20plane%20(2D%20DLT)%20and%20at%20least%206%20points%20for%20the%20calibration%20of%20a%20volume%20(3D%20DLT).%20For%20the%202D%20DLT%2C%20at%20least%20one%20view%20of%20the%20object%20(points)%20must%20be%20entered.%20A%20single%20camera%20can%20be%20calibrated%20from%20known%203D%20points%3B%20reconstructing%20an%20unconstrained%20unknown%203D%20point%20requires%20at%20least%20two%20distinct%20calibrated%20views.%20Calibration%20points%20must%20also%20avoid%20degenerate%20configurations%3A%20a%20point%20count%20alone%20does%20not%20guarantee%20a%20unique%20fit.%0A%0A%20%20%20%20These%20coordinates%20(from%20the%20object%20and%20image(s))%20are%20inputed%20to%20a%20DLT%20algorithm%20which%20estimates%20the%20camera%20parameters%20(8%20for%202D%20DLT%20and%2011%20for%203D%20DLT).%0A%0A%20%20%20%20Usually%20it%20is%20used%20more%20points%20than%20the%20minimum%20necessary%20and%20the%20overdetermined%20linear%20system%20is%20solved%20by%20a%20least%20squares%20minimization%20algorithm%20or%20using%20singular%20value%20decomposition%20(SVD).%0A%0A%20%20%20%20With%20these%20camera%20parameters%20and%20with%20the%20camera(s)%20at%20the%20same%20position%20of%20the%20calibration%20step%2C%20we%20now%20can%20reconstruct%20the%20real%20position%20of%20any%20point%20inside%20the%20calibrated%20space%20(area%20for%202D%20DLT%20and%20volume%20for%20the%203D%20DLT)%20from%20the%20point%20position(s)%20viewed%20by%20the%20same%20fixed%20camera(s).%0A%0A%20%20%20%20See%20more%20about%20DLT%20at%20%5Bhttps%3A%2F%2Fdocs.opencv.org%2F4.x%2Fd9%2Fdab%2Ftutorial_homography.html%5D(https%3A%2F%2Fdocs.opencv.org%2F4.x%2Fd9%2Fdab%2Ftutorial_homography.html).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Exercise%201.**%20A%20camera%20maps%20a%20point%20to%20homogeneous%20image%20coordinates%20%24(600%2C300%2C3)%24.%20What%20are%20the%20pixel%20coordinates%3F%20Does%20multiplying%20all%20camera%20coefficients%20by%205%20change%20them%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Worked%20solution%20%E2%80%94%20Exercise%201%0A%0A%20%20%20%20Dividing%20by%20the%20third%20coordinate%20gives%20%24(200%2C100)%24%20pixels.%20A%20common%20nonzero%20scale%20cancels%20in%20both%20ratios%2C%20so%20multiplying%20the%20matrix%20by%205%20gives%20the%20same%20pixels.%0A%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Python%20code%20for%20camera%20calibration%20and%20point%20reconstruction%20based%20on%20DLT%0A%0A%20%20%20%20%3E%20%5Bdltx%5D(https%3A%2F%2Fpypi.org%2Fproject%2Fdltx%2F)%3A%20This%20package%20implements%20camera%20calibration%20and%20point%20reconstruction%20by%20direct%20linear%20transformation%20(DLT).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20executable%20example%20uses%20the%20embedded%20NumPy%20implementation%20if%20the%20optional%20%60dltx%60%20package%20is%20unavailable.%20Its%20original%20package%20attribution%20and%20example%20are%20retained%20below.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Exercise%202.**%20How%20many%20scalar%20image%20equations%20come%20from%20six%203D%20calibration%20points%3F%20Why%20does%20that%20not%20prove%20that%20every%20six-point%20set%20works%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Worked%20solution%20%E2%80%94%20Exercise%202%0A%0A%20%20%20%20Each%20point%20supplies%20two%20equations%2C%20hence%20twelve%20equations%20for%20eleven%20projective%20degrees%20of%20freedom.%20Their%20independence%20also%20matters%3A%20coplanar%20or%20otherwise%20degenerate%20configurations%20do%20not%20identify%20a%20general%20volumetric%20camera.%0A%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Example%20from%20%5Bdltx%5D(https%3A%2F%2Fgithub.com%2Fjoonaojapalo%2Fdltx)%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(dlt_calibrate_1%2C%20dlt_reconstruct_1)%3A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20from%20dltx%20import%20dlt_calibrate%2C%20dlt_reconstruct%0A%20%20%20%20except%20ImportError%3A%0A%20%20%20%20%20%20%20%20%23%20dltx%20is%20not%20installed%3A%20use%20the%20copy%20of%20its%20code%20in%20the%20cell%20below%0A%20%20%20%20%20%20%20%20print('dltx%20is%20not%20installed%3B%20using%20the%20copy%20of%20its%20code%20in%20this%20notebook.')%0A%20%20%20%20%20%20%20%20dlt_calibrate%2C%20dlt_reconstruct%20%3D%20dlt_calibrate_1%2C%20dlt_reconstruct_1%0A%0A%20%20%20%20%23%20Define%20locations%20of%206%20or%20more%20points%20in%20real%20world.%0A%20%20%20%20world_positions%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%5B0%2C%20%20%20%20%200%2C%20%20%20%20%20%202550%5D%2C%20%20%23%20point%201%0A%20%20%20%20%20%20%20%20%5B0%2C%20%20%20%20%200%2C%20%20%20%20%20%200%5D%2C%20%20%20%20%20%23%20point%202%0A%20%20%20%20%20%20%20%20%5B0%2C%20%20%20%20%202632%2C%20%20%200%20%20%20%5D%2C%20%20%23%20point%203%0A%20%20%20%20%20%20%20%20%5B4500%2C%20%200%2C%20%20%20%20%20%202550%5D%2C%20%20%23%20point%204%0A%20%20%20%20%20%20%20%20%5B5000%2C%20%200%2C%20%20%20%20%20%200%20%20%20%5D%2C%20%20%23%20point%205%0A%20%20%20%20%20%20%20%20%5B5660%2C%20%202620%2C%20%20%200%20%20%20%5D%20%20%20%23%20point%206%0A%20%20%20%20%5D%0A%0A%20%20%20%20%23%20Define%20pixel%20coordinates%20of%20respective%20points%20seen%20by%20two%20or%20more%20cameras.%0A%20%20%20%20cameras%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%23%20Camera%201%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1810%2C%20885%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1353%2C%20786%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1362%2C%20301%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B455%2C%201010%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B329%2C%20832%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B183%2C%20180%5D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%23%20Camera%202%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1734%2C%20952%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1528%2C%20768%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1546%2C%20135%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B115%2C%20834%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B459%2C%20719%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B358%2C%20202%5D%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%5D%0A%0A%20%20%20%20%23%20Calibrate%20cameras%0A%20%20%20%20n_dims%20%3D%203%0A%20%20%20%20L1%2C%20err%20%3D%20dlt_calibrate(n_dims%2C%20world_positions%2C%20cameras%5B0%5D)%0A%20%20%20%20L2%2C%20err%20%3D%20dlt_calibrate(n_dims%2C%20world_positions%2C%20cameras%5B1%5D)%0A%20%20%20%20camera_calibration%20%3D%20%5BL1%2C%20L2%5D%0A%0A%20%20%20%20%23%20Find%20world%20coordinates%20for%20%60query_point%60%20visible%20in%20both%20cameras%0A%20%20%20%20query_point%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%5B1810%2C%20885%5D%2C%20%23%20cam%201%0A%20%20%20%20%20%20%20%20%5B1734%2C%20952%5D%20%20%23%20cam%202%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20dlt_reconstruct(n_dims%2C%20len(cameras)%2C%20camera_calibration%2C%20query_point)%0A%20%20%20%20%23%20coordinates%20in%20real%20world%3A%20%5B-1.31704156e-01%2C%20%208.71539661e-01%2C%20%202.54975288e%2B03%5D%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20__author__%20%3D%20'Marcos%20Duarte%20%3Cduartexyz%40gmail.com%3E'%0A%20%20%20%20__version__%20%3D%20'dlt.py%20v.0.1.0%202023%2F01%2F16'%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20def%20dlt_calibrate_1(n_dims%2C%20xyz%2C%20uv)%3A%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20Camera%20calibration%20by%20DLT%20with%20known%20object%20points%20and%20image%20points%0A%20%20%20%20%20%20%20%20This%20code%20performs%202D%20or%203D%20DLT%20camera%20calibration%20with%20any%20number%20of%0A%20%20%20%20%20%20%20%20%20%20%20%20views%20(cameras).%0A%20%20%20%20%20%20%20%20For%203D%20DLT%2C%20at%20least%20two%20views%20(cameras)%20are%20necessary.%0A%20%20%20%20%20%20%20%20Inputs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20n_dims%20is%20the%20number%20of%20dimensions%20of%20the%20object%20space%3A%203%20for%203D%20DLT%0A%20%20%20%20%20%20%20%20%20%20%20%20and%202%20for%202D%20DLT.%0A%20%20%20%20%20%20%20%20%20%20%20%20xyz%20are%20the%20coordinates%20in%20the%20object%203D%20or%202D%20space%20of%20the%0A%20%20%20%20%20%20%20%20%20%20%20%20calibration%20points.%0A%20%20%20%20%20%20%20%20%20%20%20%20uv%20are%20the%20coordinates%20in%20the%20image%202D%20space%20of%20these%20calibration%0A%20%20%20%20%20%20%20%20%20%20%20%20points.%0A%20%20%20%20%20%20%20%20%20%20%20%20The%20coordinates%20(x%2Cy%2Cz%20and%20u%2Cv)%20are%20given%20as%20columns%20and%20the%20different%0A%20%20%20%20%20%20%20%20%20%20%20%20points%20as%20rows.%0A%20%20%20%20%20%20%20%20%20%20%20%20For%20the%202D%20DLT%20(object%20planar%20space)%2C%20only%20the%20first%202%20columns%0A%20%20%20%20%20%20%20%20%20%20%20%20(x%20and%20y)%20are%20used.%0A%20%20%20%20%20%20%20%20%20%20%20%20There%20must%20be%20at%20least%206%20calibration%20points%20for%20the%203D%20DLT%20and%204%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20the%202D%20DLT.%0A%20%20%20%20%20%20%20%20Outputs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20L%3A%20array%20of%20the%208%20or%2011%20parameters%20of%20the%20calibration%20matrix.%0A%20%20%20%20%20%20%20%20%20%20%20%20err%3A%20error%20of%20the%20DLT%20(mean%20residual%20of%20the%20DLT%20transformation%20in%20units%0A%20%20%20%20%20%20%20%20%20%20%20%20of%20camera%20coordinates).%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20xyz%20%3D%20np.asarray(xyz)%0A%20%20%20%20%20%20%20%20uv%20%3D%20np.asarray(uv)%0A%20%20%20%20%20%20%20%20n_points%20%3D%20xyz.shape%5B0%5D%0A%20%20%20%20%20%20%20%20if%20uv.shape%5B0%5D%20!%3D%20n_points%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('xyz%20(%25d%20points)%20and%20uv%20(%25d%20points)%20have%20different%20number%20of%20points.'%20%25%20(n_points%2C%20uv.shape%5B0%5D))%0A%20%20%20%20%20%20%20%20if%20n_dims%20%3D%3D%202%20and%20xyz.shape%5B1%5D%20!%3D%202%20or%20(n_dims%20%3D%3D%203%20and%20xyz.shape%5B1%5D%20!%3D%203)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('Incorrect%20number%20of%20coordinates%20(%25d)%20for%20%25dD%20DLT%20(it%20should%20be%20%25d).'%20%25%20(xyz.shape%5B1%5D%2C%20n_dims%2C%20n_dims))%0A%20%20%20%20%20%20%20%20if%20n_dims%20%3D%3D%203%20and%20n_points%20%3C%206%20or%20(n_dims%20%3D%3D%202%20and%20n_points%20%3C%204)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('%25dD%20DLT%20requires%20at%20least%20%25d%20calibration%20points.%20Only%20%25d%20points%20were%20entered.'%20%25%20(n_dims%2C%202%20*%20n_dims%2C%20n_points))%0A%20%20%20%20%20%20%20%20(Txyz%2C%20xyzn)%20%3D%20normalize(n_dims%2C%20xyz)%0A%20%20%20%20%20%20%20%20(Tuv%2C%20uvn)%20%3D%20normalize(2%2C%20uv)%0A%20%20%20%20%20%20%20%20A%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20if%20n_dims%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20i%20in%20range(n_points)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(x%2C%20y)%20%3D%20(xyzn%5Bi%2C%200%5D%2C%20xyzn%5Bi%2C%201%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(u%2C%20v)%20%3D%20(uvn%5Bi%2C%200%5D%2C%20uvn%5Bi%2C%201%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20A.append(%5Bx%2C%20y%2C%201%2C%200%2C%200%2C%200%2C%20-u%20*%20x%2C%20-u%20*%20y%2C%20-u%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20A.append(%5B0%2C%200%2C%200%2C%20x%2C%20y%2C%201%2C%20-v%20*%20x%2C%20-v%20*%20y%2C%20-v%5D)%0A%20%20%20%20%20%20%20%20elif%20n_dims%20%3D%3D%203%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20i%20in%20range(n_points)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(x%2C%20y%2C%20z)%20%3D%20(xyzn%5Bi%2C%200%5D%2C%20xyzn%5Bi%2C%201%5D%2C%20xyzn%5Bi%2C%202%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(u%2C%20v)%20%3D%20(uvn%5Bi%2C%200%5D%2C%20uvn%5Bi%2C%201%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20A.append(%5Bx%2C%20y%2C%20z%2C%201%2C%200%2C%200%2C%200%2C%200%2C%20-u%20*%20x%2C%20-u%20*%20y%2C%20-u%20*%20z%2C%20-u%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20A.append(%5B0%2C%200%2C%200%2C%200%2C%20x%2C%20y%2C%20z%2C%201%2C%20-v%20*%20x%2C%20-v%20*%20y%2C%20-v%20*%20z%2C%20-v%5D)%0A%20%20%20%20%20%20%20%20A%20%3D%20np.asarray(A)%0A%20%20%20%20%20%20%20%20(U%2C%20S%2C%20Vh)%20%3D%20np.linalg.svd(A)%0A%20%20%20%20%20%20%20%20L%20%3D%20Vh%5B-1%2C%20%3A%5D%20%2F%20Vh%5B-1%2C%20-1%5D%0A%20%20%20%20%20%20%20%20H%20%3D%20L.reshape(3%2C%20n_dims%20%2B%201)%0A%20%20%20%20%20%20%20%20H%20%3D%20np.dot(np.dot(np.linalg.pinv(Tuv)%2C%20H)%2C%20Txyz)%0A%20%20%20%20%20%20%20%20H%20%3D%20H%20%2F%20H%5B-1%2C%20-1%5D%0A%20%20%20%20%20%20%20%20L%20%3D%20H.flatten()%0A%20%20%20%20%20%20%20%20uv2%20%3D%20np.dot(H%2C%20np.concatenate((xyz.T%2C%20np.ones((1%2C%20xyz.shape%5B0%5D)))))%0A%20%20%20%20%20%20%20%20uv2%20%3D%20uv2%20%2F%20uv2%5B2%2C%20%3A%5D%0A%20%20%20%20%20%20%20%20err%20%3D%20np.sqrt(np.mean(np.sum((uv2%5B0%3A2%2C%20%3A%5D.T%20-%20uv)%20**%202%2C%201)))%0A%20%20%20%20%20%20%20%20return%20(L%2C%20err)%0A%0A%20%20%20%20def%20dlt_reconstruct_1(n_dims%2C%20n_cams%2C%20Ls%2C%20uvs)%3A%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20Reconstruction%20of%20object%20point%20from%20image%20point(s)%20based%20on%20the%20DLT%20parameters.%0A%20%20%20%20%20%20%20%20This%20code%20performs%202D%20or%203D%20DLT%20point%20reconstruction%20with%20any%20number%20of%0A%20%20%20%20%20%20%20%20%20%20%20%20views%20(cameras).%0A%20%20%20%20%20%20%20%20For%203D%20DLT%2C%20at%20least%20two%20views%20(cameras)%20are%20necessary.%0A%20%20%20%20%20%20%20%20Inputs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20n_dims%20is%20the%20number%20of%20dimensions%20of%20the%20object%20space%3A%203%20for%203D%20DLT%0A%20%20%20%20%20%20%20%20%20%20%20%20and%202%20for%202D%20DLT.%0A%20%20%20%20%20%20%20%20%20%20%20%20n_cams%20is%20the%20number%20of%20cameras%20(views)%20used.%0A%20%20%20%20%20%20%20%20%20%20%20%20Ls%20(array%20type)%20are%20the%20camera%20calibration%20parameters%20of%20each%20camera%0A%20%20%20%20%20%20%20%20%20%20%20%20(is%20the%20output%20of%20DLTcalib%20function).%20The%20Ls%20parameters%20are%20given%0A%20%20%20%20%20%20%20%20%20%20%20%20as%20columns%20and%20the%20Ls%20for%20different%20cameras%20as%20rows.%0A%20%20%20%20%20%20%20%20%20%20%20%20uvs%20are%20the%20coordinates%20of%20the%20point%20in%20the%20image%202D%20space%20of%20each%20camera.%0A%20%20%20%20%20%20%20%20%20%20%20%20The%20coordinates%20of%20the%20point%20are%20given%20as%20columns%20and%20the%20different%0A%20%20%20%20%20%20%20%20%20%20%20%20views%20as%20rows.%0A%20%20%20%20%20%20%20%20Outputs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20xyz%3A%20point%20coordinates%20in%20space.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20Ls%20%3D%20np.asarray(Ls)%0A%20%20%20%20%20%20%20%20if%20Ls.ndim%20%3D%3D%201%20and%20n_cams%20!%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('Number%20of%20views%20(%25d)%20and%20number%20of%20sets%20of%20camera%20calibration%20parameters%20(1)%20are%20different.'%20%25%20n_cams)%0A%20%20%20%20%20%20%20%20if%20Ls.ndim%20%3E%201%20and%20n_cams%20!%3D%20Ls.shape%5B0%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('Number%20of%20views%20(%25d)%20and%20number%20of%20sets%20of%20camera%20calibration%20parameters%20(%25d)%20are%20different.'%20%25%20(n_cams%2C%20Ls.shape%5B0%5D))%0A%20%20%20%20%20%20%20%20if%20n_dims%20%3D%3D%203%20and%20Ls.ndim%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('At%20least%20two%20sets%20of%20camera%20calibration%20parametersd%20are%20neede%20for%203D%20point%20reconstruction.')%0A%20%20%20%20%20%20%20%20if%20n_cams%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20Hinv%20%3D%20np.linalg.inv(Ls.reshape(3%2C%203))%0A%20%20%20%20%20%20%20%20%20%20%20%20xyz%20%3D%20np.dot(Hinv%2C%20%5Buvs%5B0%5D%2C%20uvs%5B1%5D%2C%201%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20xyz%20%3D%20xyz%5B0%3A2%5D%20%2F%20xyz%5B2%5D%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20M%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20i%20in%20range(n_cams)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20L%20%3D%20Ls%5Bi%2C%20%3A%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(u%2C%20v)%20%3D%20(uvs%5Bi%5D%5B0%5D%2C%20uvs%5Bi%5D%5B1%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20n_dims%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20M.append(%5BL%5B0%5D%20-%20u%20*%20L%5B6%5D%2C%20L%5B1%5D%20-%20u%20*%20L%5B7%5D%2C%20L%5B2%5D%20-%20u%20*%20L%5B8%5D%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20M.append(%5BL%5B3%5D%20-%20v%20*%20L%5B6%5D%2C%20L%5B4%5D%20-%20v%20*%20L%5B7%5D%2C%20L%5B5%5D%20-%20v%20*%20L%5B8%5D%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20elif%20n_dims%20%3D%3D%203%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20M.append(%5BL%5B0%5D%20-%20u%20*%20L%5B8%5D%2C%20L%5B1%5D%20-%20u%20*%20L%5B9%5D%2C%20L%5B2%5D%20-%20u%20*%20L%5B10%5D%2C%20L%5B3%5D%20-%20u%20*%20L%5B11%5D%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20M.append(%5BL%5B4%5D%20-%20v%20*%20L%5B8%5D%2C%20L%5B5%5D%20-%20v%20*%20L%5B9%5D%2C%20L%5B6%5D%20-%20v%20*%20L%5B10%5D%2C%20L%5B7%5D%20-%20v%20*%20L%5B11%5D%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20(U%2C%20S%2C%20Vh)%20%3D%20np.linalg.svd(np.asarray(M))%0A%20%20%20%20%20%20%20%20%20%20%20%20xyz%20%3D%20Vh%5B-1%2C%200%3A-1%5D%20%2F%20Vh%5B-1%2C%20-1%5D%0A%20%20%20%20%20%20%20%20return%20xyz%0A%0A%20%20%20%20def%20normalize(n_dims%2C%20x)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Normalization%20of%20coordinates%20(centroid%20to%20the%20origin%20and%20mean%20distance%20of%20sqrt(2%20or%203)).%0A%20%20%20%20%20%20%20%20Inputs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20n_dims%3A%20number%20of%20dimensions%20(2%20for%202D%3B%203%20for%203D)%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3A%20the%20data%20to%20be%20normalized%20(directions%20at%20different%20columns%20and%20points%20at%20rows)%0A%20%20%20%20%20%20%20%20Outputs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20Tr%3A%20the%20transformation%20matrix%20(translation%20plus%20scaling)%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3A%20the%20transformed%20data%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20x%20%3D%20np.asarray(x)%0A%20%20%20%20%20%20%20%20(m%2C%20s)%20%3D%20(np.mean(x%2C%200)%2C%20np.std(x))%0A%20%20%20%20%20%20%20%20if%20n_dims%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20Tr%20%3D%20np.array(%5B%5Bs%2C%200%2C%20m%5B0%5D%5D%2C%20%5B0%2C%20s%2C%20m%5B1%5D%5D%2C%20%5B0%2C%200%2C%201%5D%5D)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20Tr%20%3D%20np.array(%5B%5Bs%2C%200%2C%200%2C%20m%5B0%5D%5D%2C%20%5B0%2C%20s%2C%200%2C%20m%5B1%5D%5D%2C%20%5B0%2C%200%2C%20s%2C%20m%5B2%5D%5D%2C%20%5B0%2C%200%2C%200%2C%201%5D%5D)%0A%20%20%20%20%20%20%20%20Tr%20%3D%20np.linalg.inv(Tr)%0A%20%20%20%20%20%20%20%20x%20%3D%20np.dot(Tr%2C%20np.concatenate((x.T%2C%20np.ones((1%2C%20x.shape%5B0%5D)))))%0A%20%20%20%20%20%20%20%20x%20%3D%20x%5B0%3An_dims%2C%20%3A%5D.T%0A%20%20%20%20%20%20%20%20return%20(Tr%2C%20x)%0A%0A%20%20%20%20return%20dlt_calibrate_1%2C%20dlt_reconstruct_1%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Checkpoint%20questions%0A%0A%20%20%20%201.%20What%20is%20lost%20by%20projecting%20a%203D%20point%20into%20one%20camera%3F%0A%20%20%20%202.%20Can%20moving%20a%20calibrated%20camera%20leave%20its%20old%20matrix%20valid%3F%0A%20%20%20%203.%20Is%20a%20low%20calibration%20residual%20an%20independent%20validation%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Checkpoint%20answers%0A%0A%20%20%20%201.%20Depth%20along%20the%20viewing%20ray.%202.%20No%3B%20its%20extrinsic%20parameters%20change.%203.%20No%3B%20test%20known%20points%20held%20out%20from%20fitting%20and%20assess%20reconstruction%20across%20the%20measurement%20volume.%0A%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Problems%0A%0A%20%20%20%201.%20For%20%24P%3D%5B%5B1000%2C0%2C0%2C0%5D%2C%5B0%2C1000%2C0%2C0%5D%2C%5B0%2C0%2C1%2C0%5D%5D%24%2C%20give%20the%20image%20of%20%24(2%2C1%2C10)%24%20and%20%24(4%2C2%2C20)%24.%0A%20%20%20%202.%20A%20planar%20calibration%20uses%20four%20collinear%20points.%20Is%20the%20homography%20unique%3F%0A%20%20%20%203.%20Two%20cameras%20give%20nearly%20parallel%20viewing%20rays.%20What%20happens%20to%20depth%20uncertainty%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Final%20answers%20to%20the%20problems%0A%0A%20%20%20%201.%20Both%20project%20to%20%24(200%2C100)%24%20pixels.%202.%20No.%203.%20Depth%20uncertainty%20grows%20greatly%3B%20a%20small%20pixel%20error%20can%20produce%20a%20large%20depth%20error.%0A%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Go%20deeper%0A%0A%20%20%20%20Read%20%5BSVDalgorithm%5D(https%3A%2F%2Fmolab.marimo.io%2Fgithub%2FBMClab%2FBMC%2Fblob%2Fmaster%2Fnotebooks%2Fsvd_algorithm.py)%20for%20SVD%20and%20geometric%20conditioning.%0A%0A%20%20%20%20%23%23%23%20Video%20lectures%20on%20the%20Internet%0A%0A%20%20%20%20%5BLynch%20and%20Park%3A%20rotation%20matrices%5D(https%3A%2F%2Fmodernrobotics.northwestern.edu%2Fnu-gm-book-resource%2F3-2-1-rotation-matrices-part-1-of-2%2F)%20explains%20rigid%20geometry%20and%20coordinate%20changes%3B%20compare%20those%20distance-preserving%20transformations%20with%20the%20fitted%20mappings%20in%20this%20guide.%0A%0A%20%20%20%20%23%23%20References%0A%0A%20%20%20%20-%20%5BOpenCV%20camera%20calibration%20documentation%5D(https%3A%2F%2Fdocs.opencv.org%2F4.x%2Fd9%2Fd0c%2Fgroup__calib3d.html)%2C%20homogeneous%20camera%20model%20and%20distortion.%0A%0A%20%20%20%20-%20%5BThe%20dltx%20project%5D(https%3A%2F%2Fgithub.com%2Fjoonaojapalo%2Fdltx)%2C%20source%20of%20the%20attributed%20implementation%20and%20example.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
da5fd2179410725e8576ed199f307630