使用 python opencv 在网络摄像头上切换图像过滤器

switching image filters on webcam using python opencv

我有一个项目,我正在尝试模仿 snapchat 的过滤系统。据推测,在单击 window 一侧的过滤器按钮后,网络摄像头将显示过滤器的内容。然而,window 最终冻结了。如果我尝试单独实施过滤器,它们确实有效。但是当我尝试在这里实现它时,window 冻结了。

这是代码:(函数 detect()、get_cam_frame()、show_frame() 和 phone_filter() 不是我的。我只是从互联网上检索它们)

# Import Libraries
import numpy as np
import Tkinter as tk
import tkMessageBox
import cv2
import sys
from PIL import Image, ImageTk
from video import create_capture


# Initialize Window

root = tk.Tk()
root.wm_title("Filter App")
root.config(background="#000000")
canvas = tk.Canvas(root, width=600, height=700)
canvas.pack()
canvas.grid(row=0, column=0, padx=5, pady=20)

lmain = tk.Label(canvas)
lmain.grid(row=0, column=0, padx=85, pady=119)
cap = cv2.VideoCapture(0)

def detect(img, cascade):
    rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE)
    if len(rects) == 0:
        return []
    rects[:, 2:] += rects[:, :2]
    return rects

def get_cam_frame(cam):
    ret, img = cam.read()
    # smaller frame size - things run a lot smoother than a full screen img
    img = cv2.resize(img, (800, 470))
    return img



def show_frame():
    _, frame = cap.read()
    frame = cv2.flip(frame, 1)
    cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
    img = Image.fromarray(cv2image)
    imgtk = ImageTk.PhotoImage(image=img)
    lmain.imgtk = imgtk
    lmain.configure(image=imgtk)
    lmain.after(10, show_frame)

sliderFrame = tk.Frame(root, width=500, height=50)
sliderFrame.grid(row = 500, column=0, padx=10, pady=2)
show_frame()

def phone_filter(img):
    show_frame()
    print img
    if img == "dog":
        filter_img = cv2.imread("img/face/dogfilter.png", cv2.IMREAD_COLOR)
    elif img == "dalmatian":
        filter_img = cv2.imread("img/face/dalmatianfilter.png", cv2.IMREAD_COLOR)
    elif img == "anime":
        filter_img = cv2.imread("img/face/animefilter.png", cv2.IMREAD_COLOR)
    elif img == "catears":
        filter_img = cv2.imread("img/face/catearsfilter.png", cv2.IMREAD_COLOR)
    elif img == "mustache":
        filter_img = cv2.imread("img/face/mustachefilter.png", cv2.IMREAD_COLOR)
    elif img == "pig":
        filter_img = cv2.imread("img/face/pigfilter.png", cv2.IMREAD_COLOR)
    elif img == "shaider":
        filter_img = cv2.imread("img/face/shaiderfilter.png", cv2.IMREAD_COLOR)
    elif img == "none":
        filter_img = cv2.imread("img/Empty.png", cv2.IMREAD_COLOR)
    else:
        filter_img = cv2.imread("img/Empty.png", cv2.IMREAD_COLOR)
    haar_classifier = "data/haarcascade_frontalface_default.xml"
    # use the haar classifier for now, it seems to work a little bit better
    cascade = cv2.CascadeClassifier(haar_classifier)
    print cascade
    while True:
        print "."
        cam = cv2.VideoCapture(0)
        print cam
        bw = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        bw = cv2.equalizeHist(bw)
        rects = detect(bw, cascade)
        final = img.copy()
        # for x1, y1, x2, y2 in rects:
        #     cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2)
        if len(rects) >= 1:
            allFaces = rects
            #rect = (ax1, ay1, ax2, ay2)
            for index, (ax1, ay1, ax2, ay2) in enumerate(allFaces):
                deltaY = abs(ay2) - abs(ay1)
                stretchFactor = 0.2
                stretchAmount = int(stretchFactor * deltaY)
                ay2 = ay2 + stretchAmount
                ay1 = ay1 - stretchAmount
                height, width, _ = img.shape
                if ax1 > stretchAmount and ax2 < width - stretchAmount and ay1 > stretchAmount and ay2 < height - stretchAmount:
                    face = img[ay1:ay2, ax1:ax2]
                    filter_scale = []
                    if index % 2 == 0:
                        #dog_scale = cv2.resize(dog_img, (ax2 - ax1, ay2 - ay1))
                        filter_scale = cv2.resize(filter_img, (ax2 - ax1, ay2 - ay1))
                    else:
                        filter_scale = cv2.resize(filter_img, (ax2 - ax1, ay2 - ay1))
                    # my_scaled = np.where(dog_scale == 0, face, dog_scale)
                    my_scaled = np.where(filter_scale == 0, face, filter_scale)
                    # faceB = cv2.resize(
                    # img[by1:by2, bx1:bx2].copy(), (ax2 - ax1, ay2 - ay1))
                    final[ay1:ay2, ax1:ax2] = my_scaled
                    #final[by1:by2, bx1:bx2] = faceA
        cv2.imshow(final)

