tkinter写一个相机标定工具

本文介绍了一个用于单张标定板图像标定和矫正的GUI工具。通过输入标定板的角点分布和黑白格子尺寸,工具自动执行标定并保存结果为DTU格式。此外,它还支持矫正同一视角下拍摄的图片,矫正后的图片会自动保存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果

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()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值