ming 3 éve
szülő
commit
b6535bd1cf
52 módosított fájl, 484 hozzáadás és 0 törlés
  1. 55 0
      api/FaceSwap/README.md
  2. 70 0
      api/FaceSwap/face_detection.py
  3. 238 0
      api/FaceSwap/face_swap.py
  4. BIN
      api/FaceSwap/imgs/face.png
  5. BIN
      api/FaceSwap/imgs/target.png
  6. BIN
      api/FaceSwap/imgs/test1.jpg
  7. BIN
      api/FaceSwap/imgs/test2.jpg
  8. BIN
      api/FaceSwap/imgs/test3.jpg
  9. BIN
      api/FaceSwap/imgs/test4.jpg
  10. BIN
      api/FaceSwap/imgs/test5.jpg
  11. BIN
      api/FaceSwap/imgs/test6.jpg
  12. BIN
      api/FaceSwap/imgs/test7.jpg
  13. BIN
      api/FaceSwap/imgs/test8.jpg
  14. 12 0
      api/FaceSwap/jared.txt
  15. 47 0
      api/FaceSwap/main.py
  16. 58 0
      api/FaceSwap/main_video.py
  17. BIN
      api/FaceSwap/models/shape_predictor_68_face_landmarks.dat
  18. BIN
      api/FaceSwap/nina_noGesture_adj.mp4
  19. BIN
      api/FaceSwap/ok.avi
  20. 3 0
      api/FaceSwap/requirements.txt
  21. BIN
      api/FaceSwap/results/output6_1.jpg
  22. BIN
      api/FaceSwap/results/output6_2_2d.jpg
  23. BIN
      api/FaceSwap/results/output6_3.jpg
  24. BIN
      api/FaceSwap/results/output6_4.jpg
  25. BIN
      api/FaceSwap/results/output6_7.jpg
  26. BIN
      api/FaceSwap/results/output6_7_2d.jpg
  27. BIN
      api/FaceSwap/results/output7_4.jpg
  28. BIN
      api/FaceSwap/results/warp_2d.jpg
  29. BIN
      api/FaceSwap/results/warp_3d.jpg
  30. 1 0
      api/FaceSwap/scripts/faceswap.sh
  31. BIN
      api/FaceSwap/src_img/16243455712576303.jpg
  32. BIN
      api/FaceSwap/src_img/16243457809067454.jpg
  33. BIN
      api/FaceSwap/src_img/16243459511696787.jpg
  34. BIN
      api/FaceSwap/src_img/16243467048560734.jpg
  35. BIN
      api/FaceSwap/src_img/16243470855158741.jpg
  36. BIN
      api/FaceSwap/src_img/16243482365798137.jpg
  37. BIN
      api/FaceSwap/src_img/1624348281687592.jpg
  38. BIN
      api/FaceSwap/src_img/1624349763441171.jpg
  39. BIN
      api/FaceSwap/src_img/16243498493934758.jpg
  40. BIN
      api/FaceSwap/src_img/16243509841846786.jpg
  41. BIN
      api/FaceSwap/src_img/1624350996556805.jpg
  42. BIN
      api/FaceSwap/src_img/162435100893648.jpg
  43. BIN
      api/FaceSwap/src_img/16243522235433133.jpg
  44. BIN
      api/FaceSwap/src_img/16243527314408908.jpg
  45. BIN
      api/FaceSwap/src_img/16243536374485693.jpg
  46. BIN
      api/FaceSwap/src_img/16243536586519773.jpg
  47. BIN
      api/FaceSwap/src_img/16243536800773168.jpg
  48. BIN
      api/FaceSwap/src_img/1624353831368393.jpg
  49. BIN
      api/FaceSwap/src_img/1624354063681436.jpg
  50. BIN
      api/FaceSwap/src_img/16243570235773947.jpg
  51. BIN
      api/FaceSwap/src_img/16243577875540392.jpg
  52. BIN
      api/FaceSwap/src_img/16243585956367.jpg

+ 55 - 0
api/FaceSwap/README.md

