一:主要参数说明
1:内参矩阵K
是3*3的矩阵,其类似格式
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 360.7886749292513],
[0.0, 0.0, 1.0]])
2:畸变系数
针对鱼眼相机:为1*4的数组,格式如下:
D=np.array([[0.0590137867946409], [-0.030903466430950866], [0.002123587326450784], [-1.851242815594123e-05]])
rms 0.18562501602552903
二:畸变表
这个文摄像头的镜头场景
1:焦距
2:镜头尺寸
三:参考连接
https://github.com/792864625/AroundViewMonitor-China-Developer/tree/d664bf75a8c43bb52bf69a71c420b31cbefa5a07?tab=readme-ov-file
https://www.eet-china.com/mp/a213856.html
https://blog.csdn.net/Yong_Qi2015/article/details/130299413?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-4-130299413-blog-108095636.235^v43^pc_blog_bottom_relevance_base2&spm=1001.2101.3001.4242.3&utm_relevant_index=7
四:实际测试
import cv2
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import os
from simple_gui import display_image, PointSelector
from math import radians
import argparse
# 在这里修改各参数值
parser = argparse.ArgumentParser(description="Fisheye Camera Undistortion")
parser.add_argument('-width', default=1280, type=int, help='Camera Frame Width')
parser.add_argument('-height', default=720, type=int, help='Camera Frame Height')
parser.add_argument('-load', default=False, type=bool, help='Load New Camera K/D Data (True/False)')
'''
parser.add_argument('-path_read', default='./data/ligong/', type=str, help='Original Image Read Path')
parser.add_argument('-path_save', default='./data/ligong/', type=str, help='Undistortion Image Save Path')
'''
parser.add_argument('-path_read', default='./data/orig_3_3_npy_data/', type=str, help='Original Image Read Path')
parser.add_argument('-path_save', default='./data/orig_3_3_npy_data/', type=str, help='Undistortion Image Save Path')
parser.add_argument('-path_k', default='./KD_01/camera_1_K.npy', type=str, help='Camera K File Path')
parser.add_argument('-path_d', default='./KD_01/camera_1_D.npy', type=str, help='Camera D File Path')
parser.add_argument('-focalscale', default=1, type=float, help='Camera Undistortion Focal Scale')
parser.add_argument('-sizescale', default=2, type=float, help='Camera Undistortion Size Scale')
parser.add_argument('-offset_h', default=0, type=float, help='Horizontal Offset of Optical Axis')
parser.add_argument('-offset_v', default=0, type=float, help='Vertical Offset of Optical Axis')
parser.add_argument('-srcformat', default='npy', type=str, help='Original Image Format (jpg/png)')
parser.add_argument('-dstformat', default='jpg', type=str, help='Final Image Format (jpg/png)')
parser.add_argument('-quality', default=100, type=int, help='Save Image Quality (jpg:0-100, png:9-0 (low-high))')
parser.add_argument('-name', default=None, type=str, help='Save Image Name')
args = parser.parse_args()
#https://github.com/792864625/AroundViewMonitor-China-Developer/tree/d664bf75a8c43bb52bf69a71c420b31cbefa5a07?tab=readme-ov-file
#https://www.eet-china.com/mp/a213856.html
#https://blog.csdn.net/Yong_Qi2015/article/details/130299413?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-4-130299413-blog-108095636.235^v43^pc_blog_bottom_relevance_base2&spm=1001.2101.3001.4242.3&utm_relevant_index=7
#用来描述每个像素在实际世界中代表多少毫米。换句话说,它告诉我们在图像中每个像素的大小对应于实际场景中多大的长度。
sensorRatio = 0.003 #;% 由厂家提供,单位 mm/pixel
sensorRatio=0.0029 #这个值应该是正确的值
sensorRatio_cm=1
sensorH=3.876/720
sensorW=5.138/1280
sensorW=sensorRatio
sensorW=sensorRatio
#下面的参数是当前可以的
sensorH=3.876/1080 #0.00358888888888888888888888888889
sensorW=5.138/1920 #0.00267604166666666666666666666667
sensorH=sensorRatio #0.00358888888888888888888888888889
'''
下面是通过棋盘格校准而来,在最终的校准参数中,使用给了棋盘校准的畸变系数参数
Found 541 valid images for calibration
DIM=(1280, 720)
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 361.7886749292513],
[0.0, 0.0, 1.0]])
D=np.array([[0.0590137867946409], [-0.030903466430950866], [0.002123587326450784], [-1.851242815594123e-05]])
rms 0.18562501602552903
下面是通过畸变表计算而来
0.06244240163136363,-0.03908688528398631,0.006663506063585303,-0.0009067163647851509
[[479.34904735 0. 768. ]
[ 0. 642.86385797 432. ]
[ 0. 0. 1. ]]
畸变焦距 = 1.71781
畸变焦距 = 1.72033
畸变焦距 = 1.71520
上面三个平均值为:1.71778
根据目前的测试结果,畸变系数从肉眼上面看不来有什么差异
1:配置参数
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 360.7886749292513],
[0.0, 0.0, 1.0]])
其中focal=1.7,sensorW=sensorRatio=0.0029
K = np.array([[389.2109574522624, 0, w/2 ],
[0, focal / sensorW, h/2 ],
[0, 0, 1]])
opencvCoeffs = np.array([[0.09780962], [-0.07203037], [0.01673093], [-0.0017944 ]], dtype=np.float64) # 来自畸变表
2:配置参数
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 360.7886749292513],
[0.0, 0.0, 1.0]])
opencvCoeffs = np.array([[0.0590137867946409], [-0.030903466430950866], [0.002123587326450784], [-1.851242815594123e-05]], dtype=np.float64) # 这个来自450张照片校准生成的。
3: 配置参数
newCameraMatrixK6=np.array([
[289.67227465, 0.0, w/2],
[0.0, 558.505701978078, h/2],
[0.0, 0.0, 1.0]])
opencvCoeffs = np.array([[0.09780962], [-0.07203037], [0.01673093], [-0.0017944 ]], dtype=np.float64) # 来自畸变表
其实主要更改的参数是:内参矩阵的
k[0][0] 和 k[1][1]
'''
distortionTablePath = "./data/distorti_table/distortionTable.xlsx"
distortionTablePath = "./data/distorti_table/backupDistortionTable.xlsx"
distortionTablePath = "./data/distorti_table/3.xlsx"
def manual_select_point(img,cam_id):
radius = 1
color = (0, 0, 255) # BGR格式,红色
thickness = 2
pts_dir = args.path_read
camera_file = os.path.join(pts_dir, 'cam'+cam_id + '_dst_point.npy')
point_corners=[]
if os.path.exists(camera_file):
print("load dst point from ",camera_file)
dst_corners = np.load(camera_file)
print("dst_corners",dst_corners)
else:
gui = PointSelector(img, title="cam"+cam_id)
choice = gui.loop()
if choice > 0:
point_corners = np.float32(gui.keypoints)
print(point_corners)
print(len(point_corners))
cam_pts = np.array(point_corners, dtype=np.float32)
np.save(camera_file, cam_pts)
cnt=0
for index in range(len(point_corners)):
x, y = point_corners[index]
color = (0, 0, 255) # BGR格式,红色
cv2.putText(img, str(cnt), (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 1,color, thickness)
color = (0, 255, 255) # BGR格式,红色
cv2.circle(img,(int(x),int(y)), radius, color, thickness)
cameraData = pd.read_excel(distortionTablePath)
#print(cameraData)
#print(type(cameraData))
# 如果表格有多个 sheet,可以用 sheet_name='Sheet1' 指定具体的 sheet 名称
# 假设我们读取的是第一个 sheet,根据 MATLAB 代码推测,数据从第四行开始
cameraData = cameraData.iloc[0:101, :]
print(cameraData)
angleIn = cameraData.iloc[:, 0].values # 入射角列
print(angleIn)
theta_input = np.radians(angleIn)
focal = np.mean(cameraData.iloc[:, 2].values / np.tan(theta_input)) # 计算焦距
print("focal:",focal)
distortFrame = np.load("./data/orig_3_3_npy_data/img_cam4.npy")
def test_measure_distance():
shift_h=1000
shift_w=1000
cam2_world_point = np.array([
[0.+shift_h, 200.+shift_w],
[200.+shift_h, 200.+shift_w],
[ 0.+shift_h, 960.+shift_w],
[ 200.+shift_h, 960.+shift_w],
]).astype(np.int32)
cam2_img_point = np.array([
[1166.*sensorRatio_cm, 419.*sensorRatio_cm],
[1233.*sensorRatio_cm, 530.*sensorRatio_cm],
[1096.*sensorRatio_cm, 422.*sensorRatio_cm],
[1191.*sensorRatio_cm, 578.*sensorRatio_cm],
[ 349.*sensorRatio_cm, 381.*sensorRatio_cm],
[ 216.*sensorRatio_cm, 505.*sensorRatio_cm],
[ 271.*sensorRatio_cm,369.*sensorRatio_cm],
[ 171.*sensorRatio_cm,456.*sensorRatio_cm]
]).astype(np.float64)
shift_h=200
shift_w=200
cam2_world_point = np.array([
[0.+shift_h, 0.+shift_w],
[200.+shift_h, 0.+shift_w],
[0.+shift_h, 200.+shift_w],
[200.+shift_h, 200.+shift_w],
[ 0.+shift_h, 940.+shift_w],
[ 200.+shift_h, 940.+shift_w],
[ 0.+shift_h,1140.+shift_w],
[ 200.+shift_h,1140.+shift_w]
]).astype(np.int32)
cam2_img_point = np.array([
[1096.*sensorRatio_cm, 422.*sensorRatio_cm],
[1191.*sensorRatio_cm, 578.*sensorRatio_cm],
[ 349.*sensorRatio_cm, 381.*sensorRatio_cm],
[ 216.*sensorRatio_cm, 505.*sensorRatio_cm],
]).astype(np.float64)
cam2_img_point = np.array([
[[1167. , 419.],
[1234. , 532.],
[ 271. , 370.],
[ 173. , 454.]]
]).astype(np.float64)
cam2_img_point = np.array([
[[1137. , 402.],
[1264. , 574.],
[ 256. , 336.],
[ 10. , 477.]]
]).astype(np.float64)
cam2_undistortImg2 = cv2.imread("./data/ligong/cam2_undistortImg2.jpg")
cam_id='2'
manual_select_point(distortFrame,cam_id)
print("distortFrame.shape",cam2_undistortImg2.shape)
H, _ = cv2.findHomography(cam2_img_point, cam2_world_point,method = cv2.RANSAC)
holog = cv2.warpPerspective(cam2_undistortImg2, H, (1140*4, 1080*3))
print(holog.shape)
surround_n=cv2.resize(holog,(720,1280))
dstMap = cv2.rotate(surround_n, cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imshow("camera_homography_vir_1_H", dstMap)
h, w, _ = distortFrame.shape # 获取图像高度和宽度
K = np.array([[focal / sensorRatio, 0, w / 2],
[0, focal / sensorRatio, h / 2],
[0, 0, 1]])
K = np.array([[focal / sensorH, 0,w *3/ 5 ],
[0, focal / sensorW, h *3/ 5 ],
[0, 0, 1]])
r_d = 1. / focal * cameraData.iloc[:, 1].values # 求归一化平面上的 r_d
thetaRadian = np.radians(angleIn) # 度数转为弧度
A = np.column_stack([thetaRadian**3, thetaRadian**5, thetaRadian**7, thetaRadian**9])
b = r_d - thetaRadian
opencvCoeffs = np.linalg.lstsq(A, b, rcond=None)[0]
focal=1.7
K = np.array([[focal / sensorH, 0,630.2525667489842 ],
[0, focal / sensorW, 400.7886749292513 ],
[0, 0, 1]])
K = np.array([[focal / sensorH, 0,w*2/5 ],
[0, focal / sensorW, h*2/5 ],
[0, 0, 1]])
K = np.array([[focal / sensorH, 0,730.2525667489842 ],
[0, focal / sensorW, 730.7886749292513 ],
[0, 0, 1]])
if 1==1:
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 400.7886749292513],
[0.0, 0.0, 1.0]])
K = np.array([[focal / sensorH, 0,w*3/5 ],
[0, focal / sensorW, h*3/5 ],
[0, 0, 1]])
K = np.array([[focal / sensorH,0, w/2 ],
[0, focal / sensorW, h/2 ],
[0, 0, 1]])
K = np.array([[focal / sensorH,0, w/2 ],
[0, focal / sensorW, h/2 ],
[0, 0, 1]])
K = np.array([[focal / sensorH, 0,w/2 ],
[0, focal / sensorW, h*2/5 ],
[0, 0, 1]])
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 360.7886749292513],
[0.0, 0.0, 1.0]])
K = np.array([[focal / sensorH, 0,630.2525667489842 ],
[0, focal / sensorW, 360.7886749292513 ],
[0, 0, 1]])
K = np.array([[389.2109574522624, 0, w/2 ],
[0, focal / sensorW, h/2 ],
[0, 0, 1]])
opencvCoeffs = np.array([[0.09780962], [-0.07203037], [0.01673093], [-0.0017944 ]], dtype=np.float64) # 来自畸变表
newCameraMatrixK = K.copy()
newImageSize = distortFrame.shape[:2] # 假设 distortFrame 是已定义的畸变图像
newCameraMatrixK[0][0]*=0.55 #控制X方向显示多少
newCameraMatrixK[1][1]*=0.90
newCameraMatrixK6=np.array([
[289.67227465, 0.0, w/2],
[0.0, 558.505701978078, h/2],
[0.0, 0.0, 1.0]])
#===========================================================================================================
else:
'''
下面的是中间压缩,类似之前程彪校准的,左右比较模糊,但是实际中进行透视变化后,比较直
'''
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 400.7886749292513],
[0.0, 0.0, 1.0]])
K=np.array([
[389.2109574522624, 0.0, w/2],
[0.0, 388.505701978078, h/2],
[0.0, 0.0, 1.0]])
######################################################################################
K=np.array([
[389.2109574522624, 0.0, 630.2525667489842],
[0.0, 388.505701978078, 360.7886749292513],
[0.0, 0.0, 1.0]])
opencvCoeffs = np.array([[0.0590137867946409], [-0.030903466430950866], [0.002123587326450784], [-1.851242815594123e-05]], dtype=np.float64) # 这个来自450张照片校准生成的。
# 假设接下来的部分中的函数和变量定义,需要根据具体情况修改
#newCameraMatrixK = K # 假设 K 是已定义的新相机矩阵
newCameraMatrixK = K.copy()
newImageSize = distortFrame.shape[:2] # 假设 distortFrame 是已定义的畸变图像
newCameraMatrixK[0][0]*=0.35 #控制X方向显示多少,值越小,显示校准后的区域越大
newCameraMatrixK[1][1]*=0.72
newImageSize = newImageSize[::-1]
print(opencvCoeffs)
print("最小二乘拟合 OpenCV 鱼眼模型畸变系数为(k1~k4):" + ",".join(map(str, opencvCoeffs)))
print("K",K)
print("newCameraMatrixK:",newCameraMatrixK)
print("newImageSize:",newImageSize)
balance=0
newCameraMatrixK1 = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, opencvCoeffs, newImageSize, np.eye(3), balance=balance)
print("newCameraMatrixK1:",newCameraMatrixK1)
balance=1
newCameraMatrixK2 = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, opencvCoeffs, newImageSize, np.eye(3), balance=balance)
print("newCameraMatrixK2:",newCameraMatrixK2)
balance=0.1
newCameraMatrixK3 = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, opencvCoeffs, newImageSize, np.eye(3), balance=balance)
print("newCameraMatrixK3:",newCameraMatrixK3)
balance=0.3
newCameraMatrixK4 = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, opencvCoeffs, newImageSize, np.eye(3), balance=balance)
print("newCameraMatrixK4:",newCameraMatrixK4)
balance=0.5
newCameraMatrixK5 = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, opencvCoeffs, newImageSize, np.eye(3), balance=balance)
print("newCameraMatrixK5:",newCameraMatrixK5)
balance=0.7
newCameraMatrixK6 = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, opencvCoeffs, newImageSize, np.eye(3), balance=balance)
print("newCameraMatrixK6:",newCameraMatrixK6)
base_newCameraMatrixK6=np.array([
[289.67227465, 0.0, w/2],
[0.0, 458.505701978078, h/2],
[0.0, 0.0, 1.0]])
newCameraMatrixK7=np.array([
[250.67227465, 0.0, w/2],
[0.0, 558.505701978078, h/2],
[0.0, 0.0, 1.0]])
print(newCameraMatrixK6)
R = np.eye(3, dtype=np.float64)
mapX, mapY = cv2.fisheye.initUndistortRectifyMap(K, opencvCoeffs, R, newCameraMatrixK, newImageSize, cv2.CV_16SC2)
mapX, mapY = cv2.fisheye.initUndistortRectifyMap(K, opencvCoeffs, R, newCameraMatrixK7, (w,h), cv2.CV_16SC2)
undistortImg2 = cv2.remap(distortFrame, mapX, mapY, cv2.INTER_LINEAR)
undistortImg2 = cv2.remap(distortFrame, mapX, mapY, cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=255)
print(undistortImg2.shape)
cv2.imshow("img",distortFrame)
cv2.imshow("undistortImg2",undistortImg2)
cv2.imwrite('cam2_undistortImg2.jpg', undistortImg2)
cv2.waitKey(0)
indices = np.indices((720, 1280), dtype=np.float32)
indices = np.stack((indices[1], indices[0], np.zeros((720, 1280))), axis=-1).astype(np.float64)
indices = cv2.remap(indices, mapX, mapY, interpolation=cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT, borderValue=-1)
position=1
map_dict = np.array(indices[:, :, :-1], dtype=np.float32)
while True:
if cv2.waitKey(10) & 0xFF == ord('q'):
filenames = os.listdir(args.path_read) # 在argparse中修改图片路径
index = 1
for filename in filenames:
if filename[-4:] == '.' + args.srcformat:
all_name=args.path_read + filename
img = np.load(all_name)
cv2.imwrite(args.path_save + filename[:-4] + '_orig_distort.jpg', img, [cv2.IMWRITE_PNG_COMPRESSION, args.quality])
print(filename)
print(all_name)
undistort_img = cv2.remap(img, mapX, mapY, cv2.INTER_LINEAR)
np.save('%sF_cam%s.npy' % ("./fisheye_k_d/", index), map_dict)
index+=1
print(undistort_img.shape)
print(img.shape)
if args.dstformat == 'jpg':
print("save")
cv2.imwrite(args.path_save + filename[:-4] + '.jpg', undistort_img, [cv2.IMWRITE_JPEG_QUALITY, args.quality])
elif args.dstformat == 'png':
cv2.imwrite(args.path_save + filename[:-4] + '.png', undistort_img, [cv2.IMWRITE_PNG_COMPRESSION, args.quality])
else:
cv2.imwrite(filename[:-4] + '.' + args.dstformat, undistort_img)
break
'''
if __name__ == "__main__":
main()
'''
五:测试结果
1:原始图片
校准后的
不同的newCameraMatrixK7,有不同的结果