tkinter写一个相机标定工具

效果

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


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Tkinter一个 Python 的图形用户界面(GUI)库,可以用来开发扑克牌游戏。要一个扑克牌游戏,你需要了解 Tkinter 的基本知识,包括创建窗口、放置按钮和图片等元素。 下面是一个简单的例子,演示了如何在 Tkinter 中创建一个扑克牌游戏: ``` import tkinter as tk class PokerGame(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) self.title("扑克牌游戏") self.geometry("400x400") self.resizable(False, False) self.create_widgets() def create_widgets(self): label = tk.Label(self, text="这是一张扑克牌", font=("Arial", 16)) label.pack() image = tk.PhotoImage(file="card.png") image_label = tk.Label(self, image=image) image_label.pack() if __name__ == "__main__": app = PokerGame() app.mainloop() ``` 这个例子创建了一个带有文字和图像的窗口,你可以根据需要添加更多元素来完善你的扑克牌游戏。 ### 回答2: 扑克牌是一种常见的纸牌游戏,可以使用Python编程语言中的tkinter库来实现一个简单的扑克牌游戏。下面是一个大致的实现思路: 首先,可以创建一个窗口和画布来进行游戏界面的展示。使用tkinter创建游戏窗口,并在窗口上添加画布组件,画布用来展示扑克牌的图像。 其次,可以创建一个Card类来表示一张扑克牌。Card类包含属性(如花色和牌面值)和方法(如绘制和翻牌)来处理扑克牌的操作。 然后,可以创建一个Deck类来表示一副扑克牌。Deck类包含一个Card对象列表,用来表示一副完整的扑克牌。Deck类包含方法来洗牌、发牌和收回牌等操作。 接着,可以创建一个Player类来表示玩家。Player类可以包含一个手牌列表和方法来处理玩家的操作,如抽牌、出牌和判断牌面等。 最后,可以创建一个Game类来控制整个游戏的流程。Game类可以包含一个Deck对象、若干个Player对象和一些游戏逻辑的方法,如开始游戏、判断胜负等。 在游戏界面上,可以使用画布来展示扑克牌的图像,并通过按钮或键盘事件来触发玩家的动作。玩家的手牌可以在游戏界面上显示,根据游戏规则判断胜负并进行游戏结果的展示。 以上是一个扑克牌游戏的大致实现思路,可以根据实际需求和具体规则进行具体的编码和设计。通过利用tkinter库和相关的类和方法,我们可以实现一个基本的扑克牌游戏。 ### 回答3: 扑克牌是一种非常经典和有趣的牌类游戏。TkinterPython编程语言的一个GUI库,提供了创建图形界面的功能。 要使用Tkinter一个扑克牌游戏,首先需要了解扑克牌的规则和玩法。然后,我们可以使用Tkinter创建一个窗口,用于显示游戏界面。在窗口中,我们可以布置一些扑克牌的图像和按钮。 游戏开始时,可以通过按钮或者其他方式进行洗牌,并将扑克牌发给玩家和电脑。玩家可以选择要保留的牌,然后再次发牌。在游戏的过程中,可以通过按钮实现玩家和电脑的操作,如选择出牌、跟牌、抢地主等。 为了实现这个游戏,我们需要使用Tkinter提供的组件和功能来构建游戏界面。可以使用Canvas组件来显示扑克牌的图像,使用Button组件来实现按钮的点击操作,使用Label组件显示分数和游戏信息等。 在游戏的过程中,可以使用Tkinter提供的事件处理机制来处理按钮的点击事件和鼠标的点击事件。通过编逻辑代码,可以实现扑克牌的洗牌、发牌、比较大小、计算得分等功能。 总结起来,使用Tkinter一个扑克牌游戏需要实现以下几个步骤:了解扑克牌的规则和玩法、创建游戏窗口、布置游戏界面、编按钮和事件处理代码、实现游戏的逻辑功能。 通过以上步骤,我们可以使用Tkinter一个简单的扑克牌游戏,并且随着对Tkinter的进一步学习和掌握,可以添加更多的功能和特性,使游戏变得更加完善和精彩。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值