@@ -0,0 +1,55 @@
+# FaceSwap
+Swap face between two photos for Python 3 with OpenCV and dlib.
+
+## Get Started
+```sh
+python main.py --src imgs/test6.jpg --dst imgs/test7.jpg --out results/output6_7.jpg --correct_color
+```
+
+| Source | Destination | Result |
+| --- | --- | --- |
+|![](imgs/test6.jpg) | ![](imgs/test7.jpg) | ![](results/output6_7.jpg) |
+
+```sh
+python main.py --src imgs/test6.jpg --dst imgs/test7.jpg --out results/output6_7_2d.jpg --correct_color --warp_2d
+```
+
+| Source | Destination | Result |
+| --- | --- | --- |
+|![](imgs/test6.jpg) | ![](imgs/test7.jpg) | ![](results/output6_7_2d.jpg) |
+
+
+## Install
+### Requirements
+* `pip install -r requirements.txt`
+* OpenCV 3: `conda install opencv` (If you have conda/anaconda)
+
+Note: See [requirements.txt](requirements.txt) for more details.
+### Git Clone
+```sh
+git clone https://github.com/wuhuikai/FaceSwap.git
+```
+### Swap Your Face
+```sh
+python main.py ...
+```
+Note: Run **python main.py -h** for more details.
+
+
+### Real-time camera
+```sh
+python main_video.py --src_img imgs/test7.jpg --show --correct_color --save_path {*.avi}
+```
+### Video
+```sh
+python main_video.py --src_img imgs/test7.jpg --video_path {video_path} --show --correct_color --save_path {*.avi}
+```
+
+## More Results
+| From | To |
+| --- | --- |
+| ![](imgs/test4.jpg) | ![](results/output6_4.jpg) |
+| ![](imgs/test3.jpg) | ![](results/output6_3.jpg) |
+| ![](imgs/test2.jpg) | ![](results/output6_2_2d.jpg) |
+| ![](imgs/test1.jpg) | ![](results/output6_1.jpg) |
+| ![](imgs/test4.jpg) | ![](results/output7_4.jpg) |

+ 70 - 0
api/FaceSwap/face_detection.py

@@ -0,0 +1,70 @@
+import cv2
+import dlib
+import numpy as np
+
+## Face detection
+def face_detection(img,upsample_times=1):
+    # Ask the detector to find the bounding boxes of each face. The 1 in the
+    # second argument indicates that we should upsample the image 1 time. This
+    # will make everything bigger and allow us to detect more faces.
+    detector = dlib.get_frontal_face_detector()
+    faces = detector(img, upsample_times)
+
+    return faces
+
+PREDICTOR_PATH = 'FaceSwap/models/shape_predictor_68_face_landmarks.dat'
+predictor = dlib.shape_predictor(PREDICTOR_PATH)
+## Face and points detection
+def face_points_detection(img, bbox:dlib.rectangle):
+    # Get the landmarks/parts for the face in box d.
+    shape = predictor(img, bbox)
+
+    # loop over the 68 facial landmarks and convert them
+    # to a 2-tuple of (x, y)-coordinates
+    coords = np.asarray(list([p.x, p.y] for p in shape.parts()), dtype=np.int)
+
+    # return the array of (x, y)-coordinates
+    return coords
+
+def select_face(im, r=10, choose=True):
+    faces = face_detection(im)
+
+    if len(faces) == 0:
+        return None, None, None
+
+    if len(faces) == 1 or not choose:
+        idx = np.argmax([(face.right() - face.left()) * (face.bottom() - face.top()) for face in faces])
+        bbox = faces[idx]
+    else:
+        bbox = []
+
+        def click_on_face(event, x, y, flags, params):
+            if event != cv2.EVENT_LBUTTONDOWN:
+                return
+
+            for face in faces:
+                if face.left() < x < face.right() and face.top() < y < face.bottom():
+                    bbox.append(face)
+                    break
+
+        im_copy = im.copy()
+        for face in faces:
+            # draw the face bounding box
+            cv2.rectangle(im_copy, (face.left(), face.top()), (face.right(), face.bottom()), (0, 0, 255), 1)
+        cv2.imshow('Click the Face:', im_copy)
+        cv2.setMouseCallback('Click the Face:', click_on_face)
+        while len(bbox) == 0:
+            cv2.waitKey(1)
+        cv2.destroyAllWindows()
+        bbox = bbox[0]
+
+    points = np.asarray(face_points_detection(im, bbox))
+
+    im_w, im_h = im.shape[:2]
+    left, top = np.min(points, 0)
+    right, bottom = np.max(points, 0)
+
+    x, y = max(0, left - r), max(0, top - r)
+    w, h = min(right + r, im_h) - x, min(bottom + r, im_w) - y
+
+    return points - np.asarray([[x, y]]), (x, y, w, h), im[y:y + h, x:x + w]

+ 238 - 0
api/FaceSwap/face_swap.py