def dogOp():
    phone_filter("dog")
    # tkMessageBox.showinfo("Face Filter", "Dog Filter")

def dalmatianOp():
    phone_filter("dalmatian")
    # tkMessageBox.showinfo("Face Filter", "Dalmatian Filter")

def animeOp():
    phone_filter("anime")
    # tkMessageBox.showinfo("Face Filter", "Anime Filter")

def catearsOp():
    phone_filter("catears")
    # tkMessageBox.showinfo("Face Filter", "Cat Ears Filter")

def mustacheOp():
    phone_filter("mustache")
    # tkMessageBox.showinfo("Face Filter", "Mustache Filter")

def pigOp():
    phone_filter("pig")
    # tkMessageBox.showinfo("Face Filter", "Pig Filter")

def shaiderOp():
    phone_filter("shaider")
    # tkMessageBox.showinfo("Face Filter", "Shaider Pulis Pangkalawakan")

initializing background

image = Image.open('img/phone_bg.png')
image = image.resize((820, 700), Image.ANTIALIAS)
tk_img = ImageTk.PhotoImage(image)
canvas.create_image(400, 360, image=tk_img)

initializing face filters

dogfilter = Image.open("img/face/dogfilter.png")
dogfilter = dogfilter.resize((50, 50), Image.ANTIALIAS)
dog = ImageTk.PhotoImage(dogfilter)

dalmatianfilter = Image.open("img/face/dalmatianfilter.png")
dalmatianfilter = dalmatianfilter.resize((50, 50), Image.ANTIALIAS)
dalmatian = ImageTk.PhotoImage(dalmatianfilter)

animefilter = Image.open("img/face/animefilter.png")
animefilter = animefilter.resize((50, 50), Image.ANTIALIAS)
anime = ImageTk.PhotoImage(animefilter)

catearsfilter = Image.open("img/face/catearsfilter.png")
catearsfilter = catearsfilter.resize((50, 50), Image.ANTIALIAS)
catears = ImageTk.PhotoImage(catearsfilter)

mustachefilter = Image.open("img/face/mustachefilter.png")
mustachefilter = mustachefilter.resize((50, 50), Image.ANTIALIAS)
mustache = ImageTk.PhotoImage(mustachefilter)

pigfilter = Image.open("img/face/pigfilter.png")
pigfilter = pigfilter.resize((50, 50), Image.ANTIALIAS)
pig = ImageTk.PhotoImage(pigfilter)

shaiderfilter = Image.open("img/face/shaiderfilter.png")
shaiderfilter = shaiderfilter.resize((50, 50), Image.ANTIALIAS)
shaider = ImageTk.PhotoImage(shaiderfilter)


face filter buttons

dogbtn = tk.Button(root, width=30, height=30, image = dog, command=dogOp)
dogbtn_window = canvas.create_window(100,150, anchor='nw', window=dogbtn)

dalmatianbtn = tk.Button(root, width=30, height=30, image = dalmatian, command=dalmatianOp)
dalmatianbtn_window = canvas.create_window(100,190, anchor='nw', window=dalmatianbtn)

animebtn = tk.Button(root, width=30, height=30, image = anime, command=animeOp)
animebtn_window = canvas.create_window(100,230, anchor='nw', window=animebtn)

catearsbtn = tk.Button(root, width=30, height=30, image = catears, command=catearsOp)
catearsbtn_window = canvas.create_window(100,270, anchor='nw', window=catearsbtn)

mustachebtn = tk.Button(root, width=30, height=30, image = mustache, command=mustacheOp)
mustachebtn_window = canvas.create_window(100,310, anchor='nw', window=mustachebtn)

pigbtn = tk.Button(root, width=30, height=30, image = pig, command=pigOp)
pigbtn_window = canvas.create_window(100,350, anchor='nw', window=pigbtn)

shaiderbtn = tk.Button(root, width=30, height=30, image = shaider, command=shaiderOp)
shaiderbtn_window = canvas.create_window(100,390, anchor='nw', window=shaiderbtn)

quit_button = tk.Button(root, text = "X", command = root.quit, anchor = 'w',
                    width = 2, bg="red")
quit_button_window = canvas.create_window(680,120, anchor='nw', window=quit_button)


root.mainloop()

只要您按下按钮,camerafeed 就会冻结,因为您的 phone_filter() 功能永远不会结束。实际上,它包含一个 while True 循环。

此外,在这个函数中,您尝试重新打开 VideoCapture(0),这显然是错误的,因为您已经在初始化步骤 (cap = cv2.VideoCapture(0)) 中打开了它。请改用 cap 变量。

下面两行,使用 bw = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),你尝试转换 img 这是你的输入 string!


无论如何,根据您要实现的目标,我认为您的代码结构不正确。你应该做点这样的事:

while True 循环内:

  • 从相机中检索帧。
  • 然后,在该帧上调用 人脸识别 函数,该函数将 return 检测到的人脸的位置。
  • 在检测到的面部上方绘制选定的滤镜。
  • 最后,显示生成的图像。

绑定到按钮的函数应该只更改一个变量(您可以调用 selected_filter)。然后,在 while True 循环中,您将读取此变量以绘制正确的过滤器。