我正在尝试为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()