最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python tkinter實(shí)現(xiàn)圖片標(biāo)注功能(完整代碼)

 更新時(shí)間:2019年12月08日 09:19:27   作者:默默的點(diǎn)滴  
tkinter是Python下面向tk的圖形界面接口庫(kù),可以方便地進(jìn)行圖形界面設(shè)計(jì)和交互操作編程,本文通過(guò)實(shí)例代碼給大家介紹的Python tkinter實(shí)現(xiàn)圖片標(biāo)注功能,感興趣的朋友一起看看吧

.tkinter

tkinter是Python下面向tk的圖形界面接口庫(kù),可以方便地進(jìn)行圖形界面設(shè)計(jì)和交互操作編程。tkinter的優(yōu)點(diǎn)是簡(jiǎn)單易用、與Python的結(jié)合度好。tkinter在Python 3.x下默認(rèn)集成,不需要額外的安裝操作;不足之處為缺少合適的可視化界面設(shè)計(jì)工具,需要通過(guò)代碼來(lái)完成窗口設(shè)計(jì)和元素布局。

Python tkinter實(shí)現(xiàn)圖片標(biāo)注代碼,代碼如下所述:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
import sys
if sys.version_info < (3, 0): 
  import Tkinter as tk # 導(dǎo)入 Tkinter 庫(kù)
  from tkFileDialog import askopenfilename, asksaveasfilename
else :
  import tkinter as tk # 導(dǎo)入 Tkinter 庫(kù)
  from tkinter.filedialog import askopenfilename, asksaveasfilename
