【问题标题】:How to create box around selected image on GUI如何在 GUI 上围绕选定图像创建框
【发布时间】:2023-03-17 01:54:01
【问题描述】:

我的 GUI 是一个图像幻灯片,幻灯片的每一页上都有一个正确的图像。正确的图像是左上角的三角形、心形气球、圆圈和河马。我对 python 完全陌生,所以当用户使用幻灯片时,我一直在努力解决如何在所选图像周围创建框。此框围绕正确或不正确的图像形成,以按下者为准。为了进一步解释,这包括根据用户单击的位置在图像周围插入一个框,但它没有说明所选图像是否是正确的图像。谢谢你的帮助

import PIL.Image
import PIL.ImageDraw
import tkinter as tk
import PIL.ImageTk
import csv
from PIL import Image

MAX_HEIGHT = 500
# height of the window (dimensions of the image)

class App(tk.Frame):
    def __init__(self, imageData, master=None):
        tk.Frame.__init__(self, master)

        self.clickStatus = tk.StringVar()
        self.loadedImages = dict()
        self.master.title('Slideshow')
        fram = tk.Frame(self)
        tk.Button(fram, text="Previous Image", command=self.prev).pack(side=tk.LEFT)
        tk.Button(fram, text="  Next Image  ", command=self.next).pack(side=tk.LEFT)
        tk.Label(fram, textvariable=self.clickStatus, font='Helvetica 18 bold').pack(side=tk.RIGHT)
        # inside or outside 
        fram.pack(side=tk.TOP, fill=tk.BOTH)
        self.imageLabel = tk.Label(self)
        # drawing the image on the label
        self.imageData = imageData
        self.currentIndex = 0
        # start from 0th image
        self.__loadImage__()
        self.imageLabel.bind("<Button-1>", self.clicked_evt)
        # when you click button, it opens event of clicked_evt
        self.imageLabel.pack()
        self.pack()

    def clicked_evt(self, evt):
        x, y = evt.x, evt.y
        imgData = self.loadedImages[self.imageData[self.currentIndex]['image_file']]
        (l, t), (r,b) = imgData['lt'], imgData['rb']
        if t<=y<=b and l<=x<=r:
            ##self.clickStatus.set('inside')
            print('Inside')
        else:
            ##self.clickStatus.set('outside')
            print('Outside')


    def __loadImage__(self):
        if self.imageData[self.currentIndex]['image_file'] not in self.loadedImages:

            self.im = PIL.Image.open(self.imageData[self.currentIndex]['image_file'])
    
            ratio = MAX_HEIGHT/self.im.height
        # ratio divided by existing height -> to get constant amount
            height, width = int(self.im.height*ratio), int(self.im.width * ratio)
            # calculate the new h and w and then resize next
            self.im = self.im.resize((width, height))
            lt = (int(self.imageData[self.currentIndex]['left']*ratio), int(self.imageData[self.currentIndex]['top']*ratio))
            rb = (int(self.imageData[self.currentIndex]['right']*ratio), int(self.imageData[self.currentIndex]['bottom']*ratio))
            # modifying new ratios with new height and width 
        #shape = [lt, rb]
            # print(shape)
            #img1 = PIL.ImageDraw.Draw(self.im) 
            #img1.rectangle(shape, outline ="red")            
            if self.im.mode == "1": 
                self.img = PIL.ImageTk.BitmapImage(self.im, foreground="white")
            else:              
                self.img = PIL.ImageTk.PhotoImage(self.im)
            imgData = self.loadedImages.setdefault(self.imageData[self.currentIndex]['image_file'], dict())
            imgData['image'] = self.img
            imgData['lt'] = lt
            imgData['rb'] = rb
        # for next and previous so it loads the same image adn don't do calculations again
        self.img = self.loadedImages[self.imageData[self.currentIndex]['image_file']]['image']
        self.imageLabel.config(image=self.img, width=self.img.width(), height=self.img.height())

    def prev(self):
        self.currentIndex = (self.currentIndex+len(self.imageData) - 1 ) % len(self.imageData)
        self.__loadImage__()
    # here if i go to the first one and press back, goes to last, round robbin

    def next(self):
        self.currentIndex = (self.currentIndex + 1) % len(self.imageData)
        self.__loadImage__()
    # here if i go to the last one and press next, goes to first, round robbin

def loadData(fname):
    with open(fname, mode='r') as f:
        reader = csv.DictReader(f)
        data = [dict(row) for row in reader]
    for row in data:
        row['top'], row['bottom'], row['left'], row['right'] = int(row['top']),int(row['bottom']),int(row['left']),int(row['right'])
    return data          
if __name__ == "__main__":
    data = loadData('bounding_box.csv')
    app = App(data)
    app.mainloop()

【问题讨论】:

  • 好的,我改了

标签: python excel user-interface tkinter jupyter-notebook


【解决方案1】:

据我了解,您只是想在单击图像时在图像周围绘制一个矩形(代码 cmets 中的解释):

from tkinter import Tk, Canvas
from PIL import Image, ImageTk

# below code is used to create images, you can also load them from a file if you need
mode = 'RGB'
size = (150, 150)
color_lst = ['red', 'green', 'blue', 'yellow']
# best to get all the images for the slide in a single list for further easier workings
img_lst = [Image.new(mode, size, color) for color in color_lst]


# selecting function that will be called when user clicks on image
def select(id_):
    canvas.create_rectangle(canvas.bbox(id_), width=5)
    
    # here you will put other code to be executed after
    # user clicks on the image like going to the next frame or sth
    
    # additionally you could use this if you want the other rectangles to disappear
    # but kinda pointless if you will switch frames and stuff
    # for canvas_id in canvas_images:
    #     if canvas_id == id_:
    #         continue
    #     canvas.create_rectangle(canvas.bbox(canvas_id), width=5, outline='white')


root = Tk()

# here create a photoimage list from the above image list
photo_lst = [ImageTk.PhotoImage(image) for image in img_lst]

# create canvas
canvas = Canvas(root, width=400, height=400)
canvas.pack()

# set the coordinates for the four images
coordinates = [(100, 100), (300, 100), (100, 300), (300, 300)]
# create the images and append their id to a list
canvas_images = [
    canvas.create_image(pos[0], pos[1], image=photo) for pos, photo in zip(coordinates, photo_lst)
]

# bind the ids from `canvas_images` to being clicked and execute simple drawing method
for c_img in canvas_images:
    canvas.tag_bind(
        c_img, '<Button-1>', lambda e, i=c_img: select(i)
    )

root.mainloop()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 2022-06-21
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多