From 39d606552158de83d20328754ebf3f4f13ce7790 Mon Sep 17 00:00:00 2001 From: fly6516 Date: Fri, 23 May 2025 11:43:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(camera):=20=E6=B7=BB=E5=8A=A0=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=E6=A0=87=E5=AE=9A=E4=B8=8E=E8=BF=90=E5=8A=A8=E4=BC=B0?= =?UTF-8?q?=E8=AE=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 camera_calibration.py 文件,实现相机标定功能 - 新增 motion_estimation.py 文件,实现运动估计功能- 编写实验报告,总结相机标定与运动估计的原理和实验结果 --- camera_calibration.py | 56 +++++++++++++++++++++++++++++++++ images/calib_1.jpg | Bin 0 -> 27835 bytes images/left.jpg | Bin 0 -> 13319 bytes images/right.jpg | Bin 0 -> 20992 bytes motion_estimation.py | 55 ++++++++++++++++++++++++++++++++ 实验报告_相机标定与运动估计.md | 43 +++++++++++++++++++++++++ 6 files changed, 154 insertions(+) create mode 100644 camera_calibration.py create mode 100644 images/calib_1.jpg create mode 100644 images/left.jpg create mode 100644 images/right.jpg create mode 100644 motion_estimation.py create mode 100644 实验报告_相机标定与运动估计.md diff --git a/camera_calibration.py b/camera_calibration.py new file mode 100644 index 0000000..2ad03ba --- /dev/null +++ b/camera_calibration.py @@ -0,0 +1,56 @@ +import cv2 +import numpy as np +import glob + +# 棋盘格尺寸:内角点数量(宽度,高度) +chessboard_size = (9, 6) + +# 创建棋盘格世界坐标系下的三维点阵 +# 生成形如(0,0,0), (1,0,0)...(8,5,0)的三维坐标 +objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32) +objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) + +# 存储对象点和图像点的列表 +objpoints = [] # 世界坐标系中的3D点 +imgpoints = [] # 图像坐标系中的2D点 + +# 加载所有棋盘格图像路径 +images = glob.glob('images/*.jpg') + +for fname in images: + img = cv2.imread(fname) + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + + # 寻找棋盘格角点 + ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) + + if ret: + objpoints.append(objp) + imgpoints.append(corners) + + # 绘制并显示检测到的角点 + cv2.drawChessboardCorners(img, chessboard_size, corners, ret) + cv2.imshow('Corners', img) + cv2.waitKey(0) # 修改此处:改为等待用户按键关闭窗口 + +# 销毁所有OpenCV创建的窗口 +cv2.destroyAllWindows() + +if len(objpoints) > 0: + # 执行相机标定,获取相机矩阵、畸变系数等参数 + ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) + + # 输出相机矩阵和畸变系数 + print("相机矩阵:\n", mtx) + print("畸变系数:\n", dist) + + # 计算重投影误差 + mean_error = 0 + for i in range(len(objpoints)): + imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) + error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2) + mean_error += error + + print("平均重投影误差: ", mean_error / len(objpoints)) +else: + print("未找到有效的棋盘格图像。") \ No newline at end of file diff --git a/images/calib_1.jpg b/images/calib_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f9112c3a45c8191c969c20649aafb528803a6f6 GIT binary patch literal 27835 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 VJu)40-bwyj{OGA85r@t@{tp6o+Lr(T literal 0 HcmV?d00001 diff --git a/images/left.jpg b/images/left.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9e0db2df68a76c76655b50e55e83a25ae78a5e50 GIT binary patch literal 13319 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 E8^+s#!2kdN literal 0 HcmV?d00001 diff --git a/images/right.jpg b/images/right.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d5fdaeedd8ed32ae859911e45b60f90bc681111 GIT binary patch literal 20992 zcmeIac{o)6|2IAoLM7QLlk9uh%QBUa#Dwfy_MPlxn4-vD)*>b$S*K**CVL3k8T&{I zlNmG)X8D~ypWpSnulxJ`UBB!1y|4SeultYpah;>CIcLu6xj&ze=ktX&LtBQNxvi_O z3!$TfKI?2j%^6!8Ce#yTdJ;p#!&%naO$n>vU{!16yX9)WVy5(b!=;s5=8LpPn9EGy}L|@a`z^bI5UahOwh=DJ5kURkbTuwQuU^>fO@6 zZFv$AtuzRG=DR9y0|^nF=* z&8OPB`i91)=FYC}p5DGM{R3m;6O&WZGqczg-0JtWAL~DVZ4h^M_x_OffrG=pbkRZR z|4kNn{ePv49i;2nUl}m{rHk%Z7D{%y{;?F_U8e$3=z5Cpd4sDE!#LEUaik z;BpEaW#JZ4S`j7wCGB67{r@8@=6{H?|A(;uMi&-xlAaC}9z8n*2B9Kb^*k zH4BSuF@DJ8jNgdvScccWMcueHG&j7fd$xfoJRogor(a_F-J7>q6aC>z$p-f#PyM>! zNqq3+I1G25203h@LCAeH2xUo+tPOs<1(F7NNrTWJEt@~suydq(N`;2%kvYPUupN)| zL_ag^}_b{4)*4ZYWuP{+$lTfQS=Aio+v9)uB%|MF;V+N ze-5yBAE!YCXprR?8l)B(BkM95%}l=jjT~~^eDveT0@zmGft%;;8r}4k&&GEvwj;j1 zR%3nMLghl&!5U;e(_4;zA=iWUvu zUfxgL8%e;NY=s9Ec{eM6K^aZ>^7RHkw&eb4hCBYbDD^rXW%R(M=I zmYkg}#(bf;G_pthw2jKze&g$$GJ);rf+8Z#JPC0%Cbyp_14 zuax|;=bXPt^0VYFk~+x)v>#E7$M!QQtE`6Akui0)9SZp3BA4VGfSa{!ObyT4dssU- z4#HF&d~1_!i>qYd=PripWmaZjrHnhYF}(9RR6gj<9F%lN@nY!}5jS1wO=GOt;%@s=;@N+qVJ&24sAy}g&KC94SaZqU) z%0z>77-5!C(dwYAouX&8Bq+~Ykwm60swC>>j$iFU(6#o2_DRPF1-_r==Va2vP=QWT zBi@(iTe3z=;%>QT$8YHzF_Q05np*YHzqBAz!9!w$UAgY4_g>A#PkI{^iZLz?Ctd~p z=;vU3a3Y0$=J)*<`m0nKqI+U%B(4hHXMdHbQds5vaH>$5`l)hb8XXjZ3{iX~+L&v_ z9N`+~78)x0>SemV^5GR4gmIe&8FB!f73fX^%?RzH?gweC1S5IH&$Z>_ch`LFd=1L&?DL#M}u&>wF<0EsjCfIoBfjVk~4TE_wd8Jg?e8}6?6$ccq)EfHAMr8 zgT)tIo@}LCJ*B?&usyzPq;w;@AW;9iZI`f~l-~`r4;x)lx75Cf1X*SMLe|HV3&eZU zjwBy$Q(udtmC#j#0gAn@69F9hw;v?u*SF}mL_mWwoi^O~jG$b`qEgSFp&8ypf z*X-4qC{aB=s@X-lNQnhietuDSdJhHhzUr3Yx-z6VGNEi|a>Lo?m5D=*&67J#yDkZ_ zYR7e-ZG~OBRZNlxMAyk@#z`MRQN2a@067Hz&$-j_WGJXc1q0!&j+HT{{2 zc+5^I!Lt#M2VoYMhT45doSqE8*~F06J9_Gps&WFsI2rwz;rK$S;KV& zv@^iD1Nk%1n<`z~z7wKpZlIpD7z0ORaUO;c`lOzci z@v!Ab7=oWlA@P$%4Rw%M>%g`~Tzck9wtC}r`Jg~yvT8XAJ}&QLZl22~$F~aH^3?)C4L}iXx#iXL@jW9>B=x?KofW-~K3b(X{PEILW#KPatYN!Uz&0Ef% z89CV?Gc_%d;kpc$X_DX3ldl2oISRR)hB*lmRM0L(K;e~-q=9{S3m{K?x{m79;-1vF zelmAGuKIh*#BQaq0;Qv3+_Ojqh8Ti?YUH&%=7n z$HTpLBJd?yqrdqCXPtMbn{D$dqrdOplSwsNYHwcv83iGqCo;r$FC9lj@z;NfdbjaV zDfi?DJI!uV^PTLSw(fxLom-=GmAD^a+{8*Rd)9;x+cH%SFX2gwcUpQxUpQMI)?ZA_ zV%1$F`+qHw-oPd=8AK*dhapoYR$p&Q5lbFSIZaPqzQ;+JdYW4%u-j|eUiE%xui^Jt z%34Hpgs~3SVZ@Qp9&}5G206Y4^c)4uY#xH9Qn#R}J*EVm*D9&f4p>`Q)HvJv;D&Q@ zh2s?a<%MREMm=UBA^zztIQY~)(I0>1$Y>LKOd|qq6Yj^xVEa`gfZt1H$KicU(D4t} zy?js5KT_fz@blL2C2=QSL26SWKlvTV95z&D$Dq}tpIUvm?%{4%+mZx`dH<4vVS~~k*N0LT?8f1Ug`aKPED6#C+W56kF4$T=*>wjdyjUz zbFKgrYd{zukYVwR2C2DxrYOEdRGZm&yscbEE21IFbl(9pHo)Zdsyho=AIU3 z$NDQI+X~^J&DDmT7aL>{HjAkp8y)B$m>;tH^v9kVE;qP zz&t5We;B;u0~oGWFas`S-W-x9!Es?^?p2a0U`&+m zhOr`a2s8+e6B{2_H`pe1=q)SNQ<&}@QNZIdXfMqv^CafpIp+((Xah%#;kl{SDnxc42m~l$rin6E;WqM%0_rH zoXzlV=?QUFD^YKWG9>e?I@$n*>g#RSSV`q7N$Md~>BN^9<%S3fN$g-Ro7BABDhXMf zo+npR(vZu!$XX;`d9{r(%3;N?>1{Ya?#J-D6;Y*>XNG-m_WJXFxA8(%Iie7It^P&E zbYZax-^o8Y#I-o3#W67XtdMkUhFTfkpVOSG^mhBVTLAk93 zTzoN2U4jxUmd;ZLXppmYuo$hAlsvinQ@&Mib4MJAS>J37G8HfFE;rOW`S~u22)XRy zT%XspdVQ-ohXRz3;SNOs*QPxHPW&YJ<;yX`g!9*)zy``>ZLcVCw2b=BlczQJ9%h$uzbX!Qwgf1Z zGaJztJ*|Z63l@9r>_kFy%{|PV%q_B2PcS0t_E3QIbS!eYTu=iv@6>SdKEY$78ji)( z0YL^rqzy29i|kxt{VR9zQ*e$rUcs^}k~H`;-AbwPu5HIN_lDeCFW7SN2P}M_)jg0Ior#UZO^r zJv4CxjCFVCta?Y&rb zUk<7E#46)Q^4^9UoiLyM1LLy~9xb{*Y_Rrw2(K zR!`5;AQkE25*6v&eLb(W^VeHVsiohQ+n$=Sd0Jz-e|5n_FH_xzn4&#qmEF)G9ew94 zx@`@5Q5!rbaavVYrliJXz3yM8SOE8)*b2RU$j2 z>U>pf3}%#O+ePid)y-&-C)w(j_?}g(w!u65H%70e@0C$z9#k7`%dd4&N-_7*fLIz{ zk0}WegoDo{PU`@u)wWO?#F8lAZ6|;eY_-8RWDEu<57j-H4z$shOusf0lFhzLcZT7H z3&^%)?};Lo50Us&w^Kpze_7U1-U72lpn9m8Q%UrM9Dwb z+*>7}!=Yt$k=gfz<>Q$=eKV746pj##!j?U}QRy zE&3#NSnD*URh9~&PNR4b*9#E}qtO>f3c=(rn)@5~52^rbWNDni%c@s%Zum!^=+tji z4u4oskO9SXZSf){7rC5*`Gm=!K~857p$DgTE-BUCO^j0w1;`_?x|z?4LM2Xa;1K7# z&C9nXwNKCeUa&UAzgz#QrGoQz);QMVB&|LiOsMhK3EjNwJL`$@W&4J~>QR|NgE<~N zEmQeNR)8cwM!vq9#_==zurH<6S-u;2);GyTbSic7@@D=blR##r$7Hj^aVo3 zMu61@_tpH=%^`8beUY&dmS@EYYZf=wgl5J%c+c|4Xqf}5C1mL-s+0#mycetzHy(;V zsa96YaF`5^WDf}P^?`r=@`TFpDDY7>`@p@MG)NWJKdB1owFF!&D8wx#JaiqJUtO_( zI}ML4A5@xFJ-qhHsV&_OiWu%heo)Dgq03a_9C}MZQzjArKj4(@#$x5$D_f%`@Df7aO z*V_E>)7yq^xf4*NvjC_i%;MzBMinc0sD`LC>REq458-jxyHJ3fB@gX$M8KjE&VE~} zcCF!kc!nbtWCw4Ep?fb?3@BMeo$zcIZ)%#TZq*BMCCa%?RQb;qN5-dqwQW>ol?=Ra z1~z;w!f>B0>pyBGLi5N2*^fh5g2`o0H4XBs^C1~6w0vif9p~nrBeTT8XPhFoQHJp} zzI`S%ucbL<3mxK83*%TxJEe%QNWL;`cJ7FWd1d8>Nfm#JS$PRdpmCYFcnIf#bF@pk zwT<>6g3_wNx(o;8bI1Z1o?Zuf<>5A*8{syv*?H#X_ zzSJSwo!&NYUcECTkRklayYlz>J(=ITf>t(HvJq}o#0htWRDPP?K;-ekL zx+f^vTe}b00EI5_&8^}DZyXz$)4TVoTp@P@Zs-P_FZB+0Mw5P9vSA_Gy zRX6M`I;Ks%qggFiRl`jC{RIYn-l~Th%QUFeD5*aPtsCB!f5-qWa3FZ6kxLzx-6>y} z4wJnmkE}pJngJ9L<~6LPWN+6l9W+qnd#qi*gP8F|(7oE`R0{>z>bBx9eNmq=~m{F4xZn?ZBIO)v9o1uT$03i&SJ!l1$f?Tdeab)23JDzD66Jl5N z;*35P{VEU{!}|s24OY2Y%U&J8O_7cE2|8?~_f{EdO=Cr2F9g_Ozd)I9_hQbp!jEii z!~KqWa=!|45~kyPs+2ISZIg{PId?PrgF?!E>l;I}3M6Il#{R;o-a)PpzDdL#lr)mU zS5rPTxyLIjww}X=l%bud)5>PQG2)!_`J^>(i=sm|cCt=~3zfqRC&Qpya52-2skUiT zZ$8>2#?M!?iGT7Z`O^w~YYvP-XbQTHoghGE(OE^)+b%3_UJU@Ez_P~Yo~zc+hH)1TRi#4XO_vf4KhHA%S{@sMmqy@>W$T zxHN&@^R}vkGRklp51nXie)>YpW;T68;qzM4CRt6nPh6eMIAa%U-GxB5|YtFa2q0_QK zMju*4m+t7hH$KBAuyViRdgD~Rq%v*hwDnGp0zMTphU{oY)%0y?f~34B!0{iC&LOmk zOlf~kaU7kNhXVZ?I!;)zmJ)}&*WOcvQ(rX(TiWEXy!g@=+_Ob)R<>|3w-Z8kL}9)Y zHI!)(m$4BV#E3s7x+(gzL*4dc8pIn3sH(3ZKVuRO3sP3|O$P7fd~TN;4OwE1WvHu8 z3eGX-KDs06uc+;WJuT9m*V<{7>zb8ObOAS=9d4nmH6*s7W^9t-8)UeYEwzo;pS9bV zYiYUK=#W~H0Z7K-e0~&FNCk5i&)JS=9XM6*{m5HOS*&VlsgJ$~3RM*pO4^}nANrW* z5(s>HCRGI)jiUV!3mlyfZq$!dSW7-#ZBCEs)oI9#ARc(V_%c{?FH>65zmXgO@K%`LUtsIlP*uUY8LAR`TL5MReNFaB{hZt8lePT*X*@>8W{$hx0(i9pH*bvXA2>) zUIXgN!FM}p@gdBBPe{QRN19}nZ@)ui?dR-X$jK@%M1DbS1!}u{iRXG&{VpE=eKCDQ zEuC5Emuo^cTw>@@5fmmpfCoi63;nR&gPIMT!@=W!|6w~vhD|C}F;UN=PI{fSwBD$( zfz8OR^}J3l(3yz|dBI+w^3;xT&zg*3O|0m>2dfK`lT2kX3wg?7w#sl@j+9J;L@-HO zPd6K?Z&u~3s%iN8pSeVX%tc`M`{c5GJy+g4IT{+rVr0CcNqL!gKkpu;?dtlp-H;<& zWCy#Jd^i**{{*3a#Qzga4HB4A5ZAer+)E67{p5mMnh-DX)X_jeHFBA&XF~pJ9PcrS z7u5TGzu15)^wblEN2fuKNYEhe(5Em?n45pH;03Ufh_xUx^u_=2KN&t~S>J*oa;p3J zpZ*BV{&3*nI@Ff=RsxaUzoY}SE{si8wmx4{^F1R z)DvY(CN@1Al3Y}(x6jmv#|pP()Q8+;`S2bs2qM+>7$1rrDUQG=;mZ$7KJ^=(}7O85DgsIzuP&@r}TBD~;u75O+I$sqe>3tD9b0w>F0< ztDp7WyscNK;cNr<>en2p(COm5^bF+taMix1f{4^U!lHX(X;MYZT0r+$K&JP2hM$7p zslHsvUODXIhT*V+e-F|h35bq#EX{6{ltCW{<`IwWB__xQL8TyXN)tlXCS`|F?`P*< z1(fOV_6z*T9hR7qJbzP1|8%E*-pV!u0P9AcAv+fX^c{y`bIMUcrm^rbyvFymk)~Xo zRFV1bQfsrimX8$Eul>N-(I8G>d|Ro5Ex#B?KpQ86ha7BUyRM?1%pEzyXMG(bjx~@x z5I3*yI7Vq*my-SL$j1uyw-0}FiH(ojB)~-W2Pm~6S9v&{4q($SO$u5Uy z7SYRusjBRhsfQlu#QK>r4KDvy912_%91+T!3<=;1x!t~p-qsxpKJt{*y{%$wTP2dN z;YUZLSMLWb5+v6r^AYA|<_&G?ivhLyvYHFxYWg<@q_cWN(wjCh1QQG(Dh_felH^tg z^b;h>h7m!98=+I}qIs5+`0puOKe9u3jAGRKGYw_)8`&L0A-xKVE~U#O|0U)`w`&46 zU8vfn&ol@a0_YGhu~(60G>Dt+&mf&jYs_qAot4bR=DILh0r$Zp!(!a6u1q!Q-9q{u z|NlCF1_*uK8pEY@Kf+t5ipm^Lw?v|-colZg4V-?orL9GpI zuk&JNRhq25r}}q_quZ8;?1g&510MIRo2^;5xk|krTgna$jA_g8e(?^yIO-=Qq{C^k zgnG}wX?*Q}${C%F{O=3kXwT_i?qCr>gD4}ZYasmEZ?P7wg6#hYTGzZhMe`2X^cM#W zA{GQX)<)Rji(5b>=^Kd5b^{;5uBtp}CgV^3*pO@~MXg~+QV5^XXa(RjbL2jR^8$7Ky~Y5b!RqSwBg4+(MEDIn(&>%;RS-a#sv+ zra`hpNVB1AtS<>e=j6m#g4cB~XW9>`iHyT;4g`|9y*p+Qf^xa}Qkg=0IvXWChGM94 zO$?Rg%8?r2Ol1*05(E56ZIpZ;xe$5wUk~{ge_4m3ynU6YDjcN?3p$+zvQ@b&#at5v z4Qph(r3LgQr1zM}ywkW5mRX>JlueLbPpAdz+VtRrEGnu<|6x){h_}ySYZwoEx6yv0 zcypaz2!nC8aVc$h!zF^mCO-_8S!ckSmI zHLS>LdDL!RDZt6@c*gu%Y4+A^2%Tz<;Y`#V6qxHh?kNY8U6%0^j|tCiU~oIzrs?G< zMx7Aw9dG*+5aw;L0Jpcl8GU&r+cAl-owNyrDmnFSqrL(J)+qPsU^aLhQDb3@mwIy_2>$97jER%>5CWor zYZ}26Rn#LAqc57PT+=jnDN5yV_D{s(-RRNt-EOmm(i}3o2%e*dAQL%|U?oK`g=4)t zL6jWhDj%C0U9>z?YaoAWQ}EJct5xZ&^)J;MB%GDKhf5ybpY!g5wlwdBti*J7yWWAN z%b-E*#?l}k#KBgCR6ZY?Ts%cj?E!n}MpK#wBpA3p9CdVwU@_!wL)ZqxFES3xSh#HC z;fGLlUQUu8v_cCtyV*2}7_`jAy%6@0Bt?CvUx zERLy#rqzB4#z20yL-l>cV|4a^@NGMN7$+2P*+1Jglb6L;_bf)x z*&e}!D?w~u-haTm@gTOsZI$Ii@;zs1vB?QlPn}(dyoGdIzIw4}K43Bdr!luMsK|f! z-KJIJc-4u{%gG0(nSNz0Dwz(N2W|bLf1qSu&<&}AUB*B-b$xRX<^nyq?T_CC!#!OY z^4G3C8npUY3k{)FC?IB(e{^jrdbWTU)pZtVW;=;_>VvPoKOr)K{o>6S{tc^t@#g3G z&rGjJ%M>0ws5FPi(IB71pGKdhj?*AuqT?|{-}^AGOuiSB$e)(bQ?(XjBbVo`j9-}G zo-_L{FO}D?-H-8hgy>)mc7Xmq4dLWvTO+%tz2g5kZ7Q4t*GI{00}a}U zV|pG&@B@MLNw5c&Lxb##g2OUc=uS9_8@5%li8*{w(7pmv4Bq?Srpf-ag8kGCSqo|# z_|e{)@H{btYWxF3dDw~kg=Okm`cFd?STrCVMi#I;3Pm7*{X*)L!w2yW8iWn#>Vk4; za20u3FFr2zx@!MaHU5v~-k_SFy=!Y@oI1MxHagr-SQP77ee->>NCWga2HFlGyHc{- z6@YjWg7StcxFN_z%y}9@?^^xSI+sqg_2tP*K7D z??oNL?xDXVlF^;WgY!fvC2oQS8G9Ekxr`)dBEXc*nPutFcH}?y6XQYX_P>LIL8f&u zP*t&jFe#15)}d*F!%Ap`6js)Y;!7e*FdueBZ)N3tzp1jbsLpfl<#Wd4_-HU#*nocO zE#)m$ggSn;v==pt{)}~NDh_Y(ohp1cvtaEx=9!bg>3KOo<74GwWE^TpyRl`k?K;a& zL^xtqZUxD|tC~BR!t3NQmUU(5eb0_AyZ5VE>Bixq7JHR8tX|5Kk)485hd0;Ru2!AX z)Nm6_E;B05yl^07bn43OQHuxpd7k#CReyLw6~M*IAbtITFn=;9$4VGJDd-K-%ah7R zq(}N&mY`8e&1MU&^{SwuXe&ugUmW`pbozknc&Ea_wE<)h7x1tWU;W7LCBkul&P$!V}mk1C8_hjGWhZaUEAU; zQiSh4o8DF`AL}+ru{JSDPWLPg9-ma2N>MKNpyn3Z$4Nc$HcrnJ$wtCd>JM?# zF4GUI>-=4#RQfos_WNYN_*JNQ&ghfCo3PUC$pd<8eiRZES2b)WANd%yuZY~ZTwyWm zKnTw1+Xh^>0eRI9`PB4Z7@zuYRAx^k)_jxgmGJCP#U^QA%jDoitVEpE$;g*-gqE5n zrd0<(xsPg!CMZ&W_)~P1z4k#WHEpOSdCSlvRSHNeJa;Y7nP7<+q_<#xW>IRQ@FXX^ zUuk+sF-dXo!>e{X8~VgFWvOqOA}zh1y#_z>VD_LkWC>m+h(DrA0%Ls+4P#1k`N*!& z@pzLFhQTEemRU9!I!PDowo7P zlEnZC?&44Pw%M8eeeUNCdl$!jFaCD>Tc5A5h{0OT>t~P5Z1KAefQUR^=snqulGLgm z;*s&IIVbjhM#tfk>_?p$eGHWWg*QapT+@d=Ozz-M{wKCZc|Ulmms(t4;hCbaZkIxH68ksE1@O|DsD`^5E-PxIlQ za!pwYUH$RqHvEXRe8f@R!}rAqusO?Kf$T6v{(MXY(Hg+O8%1ucULpm9D)t8Hj|L=i zdhMX3tH3lNX_=a{lExcVbYyhYiDj%{AUn7;WFNvL*C*bk1j*JqHt5cpe7^s@YYoK= zDo6#CVC&BgRNNtuJ{}2s9x{|r3s1F8wNxN(eG{BEN|~3o{aWAf$!JuUIh0*T4&$#uBu+%vlLoo}2Miz+Xj(!yt#A#x0DAVO*Yy-;*?hB5vaf-WX?uH(^WW^|-sKHc{y%JJ!^>Tp4?VTqR z6MlQP!zwMF-W3L>J75w(B)jjq7iQki+Pv4*(P1a&Y5KlgV&P}g>nncP+lRGv4x{U2 zjx>@8$T=Hmf}jfJO{-oxHXM0}`1-0vS4UB}S#5%RWpAEmSP*CvBcVB?RYTvirA4G! zw#UWY=t?fxAd)}{T%uI9vw>2y0^>|F<`XJu4}SJ%vshB;2oC-v%-XlEt#171nGKk0 z@Z{`Tqc*~1*YJYPo20;n^v@?AA9|Bgh-`gJvor`v69B{baZ)2-Rb=lCV{a9&@U+&g zD)SzN-zmbuz+w>32dw)_D~xHlM?Hmlbw zs7z$*+5^3}f5}D5g>Y*c#JJvq=sG!3#Z~uuG4$-UFM{T^$#(|1+9r<`C}bccf^X-ZBA>M^vI4bMbmHJz&VyH9NBmZ%Q?j=JUT;&F$O+%J&hsK6Ye z@7o|jACgf}X#(rV0ODyqc!6aHd>LUE2YZ%1<4M>=Ikq>pVQegYg<2C0RGZSx8O(%i zVkL*^*q>VkHAaI?^A1C*yvGt)bUKbayW0M)er%-bXW&o%kk|X0e)}8_W%XM2*A+AZ z^kw_9i)22)r0879@SfHp#V+F32TNG2N(!%m4zaVCI|tv-tm%YOY#IG@FxPh{Uab?z zmuZow3PzmN5G_U~7*%rTgzZNNNvd~fg@qNl4?7TUjbI0wNX9SdXbE(P=UTcZz;nn(c#6=x!9{HRGcGqHor)8TK zs+Yp&aGVxb1L4KWHA-Ui(Jm=qR6O2XTtAmd*W5p1E(!gx5!P?z6<-mBIhY$UFCpLZ~| z@pPZsyApir>Tu+rhR6i;#2i%q!Ye_w;_THy<7`W47NlkuDD0YxBL$=Ry8r&J~2)ifxw&k&#dEZk4uLNnDY)p1yIJ5wmn1p*(m^JY0PE z_nr^git8MU%m?(X?&iu3}rgOY&%>2p4w>g<+Im>Ckzn(rFXBSiQAq`VLw5E8cMqe;JQ5!_qj{&tB9w;gl||m#ik$5cyO(Z$ zt2k9>ep$^T#9!oX)8(0S-0n{bczBGIC5Nny(+y$w_LdyP%X(h9Hbn8KoLHh#4ML#_O5}MGgya-){RhYExw=Pn&j2jn124|M}0n5 zfzfFxq&mh^ey)`Cic(3w@&>S2MRv2{1!U>Jrc22Bysb<9y;h)2DqDSOCTNyI&JwzI z)AZ>n5w!U8QQPq32KgRbnUnWea=D3br=hq+khDQoo7og;ao|WemMhcMa?ACk{lzEZ z=CK*2S9Gpi@3*#1_agoj;%NE=xEq^<1rw>K?rLgbHbP1AInAyk~JxL822M@ zY5xK%7eamgxZT%lY#PJL0qwe<`#(b<a>qVE|SSw%Bi{#><_ICACTQkQe({=GWX zR*m+pzE@LOACVcvXPkuQZIpUlk$=5*KB8f*xee`o_-O{_<1n{N>IadNN8!Jr&oK2+ zJTs2%+y-|Z=9BCnzH|X_(&4U-_{`RQOS})cr~XO*_nQUYy65+=$aqq}(jfIHJoHG^ zTRMv1j*}g#F4({5y?q+Yb&EY4ifeVqgQ4nX3y!zGj&8lYAXOvhJ+QeA2gI1RgpW9= z(=^DjkWFxASb5?*@L25KAc^(7lYqgH;4tIU_EB%f0}Y^LH~Wfs!NtOa6m~w1S*@^? zT|}(t7x8Dq9#~@NUc(Ozr!NWq?bLKZ>3~?HRW7BbQNkX^`(5he+y)KB5IF4YcdaM1j?%K6K)~ zmT;`ev`lc7)K~;bG;=DuXWau|bTei_#Gt~@3G!vMMeWPUMbEdOzi!P{;vXueUZhmY z`PJ?PS~=@?4No|>31^{2Ea$7Q1*UR7zg>SRik0+{g4X)mW|G0USMiYUQeHb# zCy63gUGZ7zU@V>+3R?MPFR$Un^L|iBp< zM9S%-LSkmt747ubP<6kMi@6rb{)0s}^#@KgNG8yZdD`lbjjRw9xbJ8okd(>!uIzSh z>Fw8T#d-ObJw5i9F>)z>bH+*J0ZLU}l|VPD&b@nyJv_|39y7j874o)FQJpfa{4n3S zKdzuJP$uJbcdqQzxpZBsrw;ONYZ1MTM5;|fOohJgB`Nvus;t+y5&zU zfSrk1ZU2+()~|fz@W(ga%2ItcMY~$7?JW*&kl{zc)CE{=7@5<7lsbj4^2^33@&+IA8mPYTHgI`Z z`V{F4!@@d{pW@I*QsH4Z*{_0ZQ+|m4D!s#>LcY|fVukf!^W9I3*_XSx)IMhi$Y+h} z1Ud$iPcw$N$CvP4P5+UXXpn0tvL@}fkTo}f>u|O5voWc=Bg#9T<#}bOS2Ad*_;rcz z_c059bF0yiD)+93L#5AJ)hldgytsKT&(ADb8I2nHDqM0&S2f`~Z^?M_#DzyXQLbPg zjMekV2O&=g)?%BKYgNR7h?}oXlxa_{%h;lf0sqC`vAGep{C!qFQ8sDCkM4e#cSO0? z*KL)b2b@>yQtY}>lRDq8(k8e$JYqVC6FjpLEmOiD(R(^S#(gR`szxI7@u zga_-5<4qF?o2VlwLT`M}vemz|1oLd`59~D7p)Wv0W&efMe5{5KanNhOW`x(Ay)`i= zxZuL5>M*B8*^^Gk4{9Ec1j60Y{%2&a zyq18_*-|(yu1|zQA<-}}T>gdGB1y3nl$Ma!zhO4I$U^UC=f@z-CN*I87=+o}Q*XJL zgD_k8cMCmN&3ODcsAwSUYz%Jov7)?(d9m?d~0%SUHC>Q8)i9N%)3S=6bu znPbg%cTcwx)OStSBOXf7Pr}@wb1>2)O4{$binPb=QuQC;XXZ}SS<3A-%9&W)D!nBt z=#*{ov|3OH^3;t*#EL^AN}U8E;W2}t8__}DUrKt2>Onqos8uOEX)i=Phh0iSKr3!G zTxDzt(d_21(^n}7;57LvyP8lf`$Scm+d0*v1D)eh&2MFIqYX7ZZwnRD7>EYt7ZAnxyZOg>k^(l>GrI zf65scSWkiDd%hsxmBV##MBJvbr2Iv2D5X?&kEPn2K7TB_N9zL7KkoM(sz6gNPR(a8 z-or7@*wc|k6dY1G$1d~hoK%B=e&#K!1j1G6@;WKYM3WM8DdTj{ch$KMmBvTk)q3XF z{k+?AH;aGNoL@du3Wu4rF_v4ITB#w6*)e^%Ii5 zjy}aN@xH4f2LWQMkJI(t!ra2b{J@+{LyY6p<1THs_?V|^B1N2)p!T%z-G88_(ZB>} ze)6tt>|LfaZ-qq3TYcGdt?vN(-d#@sVv*GjRZJY z^(}i&yx-4A$@}9qeK3C@v)ko&3}@>^-+2Nbrm zs9|pt4>jaCSRZ%wvBj10nkLpHnsf2ILnT+k_Wwo$(yq&XY8^Y#2YEV!zE?d0V=u!Xf z%fQ>SPxsZsd$>}ir3V8VbJdb{c!x{G=0zn+B~*(7eC_N9NQ;9tSBS4vj9=n@I(@VZ zzgKa+!N?>r@ZI;yc>xP>$kKPK;Fl%Zol*qz2Y0Wfk*Ww{8HCkU_tdI7S$X{?n~&%C zW$Rkz7s?u0gM@YX^KsH~NnSq5894qTWK!HCH2jBJoD}A zvLv%4>A6VpW^?fG!~E8~@HSBb^1te=xGGmy3HV#p5_#f7yz@@o==`CcC$K4r zm8^QFdoo>jLtD54(((BCnG@v`CYjD^js12CuDru?3KsC-hYnQ1e_S*c?y&@LG6h`Krzc1Pa?cMV5 qDW|cWyN9t3C*+^=A0GUp1OMp2KRWP_4*a77|LDN~MjfD|&Hi6VLCs?T literal 0 HcmV?d00001 diff --git a/motion_estimation.py b/motion_estimation.py new file mode 100644 index 0000000..9da0314 --- /dev/null +++ b/motion_estimation.py @@ -0,0 +1,55 @@ +import cv2 +import numpy as np + +# 读取左右视角图像(灰度模式) +img1 = cv2.imread('images/left.jpg', 0) +img2 = cv2.imread('images/right.jpg', 0) + +# 初始化SIFT特征检测器 +sift = cv2.SIFT_create() # 创建SIFT对象 + +# 检测关键点并计算描述符 +kp1, des1 = sift.detectAndCompute(img1, None) +kp2, des2 = sift.detectAndCompute(img2, None) + +# FLANN匹配器参数配置 +FLANN_INDEX_KDTREE = 1 +index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) # KD树算法参数 +search_params = dict(checks=50) # 搜索参数:检查次数 + +# 创建FLANN匹配器实例 +flann = cv2.FlannBasedMatcher(index_params, search_params) +matches = flann.knnMatch(des1, des2, k=2) # k近邻匹配 + +pts1 = [] +pts2 = [] +good_matches = [] # 初始化优质匹配列表 + +# 使用Lowe's比率测试筛选优质匹配 +for i, (m, n) in enumerate(matches): + if m.distance < 0.7 * n.distance: # 修改此处:调整距离比阈值 + good_matches.append(m) + pts2.append(kp2[m.trainIdx].pt) # 记录右图匹配点坐标 + pts1.append(kp1[m.queryIdx].pt) # 记录左图匹配点坐标 + +if len(good_matches) > 8: + pts1 = np.int32(pts1) + pts2 = np.int32(pts2) + + # 计算基础矩阵(使用RANSAC算法) + F, mask = cv2.findFundamentalMat(pts1, pts2, cv2.FM_RANSAC) + print("基础矩阵:\n", F) + + # 通过基础矩阵恢复旋转和平移变换 + _, R, t, _ = cv2.recoverPose(F, pts1, pts2) + print("旋转矩阵:\n", R) + print("平移向量:\n", t) + + # 可视化优质匹配结果 + img_match = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, + flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) + cv2.imshow('特征匹配', img_match) + cv2.waitKey(0) + cv2.destroyAllWindows() +else: + print("匹配点不足,无法计算基础矩阵。") \ No newline at end of file diff --git a/实验报告_相机标定与运动估计.md b/实验报告_相机标定与运动估计.md new file mode 100644 index 0000000..5fac756 --- /dev/null +++ b/实验报告_相机标定与运动估计.md @@ -0,0 +1,43 @@ +# 计算机视觉实验报告:相机标定与运动估计 + +## 一、 实验目的 +1. 了解相机标定和运动估计的基本原理; +2. 了解相机标定和运动估计的应用; +3. 掌握相机标定和运动估计实现方法。 + +## 二、 基本思想 +### 相机标定 +相机标定旨在计算相机的内部参数(焦距、主点坐标等)和外部参数(位置和方向),以及校正镜头畸变。使用棋盘格图案作为标定物,通过已知的3D-2D对应关系来求解相机矩阵和畸变系数。 + +### 运动估计 +运动估计是通过分析连续图像帧之间的特征匹配,确定两个视图之间的相对旋转和平移变换。这通常涉及基础矩阵或本质矩阵的计算,从而恢复场景的三维结构和相机运动。 + +## 三、 源码 +### 相机标定代码 +```python +# 见camera_calibration.py文件 +``` + +### 运动估计代码 +```python +# 见motion_estimation.py文件 +``` + +## 四、 算法分析 +### 时间复杂度 +- **相机标定**:主要耗时在角点检测O(N)和线性优化迭代求解参数,整体近似为O(N·T),其中N为像素数,T为迭代次数。 +- **运动估计**:SIFT特征提取为O(M), 特征匹配为O(M²),RANSAC筛选为O(K)。总体时间复杂度约为O(M²+K)。 + +### 空间复杂度 +- **相机标定**:存储对象点和图像点的数组为O(P),P为角点数目。 +- **运动估计**:保存关键点和描述符的空间为O(Q), Q为特征数量。 + +## 五、 实验运行结果图 +### 相机标定角点检测示例 +![标定角点](results/calibration_corners.png) + +### 运动估计特征匹配图 +![特征匹配](results/feature_matching.jpg) + +## 六、 实验总结 +这里可以添加你的实验心得和遇到的问题及解决方案。 \ No newline at end of file