繁体   English   中英

使用 tkinter Canvas 显示图像,然后使用 cv2.circle/cv2.line 在图像上绘图

[英]Using a tkinter Canvas to display an image then drawing on the image using cv2.circle/cv2.line

我对 Python 比较陌生,我正在尝试使用 tkinter 构建一个 GUI,利用tkintercv2

我希望引入一个图像( tk.Canvas当前用于显示),使用tk.Entry框从用户创建组件列表,从用户输入创建单选按钮,然后使用鼠标单击在图像上绘制圆圈,每个组件都有不同的颜色。

到目前为止,我已经成功创建了tkinter window,除了在图像上绘制之外,它还可以完成上述所有操作。 我最初创建了一个单独的代码,用于将cv2.circles绘制到可以正常工作的 JPEG 上,我只是不知道如何将 tkinter GUI 链接到cv2库。

任何帮助将不胜感激,因为我找不到任何问同样问题的东西。 我附上了下面的部分代码......

最好的,乔治

function 用于选择文件路径、导入图像并在 canvas 上显示:

    def selecting_file(self):
    self.file_path = filedialog.askopenfilename()

    self.cv_img = cv2.cvtColor(cv2.imread(self.file_path), cv2.COLOR_BGR2RGB)
    self.height, self.width, self.no_channels = self.cv_img.shape


    self.canvas = tk.Canvas(self.window, width=self.width, height=self.height)
    self.canvas.pack()

    self.photo = PIL.ImageTk.PhotoImage(image=PIL.Image.fromarray(self.cv_img))

    self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)
    self.label = tk.Label(image=self.photo)
    self.label.image = self.photo

创建单选按钮然后从中获取值的函数:

    def compile_radio(self):
    self.v = tk.StringVar()
    for i in App.part_list:
        self.radio = tk.Radiobutton(self.window, text=i, variable=self.v, value=App.part_list.index(i)+1, command=self.radio_select)
        self.radio.pack()

val = 0
def radio_select(self):
    self.radio_value = self.v.get()
    self.radio_value = App.val

function 和不在此脚本中的代码允许将圆圈绘制到 cv2.imshow 上:

def draw_circle1(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
    cv2.circle(img, center = (x, y), radius = 5, color = (0,0,255), thickness = 2)
    global red_count
    red_count += 1

img = cv2.imread('IMAGE.jpg')
cv2.namedWindow(winname = 'Drawing')
cv2.setMouseCallback('Drawing', draw_circle1)

while True:
    cv2.imshow('Drawing',img)
    if cv2.waitKey(10) & 0xFF == 27:
        break
cv2.destroyAllWindows()

无需使用cv2来绘制它。 您可以为此使用tkinterPIL

首先,您必须将图像加载为普通 PIL image

self.image = Image.open(self.file_path)

self.width, self.height = self.image.size

接下来,您必须创建用于在 canvas 上显示的photodraw并保存。

self.photo = ImageTk.PhotoImage(image=self.image)

self.draw  = ImageDraw.Draw(self.image)

您可以使用tkinter到 select 放置在显示的图像上

self.canvas.bind('<Button-1>', self.draw_circle)

并运行 function 将在 canvas 上draw圆圈并在可以保存的绘制上。

# display on canvas
self.canvas.create_oval((event.x-5, event.y-5, event.x+5, event.y+5), width=2, outline='#FF0000')

# draw on self.image
self.draw.ellipse((event.x-5, event.y-5, event.x+5, event.y+5), width=2, outline=(255,0,0))

稍后您可以保存它

self.image.save('output.jpg')

顺便说一句:如果您使用Canvas来显示图像,那么您不需要使用Label


最少的工作代码。

import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk, Image, ImageDraw
        
class App():

    def __init__(self):
        self.window = tk.Tk()
        self.window.after(100, self.selecting_file)
        self.window.mainloop()

    def selecting_file(self):
        self.file_path = filedialog.askopenfilename()
        #self.file_path = filedialog.askopenfilename(initialdir='images/', initialfile='example.jpg')

        self.image = Image.open(self.file_path)
        self.width, self.height = self.image.size

        self.draw  = ImageDraw.Draw(self.image)
        self.photo = ImageTk.PhotoImage(image=self.image)
        
        self.canvas = tk.Canvas(self.window, width=self.width, height=self.height)
        self.canvas.pack()

        self.canvas.bind('<Button-1>', self.draw_circle)

        self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)

        self.save_button = tk.Button(self.window, text='Save', command=self.save)
        self.save_button.pack()

    def draw_circle(self, event):
        # display on canvas
        self.canvas.create_oval((event.x-5, event.y-5, event.x+5, event.y+5), width=2, outline='#FF0000')
        # draw on self.image
        self.draw.ellipse((event.x-5, event.y-5, event.x+5, event.y+5), width=2, outline=(255,0,0))

    def save(self):
        self.image.save('output.jpg')

