效果
1.标定
2.矫正
说明
对单张标定板图像进行标定,填写标定板角点分布、黑白格子尺寸,标定结果自动保存为DTU数据集格式。标定完成后,可以对同一视角拍摄的图像进行矫正,矫正结果自动保存。
代码
#coding=utf-8
import cv2,os
import numpy as np
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk,Image
class CalibUI():
def __init__(self,save_path="output",wide=800, height=500):
self.W, self.H = wide, height
self.button_w, self.button_h = 50, 30
self.button_hstretch,self.button_wstretch=10,10
self._init_root()
self.calib_tool = None
self.save_path=save_path
os.makedirs(self.save_path, exist_ok=True)
def run(self):
self.root.mainloop()
def _init_root(self,):
# creat window
self.root=tk.Tk()
self.root.title("camera calib")
self.root.config(background="white")
self.root.geometry(str(self.W) + "x" + str(self.H) + "-500-200")
self.root.resizable(0, 0)
#self.root.iconbitmap("./image/icon.ico")
self.root.attributes("-alpha", 0.95)
"""left area"""
# creat video area
self.left_w, self.left_h= int(3 / 4 * self.W), int(self.H)
self.photo_area = tk.Label(self.root, bg="black", fg="green", cursor="cross")
self.photo_area.place(x=1, y=1, w=self.left_w, h=self.left_h - 35)
# state area
self.state_area = tk.Label(self.root, text="----------------")
self.state_area.place(x=1, y=self.left_h - 32, w=self.left_w, h=30)
"""right area"""
right_x, right_y = self.left_w + 20, 7 / 11 * self.H
# the area output the calib info
self.text_area = tk.Text(self.root,wrap=None,bg="black",fg='green',relief="flat",font=("楷体",12))
self.text_area.place(x=self.left_w + 5, y=1, w=self.W - self.left_w - 10, h=right_y)
# entry
tk.Label(self.root, text="标定板参数:", bg="white", justify="left") \
.place(x=right_x, y=right_y +5, w=60, h=20)
tk.Label(self.root, text="分布", bg="white", justify="left") \
.place(x=right_x, y=right_y +25, w=30, h=self.button_h)
self.input_rc = tk.Entry(self.root, bd=5, relief="groove")
self.input_rc.place(x=right_x+30, y=right_y +25, w=100, h=self.button_h)
self.input_rc.insert(1,"8 6")
tk.Label(self.root, text="尺寸", bg="white", justify="left") \
.place(x=right_x, y=right_y +55, w=30, h=self.button_h)
self.input_square = tk.Entry(self.root, bd=5, relief="groove")
self.input_square.place(x=right_x+30, y=right_y +55, w=100, h=self.button_h)
self.input_square.insert(1,"20 20")
#button
tk.Button(self.root, text=" 标定", relief="groove", command=self._calib)\
.place(x=right_x+15, y= right_y+100, w=self.button_w, h=self.button_h)
tk.Button(self.root, text="矫正", relief="groove", command=self._rectify)\
.place(x=right_x+15+self.button_w+self.button_wstretch, y= right_y+100, w=self.button_w, h=self.button_h)
#
def _calib(self):
# 获取标定板参数
pattern_rc = tuple(int(x) for x in self.input_rc.get().split(" "))
pattern_square = tuple(int(x) for x in self.input_square.get().split(" "))
self.calib_tool = CalibTool(pattern_rc, pattern_square)
file=filedialog.askopenfilename()
filename=file.split(".")[0].split("/") [-1] # os.sep is incorrect
self._set_img(img=self._open_img(file))
C, dist, R, T, corners_img=self.calib_tool.calib(img=self._open_img(file))
self._set_img(img=corners_img)
save_location = os.path.join(self.save_path, filename.split(".")[0] + ".txt")
content=self.calib_tool.save_paras(save_location,other="425 2.5")
self.text_area.delete(1.0, 'end') # 清空再插入
self.text_area.insert(1.0,content)
self.state_area.config(text="save paras to:"+save_location)
self.state_area.update()
def _rectify(self):
file=filedialog.askopenfilename()
filename=file.split(".")[0].split("/") [-1] # os.sep is incorrect
save_location = os.path.join(self.save_path, filename.split(".")[0] + ".bmp")
self._set_img(img=self._open_img(file))
rectify_img=self.calib_tool.rectify(self._open_img(file), save_location)
self._set_img(img=rectify_img)
self.state_area.config(text="save rectify img to:"+save_location)
self.state_area.update()
# 使能读取中文名称图片
def _open_img(self,img_path):
return cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), cv2.IMREAD_COLOR)
# convert frame to tk img and show
def _set_img(self,img):
h, w, _ = img.shape
wc ,hc= self.left_w,int(h * (self.left_w / w))
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
current_image = Image.fromarray(img, "RGB").resize((wc, hc), Image.ANTIALIAS)
img = ImageTk.PhotoImage(image=current_image)
self.photo_area.config(image=img)
self.photo_area.image=img
""""""
class CalibTool():
def __init__(self,pattern_rc = (8, 6),pattern_square = (20, 20)):
self.pattern_rc=pattern_rc
self.pattern_r,self.pattern_c = pattern_rc # 角点行列数
self.pattern_width,self.pattern_height = pattern_square # 黑白方块的大小
self.subpix_region_size = (11, 11)
self.C,self.dist,self.R,self.T=None,None,None,None #内参、畸变、旋转矩阵,平移向量
def _makeWorldPoints(self):
world_points=[]
for h in range(self.pattern_c): # h->y
for w in range(self.pattern_r): # w->x
world_points.append([w*self.pattern_width, h*self.pattern_height ,0]) # [x,y,z] :notice x is horizontal axis
return np.array(world_points,dtype=np.float32) # notice the dtype
def _getCorners(self,img):
ret,corners=cv2.findChessboardCorners(img, self.pattern_rc, None)
img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,corners=cv2.find4QuadCornerSubpix(img_gray,corners,self.subpix_region_size)
cv2.drawChessboardCorners(img, self.pattern_rc, corners, ret)
return np.array(corners, dtype=np.float32),img
def calib(self,img):
img_size=[img.shape[1], img.shape[0]]
world_pointss,cornerss=[],[]
world_points=self._makeWorldPoints()
corners,corners_img=self._getCorners(img)
world_pointss.append(world_points)
cornerss.append(corners)
ret, C, dist, R_vecs, T_vecs = cv2.calibrateCamera(world_pointss, cornerss, img_size, None, None)
if ret:
R,J=cv2.Rodrigues(R_vecs[0])
self.C, self.dist, self.R, self.T = C, dist[0], R, T_vecs[0]
return C, dist[0], R, T_vecs[0],corners_img
else:
print("calib occur error.")
def save_paras(self,save_location,other="425 2.5"):
RT=np.c_[self.R,self.T]
RT_=np.r_[RT,[[0,0,0,1],]]
content="extrinsic"+"\n"
for r in RT_:
for i in r:
content+=str(i)+" "
content+="\n"
content+="\n"+"intrinsic"+"\n"
for r in self.C:
for i in r:
content += str(i) + " "
content+="\n"
content+="\n"+other
with open(save_location,"w") as f:
f.write(content)
return content
def rectify(self,img,save_location):
rectify_img = cv2.undistort(img, self.C, self.dist, None, self.C)#cv2.getOptimalNewCameraMatrix(C, dist, img_size, 1, img_size, 0)[0]
cv2.imwrite(save_location, rectify_img)
return rectify_img
if __name__=="__main__":
cui=CalibUI()
cui.run()
"""test calibtool"""
# """
# input
# """
# input_dir="input"
# filename="view3_38.bmp"
# file = os.path.join(input_dir, filename)
#
# ct=CalibTool()
# C, dist, R, T,corners_img=ct.calib(img=cv2.imread(file))
# print("内参矩阵:\n",C)
# print("畸变矩阵:\n",dist)
# print("旋转矩阵:\n",R)
# print("平移矩阵:\n",T)
# cv2.imshow("d",corners_img)
# cv2.waitKey(0)
#
# output_dir="output"
# save_location=os.path.join(output_dir,filename.split(".")[0]+".txt")
# ct.save_paras(save_location)
#
# filename="view3_26.bmp"
# img_file=os.path.join(input_dir, filename)
# save_location=os.path.join(output_dir,filename.split(".")[0]+".bmp")
# rectify_img=ct.rectify(cv2.imread(img_file),save_location)
# cv2.imshow("d",rectify_img)
# cv2.waitKey(0)
# exit()