Python:计算机视觉实现视频的AI换脸(最基础)

一、实验要求

1、手动点击关键点进行替换

2、利用光流对相邻的视频帧进行关键点的追踪

二、实验结果

Python:计算机视觉实现视频的AI换脸(最基础)

三、实验代码

1、手动进行图像关键点的点击

import cv2
import numpy as np

导入图片
img1 = cv2.imread('path1')
img2 = cv2.imread('path2')

a =[]
b = []

def on_EVENT_LBUTTONDOWN1(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)

        cv2.circle(img1, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(img1, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image1", img1)

def on_EVENT_LBUTTONDOWN2(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)

        cv2.circle(img2, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(img2, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image2", img2)

cv2.namedWindow("image1")
cv2.namedWindow("image2")
cv2.setMouseCallback("image1", on_EVENT_LBUTTONDOWN1)
cv2.setMouseCallback("image2", on_EVENT_LBUTTONDOWN2)
cv2.imshow("image1", img1)
cv2.imshow("image2", img2)
cv2.waitKey(0)

cv2.destroyAllWindows()

#for i in range(8):
   print([a[i],b[i]])

调用cv2库和numpy库,利用cv2.setMouseCallback函数得到鼠标的点击信息,并在on_EVENT_LBUTTONDOWN函数中对点击的点进行标记,将点击点的坐标存储在数组a,b里面。

2、利用光流对相邻的视频帧进行关键点的追踪

(1)首先需要提取视频的第一帧,手动进行关键点的标注,调用cap.read函数,此时frame为视频第一帧的二进制流数据

import cv2
cap = cv2.VideoCapture('2.mp4')
ret, frame = cap.read()      #frame是每一帧的图像
scaling_factor = 0.5
frame = cv2.resize(frame, None, fx=scaling_factor,
                   fy=scaling_factor, interpolation=cv2.INTER_AREA)

(2)手动点击关键点

a =[]
b = []

def on_EVENT_LBUTTONDOWN1(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)
        cv2.circle(frame, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(frame, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image1", frame)

def on_EVENT_LBUTTONDOWN2(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)

        cv2.circle(img1, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(img1, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image2", img1)

cv2.namedWindow("image1")
cv2.setMouseCallback("image1", on_EVENT_LBUTTONDOWN1)
cv2.imshow("image1", frame)

cv2.namedWindow("image2")
cv2.setMouseCallback("image2", on_EVENT_LBUTTONDOWN2)
cv2.imshow("image2", img1)
cv2.waitKey(0)

p0=np.float32([[[a[0],b[0]]],[[a[1],b[1]]],[[a[2],b[2]]],[[a[3],b[3]]]])
print(p0)
cv2.destroyAllWindows()

(3)对视频光流进行追踪,p0为当前关键点,p1为视频流中关键点的下一个位置信息

调用cv2.calcOpticalFlowPyrLK()函数进行我们想要的追踪操作

(ps.关注cv2.calcOpticalFlowPyrLK()函数中p0的格式)

import cv2
import numpy as np

feature_params = dict(maxCorners=100, qualityLevel=0.3,
                      minDistance=7, blockSize=7)
lk_params = dict(winSize=(15,15), maxLevel=2,
                 criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

cap = cv2.VideoCapture('path')
ret, frame = cap.read()      #frame是每一帧的图像

scaling_factor = 0.5
frame = cv2.resize(frame, None, fx=scaling_factor,
                   fy=scaling_factor, interpolation=cv2.INTER_AREA)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
p0 = np.float32([[[174,170]],[[180,190]],[[200,200]],[[210,210]]])
p0 = cv2.goodFeaturesToTrack(gray, mask=None, **feature_params)    #角点检测
print(p0)
mask = np.zeros_like(frame)

while True:
    ret, frame = cap.read()
    frame = cv2.resize(frame, None, fx=scaling_factor,
                       fy=scaling_factor, interpolation=cv2.INTER_AREA)
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    p1, st, err = cv2.calcOpticalFlowPyrLK(gray, frame_gray, p0, None, **lk_params)
    print(p1[0][0])
    print(p0)
    good_new = p1[st == 1]
    good_old = p0[st == 1]

    for i,(new,old) in enumerate(zip(good_new,good_old)):
        a,b = new.ravel()
        a=int(a)
        b=int(b)
        c,d = old.ravel()
        c=int(c)
        d=int(d)
        cv2.line(mask, (a, b),(c, d),(0, 150, 0), 1)
        cv2.circle(frame, (a, b), 3, (0, 255, 0), -1)

    gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)

    img = cv2.add(frame, mask)
    cv2.imshow("Output", img)

    k = cv2.waitKey(30)
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()

3、人脸的替换(以为图片的替换为例)

(1)鼠标定点(不再赘述)

(2)矩阵变换

调用cv2.getPerspectiveTransform(), cv2.warpPerspective()函数进行两张图片上的关键点的对比(注:此函数规定对应点为4个点)

(3)内容替换

直接用变换好的图像相应矩阵位置处的值替换原图像位置的值

import numpy as np
import cv2
%matplotlib inline

img1 = cv2.imread('path1')
img2 = cv2.imread('path2')

a =[]
b = []

一、鼠标定点

def on_EVENT_LBUTTONDOWN1(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)

        cv2.circle(img1, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(img1, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image1", img1)

def on_EVENT_LBUTTONDOWN2(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)

        cv2.circle(img2, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(img2, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image2", img2)

cv2.namedWindow("image1")
cv2.namedWindow("image2")
cv2.setMouseCallback("image1", on_EVENT_LBUTTONDOWN1)
cv2.setMouseCallback("image2", on_EVENT_LBUTTONDOWN2)
cv2.imshow("image1", img1)
cv2.imshow("image2", img2)
cv2.waitKey(0)

print(a[3],b[3])
print(a[6],b[6])

cv2.destroyAllWindows()

二、矩阵变换

points1 = np.float32([[[a[4],b[4]]],[[a[5],b[5]]],[[a[6],b[6]]],[[a[7],b[7]]]])
points2 = np.float32([[[a[0],b[0]]],[[a[1],b[1]]],[[a[2],b[2]]],[[a[3],b[3]]]])

M  =  cv2.getPerspectiveTransform(points1, points2)

Affine_img = cv2.warpPerspective(img2, M, (img1.shape[1], img1.shape[0]))

三、内容替换

m=a[2]-a[0]
n=b[2]-b[0]
for j in range(m):
    for i in range(m):
        img1[74+i][125+j] = Affine_img[74+i][125+j]

cv2.namedWindow("image3")
cv2.imshow("image3",Affine_img)     # 显示图片
cv2.imshow("image2",np.array(img_cov, dtype = np.uint8 ))
cv2.waitKey(0)

cv2.destroyAllWindows()

四、完整代码

import numpy as np
import cv2
%matplotlib inline

#视频第一帧和图像第一帧锁定

cap = cv2.VideoCapture('2.mp4')
ret, frame = cap.read()      #frame是每一帧的图像
scaling_factor = 0.5
frame = cv2.resize(frame, None, fx=scaling_factor,
                   fy=scaling_factor, interpolation=cv2.INTER_AREA)
img1 = cv2.imread('face.jpg')

a =[]
b = []

def on_EVENT_LBUTTONDOWN1(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)
        cv2.circle(frame, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(frame, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image1", frame)

def on_EVENT_LBUTTONDOWN2(event, x, y, flags, param):
    # 点击鼠标左键
    if event == cv2.EVENT_LBUTTONDOWN:
        xy = "%d,%d" % (x, y)
        a.append(x)
        b.append(y)

        cv2.circle(img1, (x, y), 1, (255, 0, 0), thickness=-1)
        cv2.putText(img1, xy, (x, y), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        cv2.imshow("image2", img1)

cv2.namedWindow("image1")
cv2.setMouseCallback("image1", on_EVENT_LBUTTONDOWN1)
cv2.imshow("image1", frame)

cv2.namedWindow("image2")
cv2.setMouseCallback("image2", on_EVENT_LBUTTONDOWN2)
cv2.imshow("image2", img1)
cv2.waitKey(0)

p0=np.float32([[[a[0],b[0]]],[[a[1],b[1]]],[[a[2],b[2]]],[[a[3],b[3]]]])
print(p0)
cv2.destroyAllWindows()

#光流追踪关键点

lk_params = dict(winSize=(15,15), maxLevel=2,
                 criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
mask = np.zeros_like(frame)

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

while True:
    ret, frame = cap.read()
    frame = cv2.resize(frame, None, fx=scaling_factor,
                       fy=scaling_factor, interpolation=cv2.INTER_AREA)
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    p1, st, err = cv2.calcOpticalFlowPyrLK(gray, frame_gray, p0, None, **lk_params)

    good_new = p1[st == 1]
    good_old = p0[st == 1]

    for i,(new,old) in enumerate(zip(good_new,good_old)):
        e,f = new.ravel()
        e=int(e)
        f=int(f)
        g,h = old.ravel()
        g=int(g)
        h=int(h)
        cv2.line(mask, (e, f),(g, h),(0, 150, 0), 1)
        cv2.circle(frame, (e, f), 3, (0, 255, 0), -1)

    # 二、矩阵变换

    points1 = np.float32([[[a[4],b[4]]],[[a[5],b[5]]],[[a[6],b[6]]],[[a[7],b[7]]]])
    points2 = np.float32(p1)

    M  =  cv2.getPerspectiveTransform(points1, points2)

    Affine_img = cv2.warpPerspective(img1, M, (frame.shape[1], frame.shape[0]))

    # 三、内容替换

    m = p1[2][0][0]-p1[0][0][0]   #m=a[2]-a[0]
    m=int(m)
    n = p1[2][0][1]-p1[0][0][1]   #n=b[2]-b[0]
    n=int(n)
    a1 = int(p1[0][0][1])
    a2 = int(p1[0][0][0])
    a3 = int(p1[0][0][1])
    a4 = int(p1[0][0][0])
    for i in range(n):
        for j in range(m):
            frame[a1+i][a2+j] = Affine_img[a3+i][a4+j]

    cv2.namedWindow("image3")
    cv2.imshow("image3",Affine_img)     # 显示图片
    # cv2.imshow("image2",np.array(img_cov, dtype = np.uint8 ))
    cv2.waitKey(0)

    cv2.destroyAllWindows()

    gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)

    img = cv2.add(frame, mask)
    cv2.imshow("Output", img)

    k = cv2.waitKey(30)
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()

完结撒花!

Original: https://blog.csdn.net/Josepyth/article/details/125288514
Author: Josepyth
Title: Python:计算机视觉实现视频的AI换脸(最基础)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/532461/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球