# --- main ---

App()

在此处输入图像描述


编辑:

带有可更改颜色、图形和半径的按钮的版本。

在此处输入图像描述

import tkinter as tk
from tkinter import filedialog, colorchooser
from PIL import ImageTk, Image, ImageDraw


class App():

    def __init__(self):
        self.color = '#FF0000'
        self.figure = 'circle'
        self.figure = 'rectangle'
        self.size = 5
        
        self.window = tk.Tk()
        self.window.after(100, self.selecting_file)
        self.window.mainloop()

    def selecting_file(self):
        self.file_path = filedialog.askopenfilename()
        #self.file_path = filedialog.askopenfilename(initialdir='images/', initialfile='example.jpg')
            
        self.image = Image.open(self.file_path)
        self.width, self.height = self.image.size

        self.draw  = ImageDraw.Draw(self.image)
        self.photo = ImageTk.PhotoImage(image=self.image)

        self.frame_tools = tk.Frame(self.window)
        self.frame_tools.pack()
        
        self.rectangle_button = tk.Button(self.frame_tools, text='Rectangle', command=lambda:self.change_figure('rectangle'))
        self.rectangle_button.pack(side='left')
        self.circle_button = tk.Button(self.frame_tools, text='Circle', command=lambda:self.change_figure('circle'))
        self.circle_button.pack(side='left')
        self.size_entry = tk.Entry(self.frame_tools)
        self.size_entry.bind('<Return>', self.change_size)
        self.size_entry.pack(side='left')
        
        self.color_button = tk.Button(self.frame_tools, text='Color: #FF0000', command=self.change_color)
        self.color_button.pack(side='left')
        
        self.canvas = tk.Canvas(self.window, width=self.width, height=self.height)
        self.canvas.pack()
        self.canvas.bind('<Button-1>', self.on_click)

        self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)

        self.save_button = tk.Button(self.window, text='Save', command=self.save)
        self.save_button.pack()

    def on_click(self, event):
        if self.figure == 'circle':
            self.draw_circle(event)
        elif self.figure == 'rectangle':
            self.draw_rectangle(event)
            
    def draw_circle(self, event):
        x1 = event.x - self.size
        y1 = event.y - self.size
        x2 = event.x + self.size
        y2 = event.y + self.size
        # display on canvas
        self.canvas.create_oval((x1, y1, x2, y2), width=2, outline=self.color)
        # draw on self.image
        self.draw.ellipse((x1, y1, x2, y2), width=2, outline=self.color)

    def draw_rectangle(self, event):
        x1 = event.x - self.size
        y1 = event.y - self.size
        x2 = event.x + self.size
        y2 = event.y + self.size
        # display on canvas
        self.canvas.create_rectangle((x1, y1, x2, y2), width=2, outline=self.color)
        # draw on self.image
        self.draw.rectangle((x1, y1, x2, y2), width=2, outline=self.color)

    def save(self):
        self.image.save('output.jpg')

    def change_color(self):
        rgb, color_string = colorchooser.askcolor(initialcolor=self.color)
        #print(rgb, color_string)
        if color_string:
            self.color = color_string
            self.color_button['text'] = 'Color: ' + color_string

    def change_figure(self, figure):
        self.figure = figure

    def change_size(self, event=None):
        try:
            self.size = int(self.size_entry.get())
        except Exceptions as ex:
            print(ex)
# --- main ---

App()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM