使用抓取鼠标绘制Python Opencv

时间:2018-06-12 12:24:47

标签: python opencv tkinter

我正在尝试为Python Tkinter制作一个用于抓取的GUI。在左侧框架上显示输入图像,在右侧(画布)显示输出图像。

选择图像后,使用haar级联分类器检测面部。然后,从面部检测中应用了矩形的抓取。然后制作背景和前景图纸以使用蒙版应用抓取。 选择背景并应用蒙版有效。但是,对于前景,应用蒙版时不会发生任何事情。我感谢任何帮助。

import tkinter as tk
from tkinter import filedialog
import cv2
from PIL import Image
from PIL import ImageTk
import numpy as np

class Application(tk.Frame):
    BLACK = [0,0,0]         # sure BG
    WHITE = [255,255,255]   # sure FG

    bgdModel = np.zeros((1,65),np.float64)
    fgdModel = np.zeros((1,65),np.float64)
    drawing = False
    # flag for grabcut (rectangle or mask). No use right now
    rect_or_mask = 0
    # drawing values
    DRAW_BG = {'color' : BLACK, 'val' : 0,'canvas':"black"}
    DRAW_FG = {'color' : WHITE, 'val' : 1,'canvas':"white"}
    value = DRAW_FG
    image = None
    mask_draw = None

    def __init__(self, master=None):
        super().__init__(master)
        self.pack()
        self.create_widgets()
        self.canvas.bind("<ButtonPress-1>", self.on_button_press)
        self.canvas.bind("<ButtonRelease-1>", self.on_button_release)
        self.canvas.bind("<Motion>",self.on_mouse_move)
    def create_widgets(self):
        self.file_chooser = tk.Button(self,text="Choose Image",command=self.choose_file)
        self.file_chooser.pack(side="top")


        self.apply = tk.Button(self,text="Apply",command=self.apply_again)
        self.apply.pack(side="bottom")

        self.quit = tk.Button(self,text="Quit",fg="red",command=root.destroy)    
        self.quit.pack(side="bottom")

        self.background = tk.Button(self,text="Choose Background",command=self.choose_background)
        self.background.pack(side="top")

        self.foreground = tk.Button(self,text="Choose Foreground",command=self.choose_foreground)
        self.foreground.pack(side="top")       

        self.leftFrame = tk.Frame(self,width=800,height=600,bg="black")
        self.leftFrame.pack(side="left",padx=10,pady=10)

        self.canvas = tk.Canvas(self,width=800,height=600,bg="white")
        self.canvas.pack(side="right",padx=10,pady=10)



    def choose_file(self):
        # choose image
        path =  filedialog.askopenfilename()

        if len(path)>0:
            self.rect_or_mask = 0
            # read image 
            self.image = cv2.imread(path)
            self.image = self.image[...,::-1]
            # initialize mask 
            self.mask_draw = np.zeros(self.image.shape[:2],np.uint8)

            gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
            # find faces with haar cascade
            face_cascade =  cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
            faces = face_cascade.detectMultiScale(gray,1.3,5)
            # find the largest rectangle in faces
            width = []
            for (x,y,w,h) in faces:
                width.append(w)

            max_ind = np.argmax(np.asarray(width))
            x,y,w,h = faces[max_ind]
            rect = (x-150,y-250,x+w+200,y+h+200)
            # Start the first grabcut with the largest rectangle
            self.apply_mask(rect)
    # Apply button. Grabcut with mask
    def apply_again(self):
        cv2.grabCut(self.output,self.mask_draw,None,self.bgdModel,self.fgdModel,10,cv2.GC_INIT_WITH_MASK)

        mask2= np.where((self.mask_draw==1) + (self.mask_draw==3),255,0).astype('uint8')

        self.output=cv2.bitwise_and(self.output,self.output,mask=mask2)
        # Convert to PIL format
        self.secondedges = Image.fromarray(self.output)
        # ...and then to ImageTk format
        self.secondedges = ImageTk.PhotoImage(self.secondedges)
        # Display on canvas
        self.canvas.itemconfigure(self.myim,image=self.secondedges)
    # Apply the first grabcut after the image is chosen. Grabcut with rectangle.
    def apply_mask(self,rect):
        if self.rect_or_mask == 0: # grabcut WITH RECTANGLE
            self.rect_or_mask = 1
            cv2.grabCut(self.image,self.mask_draw,rect,self.bgdModel,self.fgdModel,1,cv2.GC_INIT_WITH_RECT)

        mask2 = np.where((self.mask_draw==2)|(self.mask_draw==0),0,1).astype('uint8')

        # Change image output and mask size            
        self.output = self.image*mask2[:,:,np.newaxis]
        self.image = cv2.resize(self.image,(800, 600), interpolation = cv2.INTER_CUBIC)
        self.output = cv2.resize(self.output,(800, 600), interpolation = cv2.INTER_CUBIC)
        self.mask_draw = cv2.resize(self.mask_draw,(800,600),interpolation=cv2.INTER_CUBIC)
        # convert the images to PIL format...
        myedges = Image.fromarray(self.output)
        image = Image.fromarray(self.image)

        # ...and then to ImageTk format
        self.myedges = ImageTk.PhotoImage(myedges)
        image = ImageTk.PhotoImage(image)

        # On the left frame put the input image
        self.panelA = tk.Label(self.leftFrame,image=image)
        self.panelA.image = image
        self.panelA.pack(side="left")

        # Display the output image on the canvas at right
        self.myim=self.canvas.create_image((0,0),image=self.myedges,anchor="nw")
        # Set the Apply button command
        self.apply.configure(command=self.apply_again)
    # assign draw values 
    def choose_background(self):
        self.value = self.DRAW_BG
    def choose_foreground(self):
        self.value = self.DRAW_FG
    # drawing with mouse
    def on_button_press(self, event):
        x = event.x
        y = event.y

        self.drawing = True
        # draw on canvas (black for background white for foreground)
        self.canvas.create_oval(x-5,y-5,x+5,y+5, fill=self.value['canvas'])
        # draw on mask ( 0 for background 1 for foreground)
        cv2.circle(self.mask_draw,center=(x,y),radius=5,color=self.value['val'],thickness=-1)

    #draw when mouse released
    def on_button_release(self, event):
        if self.drawing== True:
            self.drawing = False
            x1,y1 = (event.x, event.y)
            self.canvas.create_oval(x1-5,y1-5,x1+5,y1+5, fill=self.value['canvas'])
            cv2.circle(self.mask_draw,center=(x1,y1),radius=5,color=self.value['val'],thickness=-1)
            print(self.mask_draw)
    # draw when mouse is moved
    def on_mouse_move(self,event): 
        if self.drawing==True:   #check if button is pressed down
            x1,y1 = (event.x,event.y)
            self.canvas.create_oval(x1-5,y1-5,x1+5,y1+5, fill=self.value['canvas'])
            cv2.circle(self.mask_draw,center=(x1,y1),radius=5,color=self.value['val'],thickness=-1)

root = tk.Tk()
app = Application(master=root)
app.mainloop()

0 个答案:

没有答案