Tkinter和opencv绘制动态图像

一、目标

将opencv绘制的动态图像,显示在Tkinter的界面内。如下图所示:
Tkinter和opencv绘制动态图像_第1张图片

二、主要问题

1、显示问题

绘制opencv图像后,利用Label组件的image属性进行图像显示。主要代码如下:

cv2image = cv.cvtColor(temp, cv.COLOR_BGR2RGBA)  # 将cv2的BGR颜色转换到RGBA
current_image = Image.fromarray(cv2image)        # 将图像转换成Image对象
imgtk = ImageTk.PhotoImage(image=current_image)
imgLabel.config(image=imgtk)                     # 图像显示

这里的imgLabel就是提前定义的Label组件。

2、动态更新图像

为了动态更新图像,再每次延时后,重新定义Label组件,然后再次进行图像显示。主要代码如下:

if imgLabel: # 每次刷新时,forget原imgLabel
   imgLabel.pack_forget()
imgLabel = Label(root)
imgLabel.place(x=0, y=50, width=700, height=700)

3、定时问题

定时更新图像使用after()函数,用于定时刷新tkinter组件。代码为:

imgLabel.after(500, change_Img)                  # 延时0.5秒,再次调用本函数

这里的change_Img是动态绘制opencv图像的函数。
定时刷新存在递归深度的限制,就是循环一定次数之后,程序会自动跳出,可以更改递归深度。代码为:

sys.setrecursionlimit(10000) # 递归深度设置,默认1000就会报错

4、mainloop()的位置

本程序中,root.mainloop()必须放在change_Img()函数里面,否则图像也不会显示。

三、完整代码

完整代码如下:

import cv2 as cv
import numpy as np
from tkinter import *
from PIL import Image,ImageTk
import sys # 用于设置递归深度

sys.setrecursionlimit(10000) # 递归深度设置,默认1000就会报错
root = Tk()
root.title("tkinter + opencv")
root.geometry('700x750')

Label(root, text = 'tkinter & oencv动态示例').place(x=0, y=0, width=700, height=50)
imgLabel = Label(root)  # 初始化opencv图形放置的控件imgLabel

# 绘制雷达底图
radarCanvas = np.zeros((700, 700, 3), np.uint8)
point_size = 1
white = (255, 255, 255)
red = (0, 0, 255)
blue = (255, 0, 0)
yellow = (0, 255, 255)
cv.circle(radarCanvas, (350, 350), 100, white, 2)
cv.circle(radarCanvas, (350, 350), 200, white, 2)
cv.circle(radarCanvas, (350, 350), 300, white, 2)
cv.line(radarCanvas, (50, 350), (650, 350), white, 2)
cv.line(radarCanvas, (350, 50), (350, 650), white, 2)
start_point = (int(350 - 300 * np.sin(0.25 * np.pi)), int(350 - 300 * np.sin(0.25 * np.pi)))
end_point = (int(350 + 300 * np.sin(0.25 * np.pi)), int(350 + 300 * np.sin(0.25 * np.pi)))
cv.line(radarCanvas, start_point, end_point, white, 1)
start_point = (int(350 - 300 * np.sin(0.25 * np.pi)), int(350 + 300 * np.sin(0.25 * np.pi)))
end_point = (int(350 + 300 * np.sin(0.25 * np.pi)), int(350 - 300 * np.sin(0.25 * np.pi)))
cv.line(radarCanvas, start_point, end_point, white, 1)
font = cv.FONT_HERSHEY_SIMPLEX
cv.putText(radarCanvas, "N", (340, 40), font, 1, (255, 255, 255), 1)
cv.putText(radarCanvas, "30", (5, 360), font, 1, (255, 255, 255), 1)
cv.putText(radarCanvas, "30", (650, 360), font, 1, (255, 255, 255), 1)
cv.putText(radarCanvas, "Speed(m/s):", (500, 15), font, 0.5, (255, 255, 255), 1)
cv.putText(radarCanvas, "Rotation:", (530, 35), font, 0.5, (255, 255, 255), 1)
cv.putText(radarCanvas, "Coordinate(X):", (488, 55), font, 0.5, (255, 255, 255), 1)
cv.putText(radarCanvas, "Coordinate(Y):", (488, 75), font, 0.5, (255, 255, 255), 1)

# 运动目标参数
beta = 225 / 180 * np.pi   # 飞行方位角
speed = 300                # 飞行速度
pointStartX = 500          # 初始点坐标
pointStartY = 10
delteT = 1                 # 运动参数转换比例

i = 0


# 雷达动态扫描函数
def change_Img():
    global beta
    global speed
    global pointStartX
    global pointStartY
    global delteT

    pointStartX += int(speed * delteT * 0.01 * np.cos(beta))
    pointStartY += -int(speed * delteT * 0.01 * np.sin(beta))

    global imgLabel
    if imgLabel: # 每次刷新时,forget原imgLabel
        imgLabel.pack_forget()
    imgLabel = Label(root)
    imgLabel.place(x=0, y=50, width=700, height=700)

    global i
    i += 1

    cv.circle(radarCanvas, (pointStartX, pointStartY), 1, (0, 255, 255), 1)
    temp = np.copy(radarCanvas)
    cv.circle(temp, (pointStartX, pointStartY), 1, ( 0, 0, 255 ), 6)
    font = cv.FONT_HERSHEY_SIMPLEX
    cv.putText(temp, str(speed), (605, 15), font, 0.5, (0, 255, 0), 1)
    cv.putText(temp, str(beta / np.pi * 180), (605, 35), font, 0.5, (0, 255, 0), 1)
    cv.putText(temp, str(pointStartX), (605, 55), font, 0.5, (0, 255, 0), 1)
    cv.putText(temp, str(pointStartY), (605, 75), font, 0.5, (0, 255, 0), 1)
    cv2image = cv.cvtColor(temp, cv.COLOR_BGR2RGBA)  # 将cv2的BGR颜色转换到RGBA
    current_image = Image.fromarray(cv2image)        # 将图像转换成Image对象
    imgtk = ImageTk.PhotoImage(image=current_image)
    imgLabel.config(image=imgtk)                     # 图像显示
    imgLabel.after(500, change_Img)                  # 延时0.5秒,再次调用本函数
    root.mainloop() # gui线程里要尽快执行完工作返回消息机制里,如果把这句写在函数外面,则图像不会显示

change_Img()

你可能感兴趣的:(python学习,python,opencv)