@@ -0,0 +1,238 @@
+#! /usr/bin/env python
+import cv2
+import numpy as np
+import scipy.spatial as spatial
+import logging
+
+
+## 3D Transform
+def bilinear_interpolate(img, coords):
+    """ Interpolates over every image channel
+    http://en.wikipedia.org/wiki/Bilinear_interpolation
+    :param img: max 3 channel image
+    :param coords: 2 x _m_ array. 1st row = xcoords, 2nd row = ycoords
+    :returns: array of interpolated pixels with same shape as coords
+    """
+    int_coords = np.int32(coords)
+    x0, y0 = int_coords
+    dx, dy = coords - int_coords
+
+    # 4 Neighour pixels
+    q11 = img[y0, x0]
+    q21 = img[y0, x0 + 1]
+    q12 = img[y0 + 1, x0]
+    q22 = img[y0 + 1, x0 + 1]
+
+    btm = q21.T * dx + q11.T * (1 - dx)
+    top = q22.T * dx + q12.T * (1 - dx)
+    inter_pixel = top * dy + btm * (1 - dy)
+
+    return inter_pixel.T
+
+def grid_coordinates(points):
+    """ x,y grid coordinates within the ROI of supplied points
+    :param points: points to generate grid coordinates
+    :returns: array of (x, y) coordinates
+    """
+    xmin = np.min(points[:, 0])
+    xmax = np.max(points[:, 0]) + 1
+    ymin = np.min(points[:, 1])
+    ymax = np.max(points[:, 1]) + 1
+
+    return np.asarray([(x, y) for y in range(ymin, ymax)
+                       for x in range(xmin, xmax)], np.uint32)
+
+
+def process_warp(src_img, result_img, tri_affines, dst_points, delaunay):
+    """
+    Warp each triangle from the src_image only within the
+    ROI of the destination image (points in dst_points).
+    """
+    roi_coords = grid_coordinates(dst_points)
+    # indices to vertices. -1 if pixel is not in any triangle
+    roi_tri_indices = delaunay.find_simplex(roi_coords)
+
+    for simplex_index in range(len(delaunay.simplices)):
+        coords = roi_coords[roi_tri_indices == simplex_index]
+        num_coords = len(coords)
+        out_coords = np.dot(tri_affines[simplex_index],
+                            np.vstack((coords.T, np.ones(num_coords))))
+        x, y = coords.T
+        result_img[y, x] = bilinear_interpolate(src_img, out_coords)
+
+    return None
+
+
+def triangular_affine_matrices(vertices, src_points, dst_points):
+    """
+    Calculate the affine transformation matrix for each
+    triangle (x,y) vertex from dst_points to src_points
+    :param vertices: array of triplet indices to corners of triangle
+    :param src_points: array of [x, y] points to landmarks for source image
+    :param dst_points: array of [x, y] points to landmarks for destination image
+    :returns: 2 x 3 affine matrix transformation for a triangle
+    """
+    ones = [1, 1, 1]
+    for tri_indices in vertices:
+        src_tri = np.vstack((src_points[tri_indices, :].T, ones))
+        dst_tri = np.vstack((dst_points[tri_indices, :].T, ones))
+        mat = np.dot(src_tri, np.linalg.inv(dst_tri))[:2, :]
+        yield mat
+
+
+def warp_image_3d(src_img, src_points, dst_points, dst_shape, dtype=np.uint8):
+    rows, cols = dst_shape[:2]
+    result_img = np.zeros((rows, cols, 3), dtype=dtype)
+
+    delaunay = spatial.Delaunay(dst_points)
+    tri_affines = np.asarray(list(triangular_affine_matrices(
+        delaunay.simplices, src_points, dst_points)))
+
+    process_warp(src_img, result_img, tri_affines, dst_points, delaunay)
+
+    return result_img
+
+
+## 2D Transform
+def transformation_from_points(points1, points2):
+    points1 = points1.astype(np.float64)
+    points2 = points2.astype(np.float64)
+
+    c1 = np.mean(points1, axis=0)
+    c2 = np.mean(points2, axis=0)
+    points1 -= c1
+    points2 -= c2
+
+    s1 = np.std(points1)
+    s2 = np.std(points2)
+    points1 /= s1
+    points2 /= s2
+
+    U, S, Vt = np.linalg.svd(np.dot(points1.T, points2))
+    R = (np.dot(U, Vt)).T
+
+    return np.vstack([np.hstack([s2 / s1 * R,
+                                (c2.T - np.dot(s2 / s1 * R, c1.T))[:, np.newaxis]]),
+                      np.array([[0., 0., 1.]])])
+
+
+def warp_image_2d(im, M, dshape):
+    output_im = np.zeros(dshape, dtype=im.dtype)
+    cv2.warpAffine(im,
+                   M[:2],
+                   (dshape[1], dshape[0]),
+                   dst=output_im,
+                   borderMode=cv2.BORDER_TRANSPARENT,
+                   flags=cv2.WARP_INVERSE_MAP)
+
+    return output_im
+
+
+## Generate Mask
+def mask_from_points(size, points,erode_flag=1):
+    radius = 10  # kernel size
+    kernel = np.ones((radius, radius), np.uint8)
+
+    mask = np.zeros(size, np.uint8)
+    cv2.fillConvexPoly(mask, cv2.convexHull(points), 255)
+    if erode_flag:
+        mask = cv2.erode(mask, kernel,iterations=1)
+
+    return mask
+
+
+## Color Correction
+def correct_colours(im1, im2, landmarks1):
+    COLOUR_CORRECT_BLUR_FRAC = 0.75
+    LEFT_EYE_POINTS = list(range(42, 48))
+    RIGHT_EYE_POINTS = list(range(36, 42))
+
+    blur_amount = COLOUR_CORRECT_BLUR_FRAC * np.linalg.norm(
+                              np.mean(landmarks1[LEFT_EYE_POINTS], axis=0) -
+                              np.mean(landmarks1[RIGHT_EYE_POINTS], axis=0))
+    blur_amount = int(blur_amount)
+    if blur_amount % 2 == 0:
+        blur_amount += 1
+    im1_blur = cv2.GaussianBlur(im1, (blur_amount, blur_amount), 0)
+    im2_blur = cv2.GaussianBlur(im2, (blur_amount, blur_amount), 0)
+
+    # Avoid divide-by-zero errors.
+    im2_blur = im2_blur.astype(int)
+    im2_blur += 128*(im2_blur <= 1)
+
+    result = im2.astype(np.float64) * im1_blur.astype(np.float64) / im2_blur.astype(np.float64)
+    result = np.clip(result, 0, 255).astype(np.uint8)
+
+    return result
+
+
+## Copy-and-paste
+def apply_mask(img, mask):
+    """ Apply mask to supplied image
+    :param img: max 3 channel image
+    :param mask: [0-255] values in mask
+    :returns: new image with mask applied
+    """
+    masked_img=cv2.bitwise_and(img,img,mask=mask)
+
+    return masked_img
+
+
+## Alpha blending
+def alpha_feathering(src_img, dest_img, img_mask, blur_radius=15):
+    mask = cv2.blur(img_mask, (blur_radius, blur_radius))
+    mask = mask / 255.0
+
+    result_img = np.empty(src_img.shape, np.uint8)
+    for i in range(3):
+        result_img[..., i] = src_img[..., i] * mask + dest_img[..., i] * (1-mask)
+
+    return result_img
+
+
+def check_points(img,points):
+    # Todo: I just consider one situation.
+    if points[8,1]>img.shape[0]:
+        logging.error("Jaw part out of image")
+    else:
+        return True
+    return False
+
+
+def face_swap(src_face, dst_face, src_points, dst_points, dst_shape, dst_img, args, end=48):
+    h, w = dst_face.shape[:2]
+
+    ## 3d warp
+    warped_src_face = warp_image_3d(src_face, src_points[:end], dst_points[:end], (h, w))
+    ## Mask for blending
+    mask = mask_from_points((h, w), dst_points)
+    mask_src = np.mean(warped_src_face, axis=2) > 0
+    mask = np.asarray(mask * mask_src, dtype=np.uint8)
+    ## Correct color
+    if args.correct_color:
+        warped_src_face = apply_mask(warped_src_face, mask)
+        dst_face_masked = apply_mask(dst_face, mask)
+        warped_src_face = correct_colours(dst_face_masked, warped_src_face, dst_points)
+    ## 2d warp
+    if args.warp_2d:
+        unwarped_src_face = warp_image_3d(warped_src_face, dst_points[:end], src_points[:end], src_face.shape[:2])
+        warped_src_face = warp_image_2d(unwarped_src_face, transformation_from_points(dst_points, src_points),
+                                        (h, w, 3))
+
+        mask = mask_from_points((h, w), dst_points)
+        mask_src = np.mean(warped_src_face, axis=2) > 0
+        mask = np.asarray(mask * mask_src, dtype=np.uint8)
+
+    ## Shrink the mask
+    kernel = np.ones((10, 10), np.uint8)
+    mask = cv2.erode(mask, kernel, iterations=1)
+    ##Poisson Blending
+    r = cv2.boundingRect(mask)
+    center = ((r[0] + int(r[2] / 2), r[1] + int(r[3] / 2)))
+    output = cv2.seamlessClone(warped_src_face, dst_face, mask, center, cv2.NORMAL_CLONE)
+
+    x, y, w, h = dst_shape
+    dst_img_cp = dst_img.copy()
+    dst_img_cp[y:y + h, x:x + w] = output
+
+    return dst_img_cp

BIN
api/FaceSwap/imgs/face.png


BIN
api/FaceSwap/imgs/target.png


BIN
api/FaceSwap/imgs/test1.jpg


BIN
api/FaceSwap/imgs/test2.jpg


BIN
api/FaceSwap/imgs/test3.jpg


BIN
api/FaceSwap/imgs/test4.jpg


BIN
api/FaceSwap/imgs/test5.jpg


BIN
api/FaceSwap/imgs/test6.jpg


BIN
api/FaceSwap/imgs/test7.jpg


BIN
api/FaceSwap/imgs/test8.jpg


+ 12 - 0
api/FaceSwap/jared.txt

@@ -0,0 +1,12 @@
+
+python main_video.py --src_img anc2.jpg --show --correct_color --save_path test.avi
+
+
+python main.py --src  anc3.jpg --dst anc1.jpg --out o/test.jpg --correct_color --warp_2d
+
+python main_video.py --src_img ./anc2.jpg --video_path ./ff3.mp4 --correct_color --save_path ./ok.avi
+
+python main_video.py --src_img ./t6.jpg --video_path ./ff3.mp4 --correct_color --save_path ./ok.avi
+
+python main_video.py --src_img ./t6.jpg --video_path ./model.mp4 --correct_color --save_path ./ok.avi
+

+ 47 - 0
api/FaceSwap/main.py

@@ -0,0 +1,47 @@
+#! /usr/bin/env python
+import os
+import cv2
+import argparse
+
+from face_detection import select_face
+from face_swap import face_swap
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description='FaceSwapApp')
+    parser.add_argument('--src', required=True, help='Path for source image')
+    parser.add_argument('--dst', required=True, help='Path for target image')
+    parser.add_argument('--out', required=True, help='Path for storing output images')
+    parser.add_argument('--warp_2d', default=False, action='store_true', help='2d or 3d warp')
+    parser.add_argument('--correct_color', default=False, action='store_true', help='Correct color')
+    parser.add_argument('--no_debug_window', default=False, action='store_true', help='Don\'t show debug window')
+    args = parser.parse_args()
+
+    # Read images
+    src_img = cv2.imread(args.src)
+    dst_img = cv2.imread(args.dst)
+
+    # Select src face
+    src_points, src_shape, src_face = select_face(src_img)
+    # Select dst face
+    dst_points, dst_shape, dst_face = select_face(dst_img)
+
+    if src_points is None or dst_points is None:
+        print('Detect 0 Face !!!')
+        exit(-1)
+
+    output = face_swap(src_face, dst_face, src_points, dst_points, dst_shape, dst_img, args)
+
+    dir_path = os.path.dirname(args.out)
+    if not os.path.isdir(dir_path):
+        os.makedirs(dir_path)
+
+    cv2.imwrite(args.out, output)
+
+    ##For debug
+    if not args.no_debug_window:
+        cv2.imshow("From", dst_img)
+        cv2.imshow("To", output)
+        cv2.waitKey(0)
+        
+        cv2.destroyAllWindows()

+ 58 - 0
api/FaceSwap/main_video.py

