├── .github └── FUNDING.yml ├── README.md ├── backupDistortionTable.xlsx ├── data ├── distortionImage1.png ├── distortionImage2.png ├── distortionImage3.png ├── distortionImage4.png ├── distortionImage5.png ├── distortionImage6.png └── distortionTable.xlsx ├── images ├── cuixingxingPlot.PNG ├── distionTable.png ├── flowChart.PNG ├── image0.png ├── image1.png ├── image2.png ├── image3.png └── image4.png ├── initUndistortRectifyMapOpenCV.m ├── license.md ├── main.mlx ├── undistortFisheyeImgFromTable.m └── 深入洞察 OpenCV 鱼眼模型之成像投影和畸变表估计系数相互转化.pdf /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: https://raw.githubusercontent.com/cuixing158/OpticalFlow-Visualization/refs/heads/main/README_media/sponsors.jpg # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 深入洞察OpenCV鱼眼模型之成像投影和畸变表估计系数相互转化 2 | 3 | [![Sponsor](https://img.shields.io/badge/-Sponsor-red?style=for-the-badge&logo=GitHub-Sponsors&logoColor=white)](https://raw.githubusercontent.com/cuixing158/OpticalFlow-Visualization/refs/heads/main/README_media/sponsors.jpg) 4 | [![View Use OpenCV FishEye And DistortionTable In Matlab on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://ww2.mathworks.cn/matlabcentral/fileexchange/118170-use-opencv-fisheye-and-distortiontable-in-matlab) 5 | [![Open in MATLAB Online](https://www.mathworks.com/images/responsive/global/open-in-matlab-online.svg)](https://matlab.mathworks.com/open/github/v1?repo=cuixing158/OpenCVFisheyeAndDistortionTable&file=main.mlx) 6 | 7 | >本Repo实现了从原理公式上直接使用来自OpenCV鱼眼畸变模型的4个系数 $k_1 ,k_2 ,k_3 ,k_4$ 和内参 $K$ 对图像进行去畸变以及来自厂商提供的镜头畸变表与OpenCV鱼眼模型参数的估计互相转换。另外对OpenCV鱼眼模型的成像原理过程(透视投影像高vs畸变像高)进行了绘图分析,便于从视觉上直观感受,从而加深对OpenCV鱼眼镜头模型投影成像的理解。关于pin-hole透视镜头成像标定过程可以参阅我之前的[Repo](https://github.com/cuixing158/singleImageCalibration),C++代码请参阅我这个[Repo](https://github.com/cuixing158/FishEyeImage_Undistortion)。 8 | 9 | ## Table of contents 10 | 11 | - [Overview of Distortion Table](#overview-of-distortion-table) 12 | - [Overview of OpenCV fisheye Camera Model](#overview-of-opencv-fisheye-camera-model) 13 | - [注意误点](#注意误点) 14 | - [总结几点](#总结几点) 15 | - [直接根据畸变表对图像去畸变](#直接根据畸变表对图像去畸变) 16 | - [畸变表拟合系数对图像去畸变](#畸变表拟合系数对图像去畸变) 17 | - [畸变系数推算畸变表](#畸变系数推算畸变表) 18 | - [References](#references) 19 | 20 | ## Overview of Distortion Table 21 | 22 | 来自鱼眼镜头厂商的畸变表一般为下述形式表格,其描述了光线通过透镜在相机传感器平面成像的高度信息,一般至少含有3列数据,比如下面表格有“Angle”(degrees),"Real Height"(mm),"Ref Height"(mm)等。其分别表示光线入射角(光线与摄像机光轴的夹角),实际成像高度,参考成像高度(透视投影),这些信息**足以表征此镜头的畸变扭曲程度**。另外还会提供一些常量,如每个像素长度为0.003mm,图像尺寸1920×1080,畸变中心位于图像中心,进一步地,结合畸变表,可以推算相机内参矩阵 $K$ 。 23 | 24 | ![image_0.png](images/distionTable.png) 25 | 26 | 上述表格中第1列和第3列通常满足 $\textrm{RefH}=f*\tan \left(\theta \right)$ , $\theta$ 对应第一列,一般从0°到90°之间,$`\textrm{RefH}`$ 为第三列,从此式可以推算出焦距 $f$ 。 27 | 28 | 本Repo中所使用的畸变表格数据和此镜头录制的图像畸变数据在当前“data”文件夹下的“distortionTableFromFactory.xlsx”,“distortionImageN.png”。 29 | 30 | ## Overview of OpenCV fisheye Camera Model 31 | 32 | 关于Fish-Eye其实有多种投影模型,具体参考[文献6](https://wiki.panotools.org/Fisheye_Projection),典型有equidistance,equisolid angle,orthogonal projection等,根据OpenCV实现,其依据的论文是一种通用模型,不依赖某个具体的类型,取9阶系数就足以满足绝大多数镜头畸变模型。在此,也不再叙述过程,本文重点在下述原理理解和代码实践上! 33 | 34 | 根据此处OpenCV官方文档此处[链接](https://docs.opencv.org/4.x/db/d58/group__calib3d__fisheye.html),导航到“Detailed Description”部分,要完全弄清楚其原理,其描述过程仍然令人有些费解,没有像MATLAB官方文档描述的清楚,一目了然。即使结合第三方大量博客(CSDN,知乎等,见文后References),也未必能阐述清楚。故结合OpenCV源码和论文“a generic camera model and calibration method for conventional-wide-angle and fisheye lenses”,再经过本Repo实践,我画出下面的**成像原理图,符号和公式严格表达准确,代码运行可靠!** 35 | 36 | ![image_1.png](images/cuixingxingPlot.PNG) 37 | 38 | 简单阐述下上述我绘制的图中的主要符号,坐标系 $X_c O_1 Y_c$ 为相机物理坐标系,蓝色平面 $\pi_1$ 为归一化成像平面(离光心 $O_1$ 的距离为1),橙色平面 $\pi_2$ 为实际成像平面(离光心 $O_1$ 的距离为焦距 $f$ ),点 $P$ 为坐标系 $X_c O_1 Y_c$ 下的一外点,光线通过红色虚线射入,从绿色虚线“折射”到成像平面“引起畸变”;点 $p^{\prime }$ , $N$ 分别为平面 $`\pi_2`$ ,$`\pi_1`$ 理想透视投影点,点 $p$ , $M$ 分别为平面 $\pi_2$ , $\pi_1$ 实际投影畸变点。另外位于平面 $\pi_1$ 的 $\left\|O_2 M\right\|=r_d$ , $\left\|O_2 N\right\|=r$ ,而不是平面 $\pi_2$ 中的 $`\left\|O_3 p\right\|\not= r_d$ ,$\left\|O_3 p^{\prime } \right\|\not= r`$ ,这在OpenCV文档中并没有解释清楚。 39 | 40 | 点 $P\left(x_c ,y_c ,z_c \right)$ 透视投影经归一化为平面 $\pi_1$ 中的点 $N\left(x_n ,y_n \right)$ , 41 | 42 | $$ 43 | x_n =\frac{x_c }{z_c },y_n =\frac{y_c }{z_c } 44 | $$ 45 | 46 | $$ 47 | r^2 =x_n^2 +y_n^2 48 | $$ 49 | 50 | $$ 51 | \theta =\textrm{atan}\left(r\right) 52 | $$ 53 | 54 | 畸变像高: 55 | 56 | $$ 57 | r_d =\theta \left(1+{k_1 \theta }^2 +k_2 \theta^4 +k_3 \theta^6 +{k_4 \theta }^8 \right) 58 | $$ 59 | 60 | 同时, $\bigtriangleup O_1 O_2 M$ 为直角三角形,满足, 61 | 62 | $$ 63 | r_d =1*\tan \left(\theta_d \right) 64 | $$ 65 | 66 | 注意上述式子中的 $r_d$ 并非OpenCV文档中写的 $\theta_d$ ,然后计算比例因子scale, 67 | 68 | $$ 69 | \textrm{scale}=\frac{r_d }{r} 70 | $$ 71 | 72 | 又因 $\bigtriangleup O_1 O_2 N\sim \bigtriangleup O_1 O_3 p^{\prime }$ , $\bigtriangleup O_1 O_2 M\sim \bigtriangleup O_1 O_3 p$ , 73 | 74 | 则 $$\textrm{scale}=\frac{r_d }{r}=\frac{\left\|O_3 p\right\|}{\left\|O_3 p^{\prime } \right\|}$$ 75 | 76 | 为了得到点 $p$ 的畸变坐标 $\left(x_d ,y_d \right)$ ,有, 77 | 78 | $$ 79 | x_d =\textrm{scale}*a 80 | $$ 81 | 82 | $$ 83 | y_d =\textrm{scale}*b 84 | $$ 85 | 86 | 设点 $O_3$ 在像素平面 $\textrm{uv}$ 下的坐标为 $\left(U_0 ,V_0 \right)$ ,在 $x$ 轴, $y$ 轴单位长度上的像素数为 $f_x ,f_y$ ,则像素坐标为, 87 | 88 | $$ 89 | u=f_x *x_d +U_0 90 | $$ 91 | 92 | $$ 93 | v=f_y *y_d +V_0 94 | $$ 95 | 96 | 如果考虑错切因子 $\alpha$ ,则上式 $\left.u=f_x *{\left(x\right.}_d +{\alpha y}_d \right)+U_0$ ,此时内参矩阵 $K$ 即为, 97 | 98 | $$ 99 | K=\left\lbrack \begin{array}{ccc} 100 | f_x & \alpha & U_0 \\ 101 | 0 & f_y & V_0 \\ 102 | 0 & 0 & 1 103 | \end{array}\right\rbrack 104 | $$ 105 | 106 | 注意上述步骤其实是**图像去畸变的工作过程,先一一找到无畸变点对应的畸变点坐标映射,合适时候再通过插值找到对应的像素点。** 107 | 108 | 如果是**某个点的去畸变,则需要逆向求解上述过程**,其中有已知 $\theta_d$ ,求 $\theta$ ,这就很多方法了,不在此描述。 109 | 110 | ### 注意误点 111 | 112 | - $r_d$ , $r$ 的计算分析均指在归一化平面 $\pi_1$ 上进行的,而不是实际成像平面 $\pi_2$ 。[OpenCV文档](https://docs.opencv.org/4.x/db/d58/group__calib3d__fisheye.html)中写的是 $\theta_d =\theta \left(1+{k_1 \theta }^2 +k_2 \theta^4 +k_3 \theta^6 +{k_4 \theta }^8 \right)$ 不准确的,并非上述公式中的 $\theta_d$ ,这是因为OpenCV源码变量中把 $r_d$ 中间临时变量写成了 $\theta_d$ ,而文档是根据代码自动生成的,这就导致了描述不够准确,但内部计算逻辑是正确的, $\theta$ 和 $\theta_d$ 单位为弧度,非度数。 113 | - 参考[文献4](https://blog.csdn.net/qq_16137569/article/details/112398976)描述“畸变与焦距无关”是不完全正确的,这在归一化成像平面 $\pi_1$ 上成立,因为有 $r_d =1*\tan \left(\theta_d \right)$ ,但在实际成像平面上 $\pi_2$ 上不成立,因为 $\left\|O_3 p\right\|=f*\tan \left(\theta_d \right)$ , $\theta_d$ 一定的情况下,与焦距 $f$ 成正比的。 114 | - 参考[文献4](https://blog.csdn.net/qq_16137569/article/details/112398976)把平面 $\pi_1$ 和平面 $\pi_2$ 混为一团,后果是牵强认为 $r_d =1*\tan \left(\theta_d \right)=\theta_d$ ,为了说服其成立,认为“ $\theta_d$ 趋于0, $r_d$ 就等于 $\theta_d$ ,但这里根本就没有趋向于0的说法。 115 | 116 | ### 总结几点 117 | 118 | - 归一化平面 $\pi_1$ 存在的目的是为了求取尺度scale,然后根据三角形相似原理转嫁到实际成像平面 $\pi_2$ 做去畸变计算。 119 | - 焦距不会影响畸变形状(或外观),影响的是尺度变化,但尺度变化百分比保持不变。 120 | - 4个畸变系数 $k_1 ,k_2 ,k_3 ,k_4$ 影响畸变形状(或外观),也会影响尺度大小。 121 | - 内参矩阵 $K$ 是相机物理坐标与像平面像素坐标互相转换的“过渡矩阵”,决定着畸变中心位置坐标和坐标系转换的功能。 122 | 123 | 为了利用畸变表提供的数据对畸变图像进行去畸变,通常有下面2种方式: 124 | 125 | ```mermaid 126 | --- 127 | title: 利用畸变表对图像去畸变流程 128 | --- 129 | flowchart LR 130 | A[畸变表]-- 直接利用像高比例 ----->C[去畸变图] 131 | A-- "OpenCV鱼眼模型"-->D["拟合畸变系数(k1~k4)"]--->C 132 | ``` 133 | 134 | 下面对上述2种方式分别进行实现。 135 | 136 | ## 直接根据畸变表对图像去畸变 137 | 138 | 主要利用畸变表中像高比例进行查表(一维插值)进行畸变量计算,算法步骤为: 139 | 140 | 1. 根据畸变表估算内参矩阵 $K$ 和人为指定无畸变图大小; 141 | 1. 利用内参矩阵 $K$ 对某个无畸变图像素坐标 $\left(u,v\right)$ 转为像平面 $\pi_2$ 的物理坐标 $\left(x,y\right)$ ; 142 | 1. 计算物理坐标 $\left(x,y\right)$ 离原点的距离为RefH; 143 | 1. 计算入射角 $\theta$ ,然后查表得到畸变像高距离 $r_d$ ,直接根据比例计算物理畸变点坐标 $\left(x_d ,y_d \right)$ ; 144 | 1. 再次利用内参矩阵 $K$ 将物理畸变点坐标 $\left(x_d ,y_d \right)$ 转为像素坐标 $\left(u_d ,v_d \right)$ ; 145 | 1. 对所有无畸变图上的点重复step2-5找到像素坐标映射关系 $\left(u,v\right)\to \left(u_d ,v_d \right)$ ,最后图像插值即可完成去畸变。 146 | 147 | 读取畸变视频/图像源 148 | 149 | ```matlab 150 | distortFrame = imread("data/distortionImage1.png"); 151 | figure;imshow(distortFrame); 152 | title("distortion image") 153 | ``` 154 | 155 | ![figure_0.eps](images/image0.png) 156 | 157 | ```matlab 158 | 159 | distortionTablePath = "./data/distortionTable.xlsx"; 160 | sensorRatio = 0.003;% 由厂家提供,单位 mm/pixel 161 | 162 | cameraData = readtable(distortionTablePath,Range="A4:D804",VariableNamingRule="preserve"); 163 | head(cameraData)% 预览前面若干行数据 164 | ``` 165 | 166 | ```text 167 | Y Angle (deg) Real Height Ref. Height Distortion(f-tanθ) 168 | _____________ ___________ ___________ ___________________ 169 | 0.1 0.0050939 0.005103 -0.00011259 170 | 0.2 0.010188 0.010207 -0.00048478 171 | 0.3 0.015282 0.01531 -0.0011181 172 | 0.4 0.020376 0.020414 -0.0020122 173 | 0.5 0.025469 0.025518 -0.0031675 174 | 0.6 0.030563 0.030622 -0.0045836 175 | 0.7 0.035657 0.035726 -0.0062606 176 | 0.8 0.040751 0.04083 -0.0081985 177 | ``` 178 | 179 | 第一列为入射角,第二列为实际畸变量长度,单位:mm,第三列为理想参考投影长度,单位:mm. 180 | 181 | ```matlab 182 | angleIn = cameraData{:,1};% 入射角 183 | focal = mean(cameraData{:,3}./tand(angleIn));% 焦距,单位:mm 184 | angleOut = atan2d(cameraData{:,2},focal);% 出射角 185 | cameraDataIn = table(angleIn,angleOut,VariableNames = ["angle","angle_d"]); 186 | [h,w,~] = size(distortFrame); 187 | 188 | K = [focal/sensorRatio,0,w/2; 189 | 0,focal/sensorRatio,h/2; 190 | 0,0,1]; 191 | undistortImg = undistortFisheyeImgFromTable(distortFrame,K,cameraDataIn,OutputView="same"); 192 | figure; 193 | imshow(undistortImg); 194 | title("undistortion image from distortion table directly") 195 | ``` 196 | 197 | ![figure_1.eps](images/image1.png) 198 | 199 | ## 畸变表拟合系数对图像去畸变 200 | 201 | 先对畸变表中的像高按照归一化平面 $\pi_1$ 进行像高的转换,然后根据畸变公式进行系数拟合,最后根据比例进行查表(一维插值)进行畸变量计算,算法步骤为: 202 | 203 | 1. 根据畸变表数据(实际焦距 $f$ 下的像高)换算为归一化平面 $\pi_1$ 的像高; 204 | 1. 按照畸变公式进行系数拟合得到 $k_1 ~k_4$ ,同时估算内参矩阵 $K$ 和人为指定无畸变图大小; 205 | 1. 利用内参矩阵 $K$ 对某个无畸变图像素坐标 $\left(u,v\right)$ 转为像平面 $\pi_1$ 的物理坐标 $\left(x,y\right)$ ; 206 | 1. 计算物理坐标 $\left(x,y\right)$ 离原点的距离为RefH; 207 | 1. 计算入射角 $\theta$ ,然后根据畸变公式得到畸变像高距离 $r_d$ ,随后根据比例计算物理畸变点坐标 $\left(x_d ,y_d \right)$ ; 208 | 1. 再次利用内参矩阵 $K$ 将物理畸变点坐标 $\left(x_d ,y_d \right)$ 转为像素坐标 $\left(u_d ,v_d \right)$ ; 209 | 1. 对所有无畸变图上的点重复step2-5找到像素坐标映射关系 $\left(u,v\right)\to \left(u_d ,v_d \right)$ ,最后图像插值即可完成去畸变。 210 | 211 | ```matlab 212 | r_d = 1./focal*cameraData{:,2};% 求归一化平面上的r_d 213 | thetaRadian = deg2rad(angleIn);% 度数转为弧度 214 | ``` 215 | 216 | 由前面分析的畸变像高公式,对归一化平面 $\pi_1$ 上每一个入射角 $\theta \left(\theta_1 ,\theta_2 ,\cdots ,\theta_n \right)$ ,有下述等式成立, 217 | 218 | $$ 219 | \left\lbrace \begin{array}{l} 220 | \theta_1 +k_1 \theta_1^3 +k_2 \theta_1^5 +k_3 \theta_1^7 +k_4 \theta_1^9 =r_{\textrm{d1}} \\ 221 | \theta_2 +k_1 \theta_2^3 +k_2 \theta_2^5 +k_3 \theta_2^7 +k_4 \theta_2^9 =r_{\textrm{d2}} \\ 222 | \vdots \\ 223 | \theta_n +k_1 \theta_n^3 +k_2 \theta_n^5 +k_3 \theta_n^7 +k_4 \theta_n^9 =r_{\textrm{dn}} 224 | \end{array}\right. 225 | $$ 226 | 227 | 写为矩阵形式,为, 228 | 229 | $$ 230 | \left\lbrack \begin{array}{cccc} 231 | \theta_1^3 & \theta_1^5 & \theta_1^7 & \theta_1^9 \\ 232 | \theta_2^3 & \theta_2^5 & \theta_2^7 & \theta_2^9 \\ 233 | \vdots & \vdots & \vdots & \vdots \\ 234 | \theta_n^3 & \theta_n^5 & \theta_n^7 & \theta_n^9 235 | \end{array}\right\rbrack *\left\lbrack \begin{array}{c} 236 | k_1 \\ 237 | k_2 \\ 238 | k_3 \\ 239 | k_4 240 | \end{array}\right\rbrack =\left\lbrack \begin{array}{c} 241 | r_{\textrm{d1}} -\theta_1 \\ 242 | r_{\textrm{d2}} -\theta_2 \\ 243 | \vdots \\ 244 | r_{\textrm{dn}} -\theta_n 245 | \end{array}\right\rbrack 246 | $$ 247 | 248 | 典型为 $A*x=b$ ,最小二乘解为 $x=A\backslash b$ . 249 | 250 | ```matlab 251 | A = [thetaRadian.^3,thetaRadian.^5,thetaRadian.^7,thetaRadian.^9]; 252 | b = r_d-thetaRadian; 253 | opencvCoeffs = A\b; 254 | disp("最小二乘拟合OpenCV鱼眼模型畸变系数为(k1~k4):"+strjoin(string(opencvCoeffs'),",")) 255 | ``` 256 | 257 | ```text 258 | 最小二乘拟合OpenCV鱼眼模型畸变系数为(k1~k4):-0.10493,0.015032,-0.013603,0.0030601 259 | ``` 260 | 261 | ```matlab 262 | newCameraMatrixK = K; 263 | newImageSize = size(distortFrame,[1,2]);% [height,width] 264 | [mapX,mapY] = initUndistortRectifyMapOpenCV(K, opencvCoeffs,newCameraMatrixK,newImageSize); 265 | ``` 266 | 267 | mapX,mapY即为映射 $\left(u,v\right)\to \left(u_d ,v_d \right)$ 的关系坐标。 268 | 269 | ```matlab 270 | undistortImg2 = images.internal.interp2d(distortFrame,mapX,mapY,"linear",255, false); 271 | figure; 272 | imshow(undistortImg2) 273 | title("undistortion image from fit opencv fisheye model coefficient") 274 | ``` 275 | 276 | ![figure_2.eps](images/image2.png) 277 | 278 | 可以看出两种方法效果图一致,主要区别就是尺度scale计算方式不同,一个是直接查表得到scale,另一个是拟合公式求scale,没有明显的本质区别。 279 | 280 | ## 畸变系数推算畸变表 281 | 282 | 有时厂商提供了镜头畸变表,并且我们也通过OpenCV标定了该镜头得到内参矩阵 $K$ 和畸变系数 $k_1-k_4$ ,但我们**更想验证我们的标定算法与厂商提供的畸变表“差距”有多大,那也可以通过畸变系数推算畸变表,然后绘制像高曲线进行比对,从而确保双向验证参数的准确性和一致性。** 283 | 284 | 为实验方便,直接采用上节拟合的畸变系数 $k_1-k_4$ 和估计的内参矩阵 $K$ 作为我们的“标定参数”结果,反推上述的畸变表cameraData数据,注意这里已知 $\theta$ ,求像高。 285 | 286 | ```matlab 287 | disp("标定内参矩阵K:"); 288 | ``` 289 | 290 | ```text 291 | 标定内参矩阵K: 292 | ``` 293 | 294 | ```matlab 295 | disp(newCameraMatrixK); 296 | ``` 297 | 298 | ```text 299 | 974.6782 0 960.0000 300 | 0 974.6782 540.0000 301 | 0 0 1.0000 302 | ``` 303 | 304 | ```matlab 305 | disp("标定的畸变系数为(k1~k4):"+strjoin(string(opencvCoeffs'),",")) 306 | ``` 307 | 308 | ```text 309 | 标定的畸变系数为(k1~k4):-0.10493,0.015032,-0.013603,0.0030601 310 | ``` 311 | 312 | ```matlab 313 | % 入射角是从0.1°逐渐变化到90°,转为弧度制 314 | theta = deg2rad(angleIn); 315 | RefX = tan(theta); 316 | RefX = filloutliers(RefX,"nearest","mean");% 过滤填充异常点,tan90接近无限大 317 | RefY = 0; 318 | RefH = abs(RefX).*sign(tan(theta)); % 单位:mm 319 | 320 | % 再计算拟合像高 321 | r_d = theta.*(1+opencvCoeffs(1)*theta.^2+opencvCoeffs(2)*theta.^4+... 322 | opencvCoeffs(3)*theta.^6+opencvCoeffs(4)*theta.^8); 323 | 324 | scale = r_d./RefH; 325 | RealX = RefX.*scale; 326 | RealY = RefY.*scale; 327 | r_d = sqrt(RealX.^2+RealY.^2); 328 | 329 | % 绘制参考像高vs实际像高vs百分比误差 330 | figure; 331 | plot(rad2deg(theta),RefH,... 332 | rad2deg(theta),r_d,... 333 | rad2deg(theta),(r_d-RefH)./RefH*100,... 334 | LineWidth=2) 335 | hold on;grid on; 336 | 337 | plot(cameraData{:,1},cameraData{:,3},"--",... % Ref height 338 | cameraData{:,1},cameraData{:,2},":",... % Real height 339 | cameraData{:,1},(cameraData{:,2}-cameraData{:,3})./cameraData{:,3}*100,"-.",... 340 | LineWidth=2) 341 | 342 | f = mean([newCameraMatrixK(1,1),newCameraMatrixK(2,2)])*sensorRatio; 343 | legend(["paraxial height(mm),f=1","real height(mm),f=1","DISTORTION(%),f=1",... 344 | "factory paraxial height(mm),f="+string(f),"factory real height(mm),f="+string(f),... 345 | "factory DISTORTION(%),f="+string(f)],Location="northwest"); 346 | ax = gca; 347 | ax.YLim = [-50,50]; 348 | ax.XAxis.TickLabelFormat = '%g\x00B0';% 'degrees' 349 | xlabel("入射角\theta"); 350 | ylabel("像高/百分比"); 351 | title("distortion curve(f=1 vs f="+string(mean(f))+")"); 352 | ``` 353 | 354 | ![figure_3.eps](images/image3.png) 355 | 356 | 实线为推算的像高曲线与厂商提供畸变表像高曲线(虚线)不重合? 357 | 358 | Oops!原来是在不同成像平面上像高差异导致的(就是最上面分析的平面( $\pi_1$ , $\pi_2$ ),他们的畸变百分比是一致的!再看下下面焦距弥补导致的像高曲线变化。 359 | 360 | ```matlab 361 | % 转换到实际f的焦距成像平面上的像高 362 | RefH = f.*RefH; 363 | r_d = f.*r_d; 364 | 365 | % 绘制厂商结果对比图 366 | figure; 367 | plot(rad2deg(theta),RefH,... 368 | rad2deg(theta),r_d,... 369 | rad2deg(theta),(r_d-RefH)./RefH*100,... 370 | LineWidth=2) 371 | hold on;grid on; 372 | 373 | plot(cameraData{:,1},cameraData{:,3},"--",... % Ref height 374 | cameraData{:,1},cameraData{:,2},":",... % Real height 375 | cameraData{:,1},(cameraData{:,2}-cameraData{:,3})./cameraData{:,3}*100,"-.",... 376 | LineWidth=2) 377 | legend(["paraxial height(mm),f="+string(f),"real height(mm),f="+string(f),"DISTORTION(%),f="+string(f),... 378 | "factory paraxial height(mm),f="+string(f),"factory real height(mm),f="+string(f),... 379 | "factory DISTORTION(%),f="+string(f)],Location="northwest"); 380 | ax = gca; 381 | ax.YLim = [-50,50]; 382 | ax.XAxis.TickLabelFormat = '%g\x00B0';% 'degrees' 383 | xlabel("入射角\theta"); 384 | ylabel("像高/百分比"); 385 | title("distortion curve"); 386 | ``` 387 | 388 | ![figure_4.eps](images/image4.png) 389 | 390 | ```matlab 391 | writematrix([rad2deg(theta),r_d,RefH],"backupDistortionTable.xlsx") 392 | ``` 393 | 394 | 现在为实际焦距 $f$ 下的成像像高,符合预期期望。 395 | 396 | ## References 397 | 398 | 1. [Fisheye camera model](https://docs.opencv.org/4.4.0/db/d58/group__calib3d__fisheye.html) 399 | 1. Juho Kannala and Sami Brandt. A generic camera model and calibration method for conventional, wide-angle, and fish-eye lenses. *IEEE transactions on pattern analysis and machine intelligence*, 28:1335–40, 09 2006. 400 | 1. [常用相机投影及畸变模型(针孔|广角|鱼眼)](https://blog.csdn.net/qq_28087491/article/details/107965151) 401 | 1. [鱼眼镜头的成像原理到畸变矫正(完整版)](https://blog.csdn.net/qq_16137569/article/details/112398976) 402 | 1. [What are the main references to the fish-eye camera model in OpenCV3.0.0dev?](https://stackoverflow.com/questions/31089265/what-are-the-main-references-to-the-fish-eye-camera-model-in-opencv3-0-0dev) 403 | 1. [Fisheye Projection](https://wiki.panotools.org/Fisheye_Projection) 404 | -------------------------------------------------------------------------------- /backupDistortionTable.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/backupDistortionTable.xlsx -------------------------------------------------------------------------------- /data/distortionImage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/data/distortionImage1.png -------------------------------------------------------------------------------- /data/distortionImage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/data/distortionImage2.png -------------------------------------------------------------------------------- /data/distortionImage3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/data/distortionImage3.png -------------------------------------------------------------------------------- /data/distortionImage4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/data/distortionImage4.png -------------------------------------------------------------------------------- /data/distortionImage5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/data/distortionImage5.png -------------------------------------------------------------------------------- /data/distortionImage6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/data/distortionImage6.png -------------------------------------------------------------------------------- /data/distortionTable.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/data/distortionTable.xlsx -------------------------------------------------------------------------------- /images/cuixingxingPlot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/cuixingxingPlot.PNG -------------------------------------------------------------------------------- /images/distionTable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/distionTable.png -------------------------------------------------------------------------------- /images/flowChart.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/flowChart.PNG -------------------------------------------------------------------------------- /images/image0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/image0.png -------------------------------------------------------------------------------- /images/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/image1.png -------------------------------------------------------------------------------- /images/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/image2.png -------------------------------------------------------------------------------- /images/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/image3.png -------------------------------------------------------------------------------- /images/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/images/image4.png -------------------------------------------------------------------------------- /initUndistortRectifyMapOpenCV.m: -------------------------------------------------------------------------------- 1 | function [mapX,mapY,undistortPts, distortPts] = initUndistortRectifyMapOpenCV(K, opencvCoeffs,newCameraMatrixK,newImageSize) 2 | % Brief: 由opencv鱼眼畸变系数得到映射和坐标点对应,功能等同于opencv的initUndistortRectifyMap函数 3 | % Details: 4 | % None 5 | % 6 | % Syntax: 7 | % [mapX,mapY,undistortPts, distortPts] = initUndistortRectifyMapOpenCV(w, h, K, opencvCoeffs) 8 | % 9 | % Inputs: 10 | % K - [3,3] size,[double] type,fisheye camera intrinsic, 11 | % [fx,0,cx; 12 | % 0,fy,cy; 13 | % 0,0,1] format 14 | % opencvCoeffs - [1,4] size,[double] type,opencv fisheye coeffs 15 | % newCameraMatrixK - [3,3] size,[double] type,new fisheye camera intrinsic, 16 | % [fx,0,cx; 17 | % 0,fy,cy; 18 | % 0,0,1] format 19 | % newImageSize - [1,2],[double] type,new image [height,width] 20 | % 21 | % Outputs: 22 | % mapX - [h,w] size,[double] type,Description 23 | % mapY - [h,w] size,[double] type,Description 24 | % undistortPts - [h*w,2] size,[double] type,Description 25 | % distortPts - [h*w,2] size,[double] type,Description 26 | % 27 | % 28 | % See also: None 29 | 30 | % Author: cuixingxing 31 | % Email: cuixingxing150@gmail.com 32 | % Created: 27-Sep-2022 07:42:05 33 | % Implementation In Matlab R2022a 34 | % Copyright © 2022 TheMatrix.All Rights Reserved. 35 | % 36 | arguments 37 | K (3,3) {mustBeNumeric} 38 | opencvCoeffs (1,4) {mustBeNumeric} 39 | newCameraMatrixK (3,3) {mustBeNumeric} 40 | newImageSize (1,2) {mustBeNumeric} 41 | end 42 | 43 | % coeff convert to matlab 44 | centerY = newImageSize(1)/2; % ensure distortion lie in center of image 45 | centerX = newImageSize(2)/2; % ensure distortion lie in center of image 46 | offsetX = K(1,3)-centerX; 47 | offsetY = K(2,3)-centerY; 48 | [undistortX,undistortY] = meshgrid(1+offsetX:newImageSize(2)+offsetX,1+offsetY:newImageSize(1)+offsetY); 49 | undistortPts = [undistortX(:),undistortY(:)]; 50 | 51 | undistortPtsHomo = [undistortPts'; 52 | ones(1,prod(newImageSize))]; % 3*cols size 53 | undistortCameraPts = newCameraMatrixK\undistortPtsHomo; % 3*cols size 54 | undistortCameraPts = undistortCameraPts./undistortCameraPts(end,:);% 3*cols size 55 | 56 | r = vecnorm(undistortCameraPts(1:2,:),2,1); % 1*cols size 57 | theta = atan(r); 58 | 59 | r_d = theta.*(1+opencvCoeffs(1)*theta.^2+opencvCoeffs(2)*theta.^4+... 60 | opencvCoeffs(3)*theta.^6+opencvCoeffs(4)*theta.^8); % r_d非theta_d 61 | 62 | r(r<=10^(-8))=1; 63 | scale =r_d./r; 64 | u = K(1,1)*undistortCameraPts(1,:).*scale+ K(1,3); 65 | v = K(2,2)*undistortCameraPts(2,:).*scale + K(2,3); 66 | distortPts = [u',v'];% rows*2 67 | 68 | mapX = reshape(distortPts(:,1),newImageSize(1),newImageSize(2)); 69 | mapY = reshape(distortPts(:,2),newImageSize(1),newImageSize(2)); 70 | end 71 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023, xingxingCui 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution 13 | 14 | * Neither the name of nor the names of its 15 | contributors may be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /main.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/main.mlx -------------------------------------------------------------------------------- /undistortFisheyeImgFromTable.m: -------------------------------------------------------------------------------- 1 | function [undistortImg,mapX,mapY,camIntrinsic,newOrigin] = undistortFisheyeImgFromTable(... 2 | oriImg,K,cameraData,options) 3 | % Brief: 直接根据畸变表对图像进行去畸变 4 | % Details: 5 | % 数据表仅需入射角+出射角(或者提供畸变real_height和ref_height可计算出射角)+ 6 | % 焦距(或者提供畸变real_height和ref_height可计算焦距)即可,此函数支持C代码生成,快速高效 7 | % 以principle point为中心,畸变逐渐增大。经验值sensorRatio = 0.003mm/pixel. 8 | % 9 | % Syntax: 10 | % [undistortImg,mapX,mapY] = undistortImgFast(oriImg,K,cameraData) 11 | % 12 | % Inputs: 13 | % oriImg - [m,n] size,[any] type,Description 14 | % K - [3,3] size,[double] type,fisheye camera intrinsic matrix, 15 | % [fx,0,cx; 16 | % 0,fy,cy; 17 | % 0,0,1] format 18 | % cameraData - [m,n] size,[table] type,必须包含入射角angle和出射角angle_d域名 19 | % Outputview - [1,1] size,[string] type,Size of the output image, specified 20 | % as either 'same','full', or 'valid'. 21 | % ScaleFactor - [1,2] size, [double] type,Scale factor for the focal 22 | % length of a virtual camera perspective,in pixels, specified 23 | % as [sx sy] vector. Specify a vector to scale the x and y axes 24 | % individually. Increase the scale to zoom in the perspective 25 | % of the camera view. 26 | % 27 | % Outputs: 28 | % undistortImg - [M,N] size,[double] type,无畸变图像 29 | % mapX - [M,N] size,[double] type,映射到原图oriImg的x的坐标 30 | % mapY - [M,N] size,[double] type,映射到原图oriImg的y的坐标 31 | % camIntrinsic - [1,1] size, [cameraIntrinsics] type,等价的完美针孔相机内参 32 | % newOrigin - [1,2] size, [double] type,新原点坐标,使用undistortFisheyePtsFromTable 33 | % 函数返回的无畸变点应当减去此值可得到在去畸变图像上的坐标。 34 | % 35 | % Example: 36 | % %% 鱼眼图像去畸变 37 | % oriImage = imread("fisheye.jpg"); 38 | % cameraParaPath = "distortionTable.xlsx"; 39 | % sensorRatio = 0.003;% 由厂家提供,单位 mm/pixel 40 | 41 | % cameraData = readtable(cameraParaPath,VariableNamingRule='preserve');% 第一列为入射角,单位:度,第二列为实际畸变量长度,单位:mm,第三列为理想参考投影长度,单位:mm 42 | % angleIn = cameraData{:,1};% 入射角,单位:度 43 | % focal = mean(cameraData{:,2}./tand(angleIn));% 焦距,单位:mm 44 | % angleOut = atan2d(cameraData{:,3},focal);% 出射角,单位:度,与入射角一一对应 45 | % cameraData = table(angleIn,angleOut,VariableNames = ["angle","angle_d"]); 46 | % [h,w,~] = size(oriImage); 47 | 48 | % K = [focal/sensorRatio,0,w/2; 49 | % 0,focal/sensorRatio,h/2; 50 | % 0,0,1]; 51 | % scalarSXY = [1,1];% 改变输出图像大小,不影响其他计算 52 | % [undistortImg,mapX,mapY,camIntrinsic] = undistortFisheyeImgFromTable(oriImage,... 53 | % K,cameraData,OutputView="same",ScaleFactor=scalarSXY); 54 | % % 后续类似畸变图像直接使用mapX,mapY映射即可,如下语句 55 | % undistortImage = images.internal.interp2d(distortionImage,mapX,mapY,"linear",0, false); 56 | % 57 | % See also: None 58 | 59 | % Author: cuixingxing 60 | % Email: cuixingxing150@gmail.com 61 | % Created: 24-Jun-2022 19:02:23 62 | % 63 | % Implementation In Matlab R2022b 64 | % Copyright © 2022 TheMatrix.All Rights Reserved. 65 | % 66 | arguments 67 | oriImg 68 | K (3,3) double 69 | cameraData table 70 | options.OutputView (1,:) char {mustBeMember(options.OutputView,... 71 | {'same','full','valid'})}= 'same' 72 | options.ScaleFactor (1,2) double {mustBePositive}= [1,1] 73 | end 74 | sx = options.ScaleFactor(1); 75 | sy = options.ScaleFactor(2); 76 | 77 | cx = K(1,3); 78 | cy = K(2,3); 79 | flength = [K(1,1),K(2,2)]; 80 | 81 | m = tand(cameraData.angle); 82 | n = tand(cameraData.angle_d); 83 | 84 | % fill out outliers 85 | m(abs(m)>400)=NaN; 86 | n(abs(n)>400)=NaN; 87 | m = fillmissing(m,"nearest"); 88 | n = fillmissing(n,"nearest"); 89 | 90 | refHeight = mean(flength).*m; 91 | realHeight = mean(flength).*n; 92 | 93 | [h,w,~] = size(oriImg); 94 | bwImg = ones(h,w,'logical'); 95 | B = bwtraceboundary(bwImg,[1,1],'E');% 畸变图像所有边界点,顺时针逐个取点坐标 96 | B(end,:) = [];% last one is dumplicate to first one 97 | edgePts = [B(:,2),B(:,1)]; 98 | 99 | % 获取矫正图像宽和高 100 | if strcmp(options.OutputView,"same") 101 | newOrigin = round([-w/2,-h/2]);% 无畸变图像中心点为原点的坐标 102 | xlim = [newOrigin(1)+1,newOrigin(1)+w]-newOrigin(1);% 无畸变图像以左上角点为原点的坐标 103 | ylim = [newOrigin(2)+1,newOrigin(2)+h]-newOrigin(2); 104 | elseif strcmp(options.OutputView,"valid") 105 | distortL = vecnorm(edgePts-[cx,cy],2,2); 106 | undistortL = interp1(realHeight,refHeight,distortL,"linear",refHeight(end)); 107 | edgesX = (edgePts(:,1)-cx).*undistortL./distortL; 108 | edgesY = (edgePts(:,2)-cy).*undistortL./distortL; 109 | undistortPts = [edgesX,edgesY];% 无畸变图像中心点为原点的坐标 110 | 111 | % 求不规则四条曲线边轮廓的最大内接矩形算法 112 | % 使用4条边的种子边缘向内扩展算法,避免外延扩展算法效率过低,算法复杂度与边缘畸变程度正相关 113 | topEdgePoints = undistortPts(1:w,:); 114 | rightEdgePoints = undistortPts(w:w+h-1,:); 115 | bottomEdgePoints = undistortPts(w+h-1:2*w+h-2,:); 116 | leftEdgePoints = undistortPts(2*w+h-2:end,:); 117 | 118 | xmin = max(leftEdgePoints(:,1)); 119 | xmax = min(rightEdgePoints(:,1)); 120 | ymin = max(topEdgePoints(:,2)); 121 | ymax = min(bottomEdgePoints(:,2)); 122 | 123 | newOrigin = [xmin,ymin];% 无畸变图像中心点为原点的坐标 124 | xlim = [xmin,xmax]-newOrigin(1); % 无畸变图像以左上角点为原点的坐标 125 | ylim = [ymin,ymax]-newOrigin(2); 126 | else % "full" 127 | distortL = vecnorm(edgePts-[cx,cy],2,2); 128 | undistortL = interp1(realHeight,refHeight,distortL,"linear",refHeight(end)); 129 | edgesX = (edgePts(:,1)-cx).*undistortL./distortL; 130 | edgesY = (edgePts(:,2)-cy).*undistortL./distortL; 131 | undistortPts = [edgesX,edgesY]; 132 | 133 | newOrigin = [min(undistortPts(:,1)),min(undistortPts(:,2))]; 134 | xlim = [min(undistortPts(:,1)),max(undistortPts(:,1))]-newOrigin(1); 135 | ylim = [min(undistortPts(:,2)),max(undistortPts(:,2))]-newOrigin(2); 136 | end 137 | principlePt = ([0,0]-newOrigin); %等价的针孔相机主点坐标 138 | U0 = principlePt(1); 139 | V0 = principlePt(2); 140 | 141 | % 鱼眼图像插值去畸变,避免矫正图像过大,耗时较多,应当考虑适当缩放 142 | xlim = sx.*xlim; 143 | ylim = sy.*ylim; 144 | [X,Y] = meshgrid(xlim(1):xlim(end),ylim(1):ylim(end)); % X,Y是无畸变缩放图像像素点,当sx,sy小于1,从而减少X,Y数量,提高插值速度 145 | X = X./sx; 146 | Y = Y./sy; 147 | undistortD = sqrt((X-U0).^2+(Y-V0).^2); 148 | distortD = interp1(refHeight,realHeight,undistortD,"linear",refHeight(end));% 以1维插值代替查表操作 149 | mapX = (X-U0).*distortD./(undistortD+eps)+cx;% 避免除数为0 150 | mapY = (Y-V0).*distortD./(undistortD+eps)+cy;% 避免除数为0 151 | 152 | undistortImg = images.internal.interp2d(oriImg,mapX,mapY,... 153 | "linear",255, false);% 与生成的C代码mex文件一样的执行速度 154 | 155 | % 等价的pinhole camera intrinsics 156 | focalLen = [sx,sy].*flength; 157 | principlePoint = [sx,sy].*principlePt; 158 | % imageSize = size(undistortImg,[1,2]); 159 | % camIntrinsic = cameraIntrinsics(focalLen,principlePoint,imageSize); 160 | 161 | camIntrinsic = [focalLen(1),0,principlePoint(1); 162 | 0,focalLen(2),principlePoint(2); 163 | 0,0,1]; 164 | end 165 | -------------------------------------------------------------------------------- /深入洞察 OpenCV 鱼眼模型之成像投影和畸变表估计系数相互转化.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cuixing158/OpenCVFisheyeAndDistortionTable/24627473c1e41f4875765956933ca825f530acb2/深入洞察 OpenCV 鱼眼模型之成像投影和畸变表估计系数相互转化.pdf --------------------------------------------------------------------------------