美文网首页
Python tkinter 实现本地打开图片进行标注

Python tkinter 实现本地打开图片进行标注

作者: 步履不停的Suunny | 来源:发表于2018-05-19 20:47 被阅读0次

    需求:

    写一个软件,要求本地打开一张图片显示出来,并可以进行选框标注,自动生成坐标,同时给出输入框,可以手动输入内容,并保存成json文件 。

    输入: 本地打开一张图片
    操作: 鼠标进行选框标注,并输入选框内的文字
    输出: 坐标值: x、y、w、h,json文件。 json文件包含 x、y、w、h和文字内容。

    选工具

    对python比较熟悉 ,Tkinter工具使用过,首选吧。 tkinter的文档比较少,但是做的过程中遇到的一些问题还是不能解决。

    打开文件 并显示图片

    #-*- coding:utf-8 -*-
    import tkinter
    from tkinter import *
    from PIL import Image,ImageTk
    from tkinter.filedialog import askopenfilename
    import time
    
    root = Tk()
    root.geometry('500x500')
    root.title('图片处理')
    
    def choosepic():
        path_ = askopenfilename()
        path.set(path_)
        img_open = Image.open(file_entry.get())
        img = ImageTk.PhotoImage(img_open)
        image_label.config(image=img)
        image_label.image = img  # keep a reference
    
    
    path = StringVar()
    Button(root, text='选择图片', command=choosepic).pack()
    file_entry = Entry(root, state='readonly', text=path)
    #file_entry.pack() 
    image_label = Label(root)
    image_label.pack()
    root.mainloop()
    

    打开图片并刷新label显示,我自己写的代码一直没有成功,label打开后总是不能成功。以上代码参考下面连接。
    python如何在tkinter中动态显示label图片

    直接上全部代码吧

    # -*- coding:utf-8 -*-
    import tkinter
    import tkinter.filedialog
    import os
    from PIL import ImageGrab
    from time import sleep
    from tkinter import *
    
    from PIL import Image,ImageTk
    from tkinter.filedialog import askopenfilename
    import json
    import codecs
    
    # 创建tkinter主窗口
    root = tkinter.Tk()
    root.title('图片处理')
    
    # 指定主窗口位置与大小
    root.geometry('800x600+100+50')   # width x height + widthoffset + heightoffset
    
    # 不允许改变窗口大小
    root.resizable(False, False)
    root.focusmodel()
    
    class MyCapture:
        def __init__(self, png):
    
            # 变量X和Y用来记录鼠标左键按下的位置
            self.X = tkinter.IntVar(value=0)
            self.Y = tkinter.IntVar(value=0)
            self.selectPosition = None
    
            # 屏幕尺寸
            screenWidth = root.winfo_screenwidth()
            screenHeight = root.winfo_screenheight()
    
            # 创建顶级组件容器
            self.top = tkinter.Toplevel(root, width=screenWidth, height=screenWidth)
    
            # 不显示最大化、最小化按钮
            self.top.overrideredirect(True)
            self.canvas = tkinter.Canvas(self.top, bg='white', width=screenWidth, height=screenWidth)
    
            # 显示全屏截图,在全屏截图上进行区域截图
            self.image = tkinter.PhotoImage(file=png)
            self.canvas.create_image(screenWidth // 2, screenHeight // 2, image=self.image)
    
            # 鼠标左键按下的位置
            def onLeftButtonDown(event):
                self.X.set(event.x)
                self.Y.set(event.y)
                # 开始截图
                self.sel = True
    
            self.canvas.bind('<Button-1>', onLeftButtonDown)
    
            # 鼠标左键移动,显示选取的区域
            def onLeftButtonMove(event):
                if not self.sel:
                    return
                global lastDraw
                try:
                    # 删除刚画完的图形,要不然鼠标移动的时候是黑乎乎的一片矩形
                    self.canvas.delete(lastDraw)
                except Exception as e:
                    pass
                lastDraw = self.canvas.create_rectangle(self.X.get(), self.Y.get(), event.x, event.y, outline='red')
    
            self.canvas.bind('<B1-Motion>', onLeftButtonMove)
    
            # 获取鼠标左键抬起的位置,保存区域截图
            def onLeftButtonUp(event):
                self.sel = False
                try:
                    self.canvas.delete(lastDraw)
                except Exception as e:
                    pass
                sleep(0.1)
    
                # 更新主窗口位置坐标
                root.update()
                x = root.winfo_x()
                y = root.winfo_y()
    
                #考虑鼠标左键从右下方按下而从左上方抬起的截图
                myleft, myright = sorted([self.X.get(), event.x])
                mytop, mybottom = sorted([self.Y.get(), event.y])
    
                # Position : x , y, w, h
                self.selectPosition = (myleft-x,  mytop-y-30, myright-x,mybottom-y-30)
                print (myleft, myright)
                self.top.destroy()
                print ("destroy")
            self.canvas.bind('<ButtonRelease-1>', onLeftButtonUp)
            self.canvas.pack(fill=tkinter.BOTH, expand=tkinter.YES)
            # 开始截图
    
    #设置截取坐标全局变量, 元组类型
    CapturePosition = ()
    
    def buttonCaptureClick():
        filename = 'temp.png'
        im = ImageGrab.grab()
        im.save(filename)
        im.close()
    
        # 显示全屏幕截图
        w = MyCapture(filename)
        buttonCapture.wait_window(w.top)
    
        xy_text.set(str(w.selectPosition))
        global  CapturePosition
        CapturePosition = w.selectPosition
    
        root.state('normal')
        os.remove(filename)
    
    #获取输入的标注内容
    def getstr():
        if input_valueText.get() != '':
            words = input_valueText.get()
            get_label["text"] = words
    
    
    def save_jsonfile():
        json_content = {}
        #获取坐标
        json_content['x'] = CapturePosition[0]
        json_content['y'] = CapturePosition[1]
        json_content['w'] = CapturePosition[2]
        json_content['h'] = CapturePosition[3]
    
        # 获取输入内容
        value = get_label["text"]
        json_content['value'] = value
    
        # 存入json文件
        final_json = json.dumps(json_content, ensure_ascii=False)
        with codecs.open ("d:\\data_json.json",'a','utf-8') as file:
              file.write(final_json)
    
    
    # 定义坐标显示位置
    xy_text = StringVar()
    
    
    #打开图片文件并显示
    def choosepic():
        path_ = askopenfilename()
        path.set(path_)
        img_open = Image.open(file_entry.get())
        img = ImageTk.PhotoImage(img_open)
        image_label.config(image=img)
        image_label.image = img  # keep a reference
    
    path = StringVar()
    tkinter.Button(root, text = '打开文件' ,command=choosepic).place(x = 100, y = 530,w = 150, h = 40)
    file_entry = Entry(root, state='readonly', text=path)
    file_entry.pack()
    image_label = Label(root, bg = 'gray')
    image_label.place(x=0, y=0,width = 500, height = 500)
    
    
    #添加截图按钮功能
    buttonCapture = tkinter.Button(root, text='标注', command=buttonCaptureClick)
    
    #坐标名称及显示坐标
    label_xytitle = tkinter.Label(root,text ='标注位置坐标x, y, w, h :')
    label_xytitle.place(x=520, y=50)
    label = tkinter.Label(root, textvariable=xy_text,fg = 'blue')
    label.place(x=520, y=70)
    
    
    # 输入标注内容
    input_valueTitle = StringVar()
    input_valueTitle.set('请输入内容:')
    label_inputTitle = tkinter.Label(root, textvariable=input_valueTitle)
    label_inputTitle.place(x=520, y=90)
    #输入框
    input_valueText = tkinter.Entry(root,width=12)
    input_valueText.place(x =520 , y=120,width = 250, height=40,anchor = NW)
    
    #获取输入内容
    comand = tkinter.Button(root, text="获取内容" ,command=getstr, width=10, height=2)
    comand.place(x =520 , y=150,width = 250, height=40,anchor = NW)
    get_label = tkinter.Label(root, fg = 'blue')
    get_label.place(x =520 , y=200)
    
    buttonCapture.place(x=300, y=530, width=150, height=40)
    
    #保存数据
    save = tkinter.Button(root, text="保存数据", command=save_jsonfile, width=10, height=2)
    save.place(x =500 , y=530,width = 150, height=40,anchor = NW)
    
    # 启动消息主循环
    root.update()
    root.mainloop()
    

    需要整理下,看时间吧。 先记录一下。
    遗留问题: 鼠标画框后,没有能把线画出来。 用canvas试了下,总有这样那样的问题。 待解决。

    相关文章

      网友评论

          本文标题:Python tkinter 实现本地打开图片进行标注

          本文链接:https://www.haomeiwen.com/subject/prbydftx.html