@@ -0,0 +1,58 @@
+import os
+import cv2
+import logging
+import argparse
+
+from face_detection import select_face
+from face_swap import face_swap
+
+
+class VideoHandler(object):
+    def __init__(self, video_path=0, img_path=None, args=None):
+        self.src_points, self.src_shape, self.src_face = select_face(cv2.imread(img_path))
+        if self.src_points is None:
+            print('No face detected in the source image !!!')
+            exit(-1)
+        self.args = args
+        self.video = cv2.VideoCapture(video_path)
+        self.writer = cv2.VideoWriter(args.save_path, cv2.VideoWriter_fourcc(*'MJPG'), self.video.get(cv2.CAP_PROP_FPS),
+                                      (int(self.video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(self.video.get(cv2.CAP_PROP_FRAME_HEIGHT))))
+
+    def start(self):
+        while self.video.isOpened():
+            if cv2.waitKey(1) & 0xFF == ord('q'):
+                break
+
+            _, dst_img = self.video.read()
+            dst_points, dst_shape, dst_face = select_face(dst_img, choose=False)
+            if dst_points is not None:
+                dst_img = face_swap(self.src_face, dst_face, self.src_points, dst_points, dst_shape, dst_img, self.args, 68)
+            self.writer.write(dst_img)
+            if self.args.show:
+                cv2.imshow("Video", dst_img)
+
+        self.video.release()
+        self.writer.release()
+        cv2.destroyAllWindows()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.INFO,
+                        format="%(levelname)s:%(lineno)d:%(message)s")
+
+    parser = argparse.ArgumentParser(description='FaceSwap Video')
+    parser.add_argument('--src_img', required=True,
+                        help='Path for source image')
+    parser.add_argument('--video_path', default=0,
+                        help='Path for video')
+    parser.add_argument('--warp_2d', default=False, action='store_true', help='2d or 3d warp')
+    parser.add_argument('--correct_color', default=False, action='store_true', help='Correct color')
+    parser.add_argument('--show', default=False, action='store_true', help='Show')
+    parser.add_argument('--save_path', required=True, help='Path for storing output video')
+    args = parser.parse_args()
+
+    dir_path = os.path.dirname(args.save_path)
+    if not os.path.isdir(dir_path):
+        os.makedirs(dir_path)
+
+    VideoHandler(args.video_path, args.src_img, args).start()

BIN
api/FaceSwap/models/shape_predictor_68_face_landmarks.dat


BIN
api/FaceSwap/nina_noGesture_adj.mp4


BIN
api/FaceSwap/ok.avi


+ 3 - 0
api/FaceSwap/requirements.txt

@@ -0,0 +1,3 @@
+dlib >= 19.9.0
+numpy >= 1.13.1
+scipy >= 0.18.0

BIN
api/FaceSwap/results/output6_1.jpg


BIN
api/FaceSwap/results/output6_2_2d.jpg


BIN
api/FaceSwap/results/output6_3.jpg


BIN
api/FaceSwap/results/output6_4.jpg


BIN
api/FaceSwap/results/output6_7.jpg


BIN
api/FaceSwap/results/output6_7_2d.jpg


BIN
api/FaceSwap/results/output7_4.jpg


BIN
api/FaceSwap/results/warp_2d.jpg


BIN
api/FaceSwap/results/warp_3d.jpg


+ 1 - 0
api/FaceSwap/scripts/faceswap.sh

@@ -0,0 +1 @@
+python main.py --src imgs/test6.jpg --dst imgs/test4.jpg --out results/output6_4.jpg --correct_color

BIN
api/FaceSwap/src_img/16243455712576303.jpg


BIN
api/FaceSwap/src_img/16243457809067454.jpg


BIN
api/FaceSwap/src_img/16243459511696787.jpg


BIN
api/FaceSwap/src_img/16243467048560734.jpg


BIN
api/FaceSwap/src_img/16243470855158741.jpg


BIN
api/FaceSwap/src_img/16243482365798137.jpg


BIN
api/FaceSwap/src_img/1624348281687592.jpg


BIN
api/FaceSwap/src_img/1624349763441171.jpg


BIN
api/FaceSwap/src_img/16243498493934758.jpg


BIN
api/FaceSwap/src_img/16243509841846786.jpg


BIN
api/FaceSwap/src_img/1624350996556805.jpg


BIN
api/FaceSwap/src_img/162435100893648.jpg


BIN
api/FaceSwap/src_img/16243522235433133.jpg


BIN
api/FaceSwap/src_img/16243527314408908.jpg


BIN
api/FaceSwap/src_img/16243536374485693.jpg


BIN
api/FaceSwap/src_img/16243536586519773.jpg


BIN
api/FaceSwap/src_img/16243536800773168.jpg


BIN
api/FaceSwap/src_img/1624353831368393.jpg


BIN
api/FaceSwap/src_img/1624354063681436.jpg


BIN
api/FaceSwap/src_img/16243570235773947.jpg


BIN
api/FaceSwap/src_img/16243577875540392.jpg


BIN
api/FaceSwap/src_img/16243585956367.jpg