from PIL import Image, ImageTk, ImageDraw
from time import sleep
import numpy as np
import cv2 as cv
DEF_WIDTH = 1080
DEF_HEIGHT = 720
IMAGE_HEIGHT = 720
FRAME_LEFT_WIDTH = 360
# 太小的選定區(qū)域我們需要丟棄,防止誤操作
MINI_RECT_AREA = 20 
class RawImageEditor:
  def __init__(self, win, img, rects):
    #變量X和Y用來(lái)記錄鼠標(biāo)左鍵按下的位置
    self.X = tk.IntVar(value=0)
    self.Y = tk.IntVar(value=0)
    self.sel = False
    self.lastDraw = None
    self.lastDraws = []
    self.imageScale = 1.0
    self.dispWidth = DEF_WIDTH # 圖片顯示區(qū)域的最大高度,寬度
    self.dispHeight = DEF_HEIGHT
    self.rawImage = img
    self.calcImageScale(self.rawImage)
    self.dispWidth = int(self.imageScale * self.rawImage.width)
    self.dispHeight = int(self.imageScale * self.rawImage.height)
    # 圖片縮放
    self.dispImage = self.rawImage.resize((self.dispWidth, self.dispHeight))
    # 選擇區(qū)域
    self.selPositions = []
    for r in rects :
      self.selPositions.append((r[0] * self.imageScale, r[1] * self.imageScale, r[2] * self.imageScale, r[3] * self.imageScale))
    #創(chuàng)建頂級(jí)組件容器
    self.top = tk.Toplevel(win, width=self.dispWidth, height=self.dispHeight)
    #不顯示最大化、最小化按鈕
    self.top.overrideredirect(True)
    # Make topLevelWindow remain on top until destroyed, or attribute changes.
    self.top.attributes('-topmost', 'true')
    self.canvas = tk.Canvas(self.top, bg='white', width=self.dispWidth, height=self.dispHeight)
    self.tkImage = ImageTk.PhotoImage(self.dispImage)
    self.canvas.create_image(self.dispWidth//2, self.dispHeight//2, image=self.tkImage)
    for r in self.selPositions :
      draw = self.canvas.create_rectangle(r[0], r[1], r[2], r[3], outline='green')
      self.lastDraws.append(draw)
    #鼠標(biāo)左鍵按下的位置
    def onLeftButtonDown(event):
      self.X.set(event.x)
      self.Y.set(event.y)
      #開(kāi)始截圖
      self.sel = True
      #重新繪制已經(jīng)選擇的區(qū)域
      for draw in self.lastDraws :
        self.canvas.delete(draw)
      self.lastDraws = []
      for r in self.selPositions :
        draw = self.canvas.create_rectangle(r[0], r[1], r[2], r[3], outline='green')
        self.lastDraws.append(draw)
    self.canvas.bind('<Button-1>', onLeftButtonDown)
    #鼠標(biāo)左鍵移動(dòng),顯示選取的區(qū)域
    def onLeftButtonMove(event):
      if not self.sel:
        return
      try:
        #刪除剛畫完的圖形,要不然鼠標(biāo)移動(dòng)的時(shí)候是黑乎乎的一片矩形
        self.canvas.delete(self.lastDraw)
      except Exception as e:
        pass
      self.lastDraw = self.canvas.create_rectangle(self.X.get(), self.Y.get(), event.x, event.y, outline='green')
    self.canvas.bind('<B1-Motion>', onLeftButtonMove)
    #獲取鼠標(biāo)左鍵抬起的位置,保存區(qū)域截圖
    def onLeftButtonUp(event):
      self.sel = False
      sleep(0.1)
      #考慮鼠標(biāo)左鍵從右下方按下而從左上方抬起的截圖
      left, right = sorted([self.X.get(), event.x])
      top, bottom = sorted([self.Y.get(), event.y])
      if (right - left) * (bottom - top) > MINI_RECT_AREA :
        self.selPositions.append((left,top,right,bottom))
      #self.top.destroy()
    #鼠標(biāo)右鍵按下
    def onRightButtonDown(event):
      self.sel = False
      self.top.destroy()
    self.canvas.bind('<Button-2>', onRightButtonDown)
    self.canvas.bind('<ButtonRelease-1>', onLeftButtonUp)
    self.canvas.pack(fill=tk.BOTH, expand=tk.YES)
  def calcImageScale(self, image) :
    w = image.width
    h = image.height
    self.imageScale = 1.0
    # 計(jì)算最小的縮放比例,保證原始寬高比
    if w > self.dispWidth and h > self.dispHeight :
      ws = self.dispWidth * 1.0 / w
      hs = self.dispHeight * 1.0 / h
      if ws < hs :
        self.imageScale = ws
      else :
        self.imageScale = hs
    elif w > self.dispWidth and h < self.dispHeight :
      self.imageScale = self.dispWidth * 1.0 / w
    elif w < self.dispWidth and h > self.dispHeight :
      self.imageScale = self.dispHeight * 1.0 / h
  def waitForWindow(self, win) :      
    win.wait_window(self.top)
  def selectedPositions(self) : 
    # 轉(zhuǎn)換為原始像素位置
    realPos = []
    for r in self.selPositions :
      realPos.append((r[0] / self.imageScale, r[1] / self.imageScale, r[2] / self.imageScale, r[3] / self.imageScale))
    return realPos   
class MainWin(tk.Tk):
  def __init__(self):
    if sys.version_info >= (3, 0):
      super().__init__()
    else : 
      tk.Tk.__init__(self)
    self.title('圖像處理工具')
    self.geometry('{}x{}'.format(DEF_WIDTH, DEF_HEIGHT))
    self.rawImagePath = ''
    self.rawImage = None # self.rawImage 原始圖像,未經(jīng)過(guò)縮放處理
    self.transRawImage = None # self.transRawImage 經(jīng)過(guò)轉(zhuǎn)換處理之后的原始圖像,沒(méi)有經(jīng)過(guò)縮放處理
    self.dispImage = None # self.dispImage 顯示圖像,可能經(jīng)過(guò)縮放處理
    self.imageScale = 1.0 # 圖片縮放比例,根據(jù)縮放比例進(jìn)行顯示的時(shí)候的縮放處理,后期選擇區(qū)域的時(shí)候,需要進(jìn)行縮放還原
    self.leftFrameWidth = FRAME_LEFT_WIDTH
    self.frameDispHeight = DEF_HEIGHT # 整個(gè)窗口的高度
    self.labelTextHeight = 20 # 文本標(biāo)簽的高度
    self.btnHeight = 40 # 按鈕的高度
    self.imageDispWidth = IMAGE_HEIGHT # 圖片顯示區(qū)域的最大高度,寬度
    self.imageDispHeight = self.frameDispHeight / 2 - self.labelTextHeight * 2
    # 選擇區(qū)域
    self.liRect = []
    self.rawImageEditor = None
    self.setupUI()
  def scaleDisplayImage(self, image) :
    w = image.width
    h = image.height
    self.imageScale = 1.0
    # 計(jì)算最小的縮放比例,保證原始寬高比
    if w > self.imageDispWidth and h > self.imageDispHeight :
      ws = self.imageDispWidth * 1.0 / w
      hs = self.imageDispHeight * 1.0 / h
      if ws < hs :
        self.imageScale = ws
      else :
        self.imageScale = hs
    elif w > self.imageDispWidth and h < self.imageDispHeight :
      self.imageScale = self.imageDispWidth * 1.0 / w
    elif w < self.imageDispWidth and h > self.imageDispHeight :
      self.imageScale = self.imageDispHeight * 1.0 / h
    # 圖片縮放
    return image.resize((int(self.imageScale * w), int(self.imageScale * h)))
 
  # 打開(kāi)圖片時(shí)使用,傳值(圖)給展示函數(shù)
  def openAndDisplayImage(self):
    self.rawImagePath = self.selectImageFile()
    if '' != self.rawImagePath :
      self.rawImage = Image.open(self.rawImagePath)
      self.rawImage = self.rawImage.convert('RGBA')
      self.drawRawImageDisp()
  def drawListBox(self):
    self.l_box.delete(0,tk.END)
    for item in self.liRect:
      r = '{},{},{},{}'.format(round(item[0],1), round(item[1],1), round(item[2],1), round(item[3],1))
      self.l_box.insert(0, r)
  def drawRawImageDisp(self, selItems=[]):      
    self.dispImage = self.scaleDisplayImage(self.rawImage)
    self.dispImage = self.dispImage.convert('RGB')
    draw = ImageDraw.Draw(self.dispImage)
    for i in range(len(self.liRect)) :
      r = self.liRect[i]
      if i in selItems :
        draw.rectangle((r[0] * self.imageScale, r[1] * self.imageScale, r[2] * self.imageScale, r[3] * self.imageScale), outline = "red")
      else :
        draw.rectangle((r[0] * self.imageScale, r[1] * self.imageScale, r[2] * self.imageScale, r[3] * self.imageScale), outline = "green")
    img = ImageTk.PhotoImage(self.dispImage)
    self.image_l_raw.config(image=img)
    self.image_l_raw.image = img
  def deleteSelectedItemFromListBox(self):
    #print(self.l_box.get(self.l_box.curselection()))
    idx = self.l_box.curselection()
    if len(idx) > 0 :
      kp = []
      for v in range(len(self.liRect)) :
        if v not in idx :
          kp.append(self.liRect[v])
      self.liRect = kp
      self.drawListBox() 
      self.drawRawImageDisp() 
  # 打開(kāi)圖片時(shí)使用,獲得地址
  def selectImageFile(self):
    path = tk.StringVar()
    file_entry = tk.Entry(self, state='readonly', text=path)
    path_ = askopenfilename()
    path.set(path_)
    return file_entry.get()
  def rawImageLabelClicked(self, event):
    if None != self.rawImage :
      if None == self.rawImageEditor :
        self.rawImageEditor = RawImageEditor(self, self.rawImage, self.liRect)
        self.rawImageEditor.waitForWindow(self.image_l_raw)
        self.liRect = self.rawImageEditor.selectedPositions()
        self.rawImageEditor = None
        self.drawListBox()
        self.drawRawImageDisp()
  def onRectListboxSelect(self, event):
    idx = self.l_box.curselection()
    if len(idx) > 0 :
      self.drawRawImageDisp(idx)
  def drawTransImageDisp(self):      
    transImage = self.scaleDisplayImage(self.transRawImage)
    transImage = transImage.convert('L')
    img = ImageTk.PhotoImage(transImage)
    self.image_l_trans.config(image=img)
    self.image_l_trans.image = img
  def doTransRawImage(self):
    self.transRawImage = Image.new('L', (self.rawImage.width, self.rawImage.height))
    for r in self.liRect :
      im = self.rawImage.crop(r)
      cv_im = cv.cvtColor(np.asarray(im), cv.COLOR_RGB2BGR)
      hsv = cv.cvtColor(cv_im, cv.COLOR_BGR2HSV)
      _, _, v = cv.split(hsv)
      avg = np.average(v.flatten())
      pixels = im.load()
      for j in range(im.height) :
        for i in range(im.width) :
          hv = v[j,i]
          if hv < avg * 1.2:
            #im.putpixel((i, j), 0) # slow
            pixels[i, j] = 0
          '''else :
            im.putpixel((i, j), (255, 255, 255, 255))'''
      self.transRawImage.paste(im, (int(r[0]),int(r[1])), mask = None) 
    self.drawTransImageDisp()
  def onTransRawImageBtnClicked(self):
    if None != self.rawImage :
      self.doTransRawImage()
  def onSaveTransRawImageBtnClicked(self):
    if None != self.transRawImage :
      ext = os.path.splitext(self.rawImagePath)[-1]
      (path,name) = os.path.split(self.rawImagePath)
      filename = asksaveasfilename(title = '保存圖片', initialfile = name, filetypes = (("jpeg files","*{}".format(ext)), ("all files","*.*")))
      if '' != filename :
        self.transRawImage.save(filename)     
  def setupUI(self):
    # 左邊菜單欄
    left_f = tk.Frame(self, height=self.frameDispHeight, width=self.leftFrameWidth)
    left_f.pack(side=tk.LEFT)
    # 各種功能按鈕名稱及位置
    btnOpen = tk.Button(left_f, text='打開(kāi)圖像', command=self.openAndDisplayImage)
    btnOpen.place(y=25, x=30, width=300, height=self.btnHeight)
    btnTrans = tk.Button(left_f, text='處理圖像', command=self.onTransRawImageBtnClicked)
    btnTrans.place(y=85, x=30, width=300, height=self.btnHeight)
    l_selRect = tk.Label(left_f, text = '鼠標(biāo)選定區(qū)域')
    l_selRect.place(x=0, y=165, width=self.leftFrameWidth, height=self.labelTextHeight)
    '''列表'''
    self.l_box = tk.Listbox(left_f) # 創(chuàng)建兩個(gè)列表組件
    self.l_box.place(x=0, y=165+self.labelTextHeight, width=self.leftFrameWidth, height=270)
    self.l_box.bind('<<ListboxSelect>>', self.onRectListboxSelect)
    self.drawListBox()
    # 刪除選定項(xiàng)
    btnDel = tk.Button(left_f, text='刪除選定項(xiàng)', command=self.deleteSelectedItemFromListBox)
    btnDel.place(y=460, x=30, width=300, height=self.btnHeight)
    btnSave = tk.Button(left_f, text='保存結(jié)果', command=self.onSaveTransRawImageBtnClicked)
    btnSave.place(y=550, x=30, width=300, height=self.btnHeight)
    # 右側(cè)圖像顯示欄
    right_f = tk.Frame(self, height=self.frameDispHeight, width=self.imageDispWidth)
    right_f.pack(side=tk.RIGHT)
    l_rawT = tk.Label(right_f, text = '原始圖片')
    l_rawT.place(x=0, y=0, width=self.imageDispWidth, height=self.labelTextHeight)
    self.image_l_raw = tk.Label(right_f, relief='ridge')
    self.image_l_raw.place(x=0, y=self.labelTextHeight, width=self.imageDispWidth, height=self.imageDispHeight)
    self.image_l_raw.bind("<Button-1>",self.rawImageLabelClicked)
    l_transT = tk.Label(right_f, text = '處理后圖片')
    l_transT.place(x=0, y=self.labelTextHeight + self.imageDispHeight, width=self.imageDispWidth, height=self.labelTextHeight)
    self.image_l_trans = tk.Label(right_f, relief='ridge')
    self.image_l_trans.place(x=0, y=self.labelTextHeight + self.imageDispHeight + self.labelTextHeight, width=self.imageDispWidth, height=self.imageDispHeight)
if __name__ == '__main__' :
  win = MainWin()
  # 進(jìn)入消息循環(huán)
  win.mainloop()

總結(jié)

以上所述是小編給大家介紹的Python tkinter實(shí)現(xiàn)圖片標(biāo)注功能,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!

相關(guān)文章

  • Python讀取串口數(shù)據(jù)的實(shí)現(xiàn)方法

    Python讀取串口數(shù)據(jù)的實(shí)現(xiàn)方法

    本文主要介紹了Python讀取串口數(shù)據(jù)的實(shí)現(xiàn)方法,可以使用pySerial庫(kù)來(lái)讀取串口數(shù)據(jù),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • python collections模塊示例詳解

    python collections模塊示例詳解

    Python的collections模塊是其標(biāo)準(zhǔn)庫(kù)中的一部分,包含了一些擴(kuò)展內(nèi)置數(shù)據(jù)類型的有用數(shù)據(jù)結(jié)構(gòu),如OrderedDict、defaultdict、Counter、deque和namedtuple等,這些數(shù)據(jù)結(jié)構(gòu)在不同場(chǎng)景下都非常有用,能提供更高效的數(shù)據(jù)操作和方便的數(shù)據(jù)訪問(wèn)方式,有助于提升代碼的性能和可讀性
    2024-10-10
  • Python的自動(dòng)化部署模塊Fabric的安裝及使用指南

    Python的自動(dòng)化部署模塊Fabric的安裝及使用指南

    這篇文章主要介紹了Python的自動(dòng)化部署模塊Fabric的安裝及使用指南,文中以Debian系統(tǒng)為環(huán)境進(jìn)行了實(shí)例演示,需要的朋友可以參考下
    2016-01-01
  • Python實(shí)現(xiàn)繪制圣誕樹(shù)和煙花的示例代碼

    Python實(shí)現(xiàn)繪制圣誕樹(shù)和煙花的示例代碼

    這不是圣誕節(jié)快到了,還不用Python繪制個(gè)圣誕樹(shù)和煙花讓女朋友開(kāi)心開(kāi)心,也算是親手做的,稍稍花了點(diǎn)心思,學(xué)會(huì)了趕緊畫給你的那個(gè)她吧
    2022-12-12
  • Python使用matplotlib.pyplot?as?plt繪圖圖層優(yōu)先級(jí)問(wèn)題

    Python使用matplotlib.pyplot?as?plt繪圖圖層優(yōu)先級(jí)問(wèn)題

    這篇文章主要介紹了Python使用matplotlib.pyplot?as?plt繪圖圖層優(yōu)先級(jí)問(wèn)題.文章圍繞主題展開(kāi)詳細(xì)內(nèi)容需要的小伙伴可以參考一下
    2022-04-04
  • python將控制臺(tái)輸出保存至文件的方法

    python將控制臺(tái)輸出保存至文件的方法

    今天小編就為大家分享一篇python將控制臺(tái)輸出保存至文件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • Python實(shí)現(xiàn)KPM算法詳解

    Python實(shí)現(xiàn)KPM算法詳解

    大家好,本篇文章主要講的是Python實(shí)現(xiàn)KPM算法詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 序列化Python對(duì)象的方法

    序列化Python對(duì)象的方法

    這篇文章主要介紹了序列化Python對(duì)象的方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-08-08
  • 怎么使用pipenv管理你的python項(xiàng)目

    怎么使用pipenv管理你的python項(xiàng)目

    本篇文章主要介紹了怎么使用pipenv管理你的python項(xiàng)目,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Python替換NumPy數(shù)組中大于某個(gè)值的所有元素實(shí)例

    Python替換NumPy數(shù)組中大于某個(gè)值的所有元素實(shí)例

    這篇文章主要介紹了Python替換NumPy數(shù)組中大于某個(gè)值的所有元素實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-06-06

最新評(píng)論

南投市| 盘锦市| 建瓯市| 芜湖县| 封丘县| 福泉市| 萨嘎县| 呼玛县| 弥渡县| 宜章县| 勐海县| 三原县| 富平县| 无锡市| 邵阳市| 平塘县| 彭州市| 吉林省| 百色市| 萨迦县| 虞城县| 来安县| 松原市| 建始县| 岚皋县| 平顺县| 滦平县| 麟游县| 甘肃省| 广饶县| 万山特区| 衡山县| 冕宁县| 禹城市| 闽清县| 博白县| 榆林市| 永德县| 六盘水市| 泰安市| 江源县|