SimSwap icon indicating copy to clipboard operation
SimSwap copied to clipboard

Any way to process batches of images?

Open Wythneth opened this issue 3 years ago • 22 comments

I like being able to use this on single images, however, if I have 10 images I want to map one face to, I have to go through individually, one by one. After one is completed, I have to rename it to save it being overwritten during the next process.

Is there a command I can use to process one face to a folder of images? If not, could we get this in a future update?

Thankyou.

Wythneth avatar Aug 30 '21 06:08 Wythneth

I didn't test this but it should work. Instead of swapping to an image directly, you just use the path where the images are.

On line 1 in test_one_image.py, add import os https://github.com/neuralchen/SimSwap/blob/186a57aa96f6422a3043021602d3586641711186/test_one_image.py#L1

From lines 40-86 in test_one_image.py, replace this:

https://github.com/neuralchen/SimSwap/blob/186a57aa96f6422a3043021602d3586641711186/test_one_image.py#L40-L86

With this:

    pic_a = opt.pic_a_path
    img_a = Image.open(pic_a).convert('RGB')
    img_a = transformer_Arcface(img_a)
    img_id = img_a.view(-1, img_a.shape[0], img_a.shape[1], img_a.shape[2])
    
    for image in os.listdir(opt.pic_b_path):
        if image.endswith(".jpg") or filename.endswith(".png"):

            pic_b = image
            img_b = Image.open(pic_b).convert('RGB')
            img_b = transformer(img_b)
            img_att = img_b.view(-1, img_b.shape[0], img_b.shape[1], img_b.shape[2])
            
            # convert numpy to tensor
            img_id = img_id.cuda()
            img_att = img_att.cuda()
    
            #create latent id
            img_id_downsample = F.interpolate(img_id, scale_factor=0.5)
            latend_id = model.netArc(img_id_downsample)
            latend_id = latend_id.detach().to('cpu')
            latend_id = latend_id/np.linalg.norm(latend_id,axis=1,keepdims=True)
            latend_id = latend_id.to('cuda')
    
    
            ############## Forward Pass ######################
            img_fake = model(img_id, img_att, latend_id, latend_id, True)
    
    
            for i in range(img_id.shape[0]):
                if i == 0:
                    row1 = img_id[i]
                    row2 = img_att[i]
                    row3 = img_fake[i]
                else:
                    row1 = torch.cat([row1, img_id[i]], dim=2)
                    row2 = torch.cat([row2, img_att[i]], dim=2)
                    row3 = torch.cat([row3, img_fake[i]], dim=2)
    
            #full = torch.cat([row1, row2, row3], dim=1).detach()
            full = row3.detach()
            full = full.permute(1, 2, 0)
            output = full.to('cpu')
            output = np.array(output)
            output = output[..., ::-1]
    
            output = output*255
    
            cv2.imwrite(opt.output_path + f'{os.path.splitext(image)[0]}_result.jpg',output)
        else:
            print("Image not found.")
            continue

ExponentialML avatar Aug 30 '21 19:08 ExponentialML

I didn't test this but it should work. Instead of swapping to an image directly, you just use the path where the images are.

On line 1 in test_one_image.py, add import os

https://github.com/neuralchen/SimSwap/blob/186a57aa96f6422a3043021602d3586641711186/test_one_image.py#L1

From lines 40-86 in test_one_image.py, replace this:

https://github.com/neuralchen/SimSwap/blob/186a57aa96f6422a3043021602d3586641711186/test_one_image.py#L40-L86

With this:

    pic_a = opt.pic_a_path
    img_a = Image.open(pic_a).convert('RGB')
    img_a = transformer_Arcface(img_a)
    img_id = img_a.view(-1, img_a.shape[0], img_a.shape[1], img_a.shape[2])
    
    for image in os.listdir(opt.pic_b_path):
        if image.endswith(".jpg") or filename.endswith(".png"):

            pic_b = image
            img_b = Image.open(pic_b).convert('RGB')
            img_b = transformer(img_b)
            img_att = img_b.view(-1, img_b.shape[0], img_b.shape[1], img_b.shape[2])
            
            # convert numpy to tensor
            img_id = img_id.cuda()
            img_att = img_att.cuda()
    
            #create latent id
            img_id_downsample = F.interpolate(img_id, scale_factor=0.5)
            latend_id = model.netArc(img_id_downsample)
            latend_id = latend_id.detach().to('cpu')
            latend_id = latend_id/np.linalg.norm(latend_id,axis=1,keepdims=True)
            latend_id = latend_id.to('cuda')
    
    
            ############## Forward Pass ######################
            img_fake = model(img_id, img_att, latend_id, latend_id, True)
    
    
            for i in range(img_id.shape[0]):
                if i == 0:
                    row1 = img_id[i]
                    row2 = img_att[i]
                    row3 = img_fake[i]
                else:
                    row1 = torch.cat([row1, img_id[i]], dim=2)
                    row2 = torch.cat([row2, img_att[i]], dim=2)
                    row3 = torch.cat([row3, img_fake[i]], dim=2)
    
            #full = torch.cat([row1, row2, row3], dim=1).detach()
            full = row3.detach()
            full = full.permute(1, 2, 0)
            output = full.to('cpu')
            output = np.array(output)
            output = output[..., ::-1]
    
            output = output*255
    
            cv2.imwrite(opt.output_path + f'{os.path.splitext(image)[0]}_result.jpg',output)
        else:
            print("Image not found.")
            continue

Excuse me, how would you do a command to execute this? Could you provide an example? Thanks in advance!

coldplayer12 avatar Sep 04 '21 05:09 coldplayer12

我没有测试这个,但它应该可以工作。您只需使用图像所在的路径,而不是直接交换到图像。

在 test_one_image.py 的第 1 行,添加 import os

https://github.com/neuralchen/SimSwap/blob/186a57aa96f6422a3043021602d3586641711186/test_one_image.py#L1

从 test_one_image.py 的第 40-86 行,替换这个:

https://github.com/neuralchen/SimSwap/blob/186a57aa96f6422a3043021602d3586641711186/test_one_image.py#L40-L86

有了这个:

    pic_a = opt.pic_a_path
    img_a = Image.open(pic_a).convert('RGB')
    img_a = transformer_Arcface(img_a)
    img_id = img_a.view(-1, img_a.shape[0], img_a.shape[1], img_a.shape[2])
    
    for image in os.listdir(opt.pic_b_path):
        if image.endswith(".jpg") or filename.endswith(".png"):

            pic_b = image
            img_b = Image.open(pic_b).convert('RGB')
            img_b = transformer(img_b)
            img_att = img_b.view(-1, img_b.shape[0], img_b.shape[1], img_b.shape[2])
            
            # convert numpy to tensor
            img_id = img_id.cuda()
            img_att = img_att.cuda()
    
            #create latent id
            img_id_downsample = F.interpolate(img_id, scale_factor=0.5)
            latend_id = model.netArc(img_id_downsample)
            latend_id = latend_id.detach().to('cpu')
            latend_id = latend_id/np.linalg.norm(latend_id,axis=1,keepdims=True)
            latend_id = latend_id.to('cuda')
    
    
            ############## Forward Pass ######################
            img_fake = model(img_id, img_att, latend_id, latend_id, True)
    
    
            for i in range(img_id.shape[0]):
                if i == 0:
                    row1 = img_id[i]
                    row2 = img_att[i]
                    row3 = img_fake[i]
                else:
                    row1 = torch.cat([row1, img_id[i]], dim=2)
                    row2 = torch.cat([row2, img_att[i]], dim=2)
                    row3 = torch.cat([row3, img_fake[i]], dim=2)
    
            #full = torch.cat([row1, row2, row3], dim=1).detach()
            full = row3.detach()
            full = full.permute(1, 2, 0)
            output = full.to('cpu')
            output = np.array(output)
            output = output[..., ::-1]
    
            output = output*255
    
            cv2.imwrite(opt.output_path + f'{os.path.splitext(image)[0]}_result.jpg',output)
        else:
            print("Image not found.")
            continue

THANKS!!!And How to modify test_wholeimage_swapsingle.py?

CongYuSanXun avatar Sep 04 '21 10:09 CongYuSanXun

I created a handy script to do this:

import pathlib
import sys
import os
from os import path
import subprocess

try:
    face = sys.argv[1]
except IndexError:
    face = ''


selectedface = ''
faces_input_path = './input_faces'
video_input_path = './input_videos'
simswap_command = "python test_video_swapsingle.py --isTrain false --use_mask --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path ./__input_selected_face__ --video_path ./__input_video_file__ --output_path ./__output_file_name__ --temp_path ./temp_results --no_simswaplogo"
exit = 0

print('\n')

if not path.exists(faces_input_path): 
    print('WARNING: Cannot find ',faces_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(faces_input_path)
        print("\t", faces_input_path, "has been created. Please put some JPG/PNG files in there to start.")
    except:
        print("\t", "Unable to create directory:",faces_input_path)
    exit = 1

if not path.exists(video_input_path):
    print('WARNING: Cannot find ',video_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(video_input_path)
        print("\t", video_input_path, "has been created. Please put some MP4 files in there to start.")
    except:
        print("\t", "Unable to create directory:",video_input_path)
    exit = 1

if exit: sys.exit()


for file in pathlib.Path(faces_input_path).iterdir():
    if file.is_file():
        if face in str(file):
            selectedface = str(file)

inputvideos = []
for file in pathlib.Path(video_input_path).iterdir():
    if file.is_file():
        if '.mp4' in str(file):
            inputvideos.append(file)

if selectedface and (len(inputvideos) > 0):
    print('Selected Face:')
    print('\t',selectedface)
    print('Input Videos: ')
    for videofile in inputvideos:
        print('\t', videofile)

    for videofile in inputvideos:
        output_video_file = str(videofile).replace('input_videos', 'output')

        compiled_command = simswap_command.replace('__input_selected_face__', selectedface.replace('\\','/'))
        compiled_command = compiled_command.replace('__input_video_file__', str(videofile).replace('\\','/'))
        compiled_command = compiled_command.replace('__output_file_name__', output_video_file.replace('\\','/'))
        print('\n----------------------------------')
        print(' PROCESSING:', os.path.basename(videofile), "with face:", selectedface)
        print('----------------------------------')
        subprocess.run(compiled_command, stdout=subprocess.DEVNULL)
        # Use the below to show the output and diagnose any errors you might be getting. (Comment out the above first)
        # subprocess.run(compiled_command)
    print('\n\nSIMSWAP BATCH: FINISHED.\n\n')
elif not selectedface:
    print('WARNING: No selected face found.  Did you pass a parameter?  Correct syntax is python batch_swimswap.py john')
elif(len(inputvideos) == 0):
    print('WARNING: No input videos found in',video_input_path)

Put it in your simswap directoy, and run it like so:

python batch_process.py bob

This will face swap all images in the ./input_faces directory on to the videos in the ./input_videos directory. It should be easy to modify the commands if you want to do the different functions.

chud37 avatar Sep 14 '21 18:09 chud37

I created a handy script to do this:

import pathlib
import sys
import os
from os import path
import subprocess

try:
    face = sys.argv[1]
except IndexError:
    face = ''


selectedface = ''
faces_input_path = './input_faces'
video_input_path = './input_videos'
simswap_command = "python test_video_swapsingle.py --isTrain false --use_mask --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path ./__input_selected_face__ --video_path ./__input_video_file__ --output_path ./__output_file_name__ --temp_path ./temp_results --no_simswaplogo"
exit = 0

print('\n')

if not path.exists(faces_input_path): 
    print('WARNING: Cannot find ',faces_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(faces_input_path)
        print("\t", faces_input_path, "has been created. Please put some JPG/PNG files in there to start.")
    except:
        print("\t", "Unable to create directory:",faces_input_path)
    exit = 1

if not path.exists(video_input_path):
    print('WARNING: Cannot find ',video_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(video_input_path)
        print("\t", video_input_path, "has been created. Please put some MP4 files in there to start.")
    except:
        print("\t", "Unable to create directory:",video_input_path)
    exit = 1

if exit: sys.exit()


for file in pathlib.Path(faces_input_path).iterdir():
    if file.is_file():
        if face in str(file):
            selectedface = str(file)

inputvideos = []
for file in pathlib.Path(video_input_path).iterdir():
    if file.is_file():
        if '.mp4' in str(file):
            inputvideos.append(file)

if selectedface and (len(inputvideos) > 0):
    print('Selected Face:')
    print('\t',selectedface)
    print('Input Videos: ')
    for videofile in inputvideos:
        print('\t', videofile)

    for videofile in inputvideos:
        output_video_file = str(videofile).replace('input_videos', 'output')

        compiled_command = simswap_command.replace('__input_selected_face__', selectedface.replace('\\','/'))
        compiled_command = compiled_command.replace('__input_video_file__', str(videofile).replace('\\','/'))
        compiled_command = compiled_command.replace('__output_file_name__', output_video_file.replace('\\','/'))
        print('\n----------------------------------')
        print(' PROCESSING:', os.path.basename(videofile), "with face:", selectedface)
        print('----------------------------------')
        subprocess.run(compiled_command, stdout=subprocess.DEVNULL)
        # Use the below to show the output and diagnose any errors you might be getting. (Comment out the above first)
        # subprocess.run(compiled_command)
    print('\n\nSIMSWAP BATCH: FINISHED.\n\n')
elif not selectedface:
    print('WARNING: No selected face found.  Did you pass a parameter?  Correct syntax is python batch_swimswap.py john')
elif(len(inputvideos) == 0):
    print('WARNING: No input videos found in',video_input_path)

Put it in your simswap directoy, and run it like so:

python batch_process.py bob

This will face swap all images in the ./input_faces directory on to the videos in the ./input_videos directory. It should be easy to modify the commands if you want to do the different functions.

Thanks, this worked flawless, however there's an issue when modifying it to utilize the image scripts. They're designed to write to a specific file name, so when you process a whole batch of images, it's just overwriting the same file over and over. Not sure how I can change this behavior to write to a unique file for every process like with the scripts for video.

watertau avatar Sep 25 '21 23:09 watertau

@watertau I have actually modified this script a bunch of times since then and that was one of the problems. I've also added the ability to just generate the command, so that you can copy them and batch process long videos overnight. I dont have it on this machine but I will update this thread with the new script asap.

chud37 avatar Sep 26 '21 07:09 chud37

@chud37 Thanks for all your efforts! I have absolutely no affinity for coding, so it's pretty daunting to me just to even troubleshoot this, you know? I've been running a program to monitor and capture newly created jpg files and auto rename them. Works well enough, but that feels like a janky solution and not really ideal.

watertau avatar Sep 26 '21 19:09 watertau

This is my latest code:

import pathlib
import sys
import os
from os import path
import subprocess
from datetime import date



## ------------------------------
## Paths / Directories.  Change as needed.
## ------------------------------
faces_input_path = './input_faces'
video_input_path = 'c:/simswap/input'
video_output_path = 'c:/simswap'



## ------------------------------
## Input Face
## ------------------------------
try:
    face = sys.argv[1]
except IndexError:
    face = ''

## ------------------------------
## Set Arg[2] to show only generated commands (useful for creating a batch file to run overnight)
## ------------------------------
try:
    generate_commands_only = sys.argv[2]
except IndexError:
    generate_commands_only = 0






selectedface = ''
simswap_command = "python test_video_swapsingle.py --isTrain false --use_mask --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path ./__input_selected_face__ --video_path __input_video_file__ --output_path __output_file_name__ --temp_path ./temp_results --no_simswaplogo"
exit = 0

print('\n')


## ------------------------------
## PATH CHECKS
## ------------------------------
if not path.exists(faces_input_path): 
    print('WARNING: Cannot find ',faces_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(faces_input_path)
        print("\t", faces_input_path, "has been created. Please put some JPG/PNG files in there to start.")
    except:
        print("\t", "Unable to create directory:",faces_input_path)
    exit = 1

if not path.exists(video_input_path):
    print('WARNING: Cannot find ',video_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(video_input_path)
        print("\t", video_input_path, "has been created. Please put some MP4 files in there to start.")
    except:
        print("\t", "Unable to create directory:",video_input_path)
    exit = 1

if exit: sys.exit()

## ------------------------------
## Find file for faces
## ------------------------------
for file in pathlib.Path(faces_input_path).iterdir():
    if file.is_file():
        if face in str(file):
            selectedface = str(file)
            break

## ------------------------------
## Find input video(s)
## ------------------------------
inputvideos = []
for file in pathlib.Path(video_input_path).iterdir():
    if file.is_file():
        if '.mp4' in str(file):
            inputvideos.append(file)
        if '.webm' in str(file):
            newfilename = str(file).replace(".webm",".mp4")
            os.rename(file, newfilename)
            inputvideos.append(newfilename)

## ------------------------------
## Generate & Run Each Command for every video
## ------------------------------
if selectedface and (len(inputvideos) > 0):
    print('Selected Face:')
    print('\t',selectedface)
    print('Input Videos: ')
    for videofile in inputvideos:
        print('\t', videofile)

    counter = 0

    today = date.today()

    for videofile in inputvideos:
        output_video_file_path = video_output_path + "/" + face + "/" + today.strftime("%m-%d-%y") + "/"
        output_video_filename = os.path.basename(videofile)
        compiled_command = simswap_command.replace('__input_selected_face__', selectedface.replace('\\','/'))
        compiled_command = compiled_command.replace('__input_video_file__', '"' + str(videofile).replace('\\','/') + '"')
        compiled_command = compiled_command.replace('__output_file_name__', output_video_file_path + '"' + output_video_filename + '"')
        
        counter += 1

        print('\n----------------------------------')
        print(" PROCESSING: " + os.path.basename(videofile) + " with face: " + face +" (Video " + str(counter) + " of " + str(len(inputvideos)) + ")")
        print(' Output filename: ' + output_video_file_path + output_video_filename)

        # Check if the folder exists, if not, create it.
        if not path.exists(output_video_file_path):
            try:
                os.mkdir(output_video_file_path)
                print(" [Successfully created directory:", output_video_file_path,"]")
            except:
                print(" [Unable to create directory:",video_input_path,", program fail.]")
                sys.exit()

        print('----------------------------------')
        if generate_commands_only:
            print(compiled_command)
        else:
            subprocess.run(compiled_command, stdout=subprocess.DEVNULL)
            # Use the below to show the output and diagnose any errors you might be getting. (Comment out the above first)
            # subprocess.run(compiled_command)

    print('\n\nSIMSWAP BATCH: FINISHED.\n\n')
elif not selectedface:
    print('WARNING: No selected face found.  Did you pass a parameter?  Correct syntax is python batch_swimswap.py john')
elif(len(inputvideos) == 0):
    print('WARNING: No input videos found in',video_input_path)

You'll need to put it into the same directory as /simswap. Set save the file above (i.e. batch_simswap.py) and run it from the simswap directory like python batch_simswap bob.

Note: Make sure you edit the file first to set up the directories. You'll need to put your faces inside the ./input_faces path (again, inside the simswap directory) and change the video input path and the video output path. I added a feature today that creates a new folder with the face name and date i.e. c:/simswap/output/bob/09-26-2021. So all new videos go in their own folder, under the face name. I also created a script to speed up the multispecific faces if anyone wants that too.

chud37 avatar Sep 26 '21 20:09 chud37

This is my latest code:

import pathlib
import sys
import os
from os import path
import subprocess
from datetime import date



## ------------------------------
## Paths / Directories.  Change as needed.
## ------------------------------
faces_input_path = './input_faces'
video_input_path = 'c:/simswap/input'
video_output_path = 'c:/simswap'



## ------------------------------
## Input Face
## ------------------------------
try:
    face = sys.argv[1]
except IndexError:
    face = ''

## ------------------------------
## Set Arg[2] to show only generated commands (useful for creating a batch file to run overnight)
## ------------------------------
try:
    generate_commands_only = sys.argv[2]
except IndexError:
    generate_commands_only = 0






selectedface = ''
simswap_command = "python test_video_swapsingle.py --isTrain false --use_mask --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path ./__input_selected_face__ --video_path __input_video_file__ --output_path __output_file_name__ --temp_path ./temp_results --no_simswaplogo"
exit = 0

print('\n')


## ------------------------------
## PATH CHECKS
## ------------------------------
if not path.exists(faces_input_path): 
    print('WARNING: Cannot find ',faces_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(faces_input_path)
        print("\t", faces_input_path, "has been created. Please put some JPG/PNG files in there to start.")
    except:
        print("\t", "Unable to create directory:",faces_input_path)
    exit = 1

if not path.exists(video_input_path):
    print('WARNING: Cannot find ',video_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(video_input_path)
        print("\t", video_input_path, "has been created. Please put some MP4 files in there to start.")
    except:
        print("\t", "Unable to create directory:",video_input_path)
    exit = 1

if exit: sys.exit()

## ------------------------------
## Find file for faces
## ------------------------------
for file in pathlib.Path(faces_input_path).iterdir():
    if file.is_file():
        if face in str(file):
            selectedface = str(file)
            break

## ------------------------------
## Find input video(s)
## ------------------------------
inputvideos = []
for file in pathlib.Path(video_input_path).iterdir():
    if file.is_file():
        if '.mp4' in str(file):
            inputvideos.append(file)
        if '.webm' in str(file):
            newfilename = str(file).replace(".webm",".mp4")
            os.rename(file, newfilename)
            inputvideos.append(newfilename)

## ------------------------------
## Generate & Run Each Command for every video
## ------------------------------
if selectedface and (len(inputvideos) > 0):
    print('Selected Face:')
    print('\t',selectedface)
    print('Input Videos: ')
    for videofile in inputvideos:
        print('\t', videofile)

    counter = 0

    today = date.today()

    for videofile in inputvideos:
        output_video_file_path = video_output_path + "/" + face + "/" + today.strftime("%m-%d-%y") + "/"
        output_video_filename = os.path.basename(videofile)
        compiled_command = simswap_command.replace('__input_selected_face__', selectedface.replace('\\','/'))
        compiled_command = compiled_command.replace('__input_video_file__', '"' + str(videofile).replace('\\','/') + '"')
        compiled_command = compiled_command.replace('__output_file_name__', output_video_file_path + '"' + output_video_filename + '"')
        
        counter += 1

        print('\n----------------------------------')
        print(" PROCESSING: " + os.path.basename(videofile) + " with face: " + face +" (Video " + str(counter) + " of " + str(len(inputvideos)) + ")")
        print(' Output filename: ' + output_video_file_path + output_video_filename)

        # Check if the folder exists, if not, create it.
        if not path.exists(output_video_file_path):
            try:
                os.mkdir(output_video_file_path)
                print(" [Successfully created directory:", output_video_file_path,"]")
            except:
                print(" [Unable to create directory:",video_input_path,", program fail.]")
                sys.exit()

        print('----------------------------------')
        if generate_commands_only:
            print(compiled_command)
        else:
            subprocess.run(compiled_command, stdout=subprocess.DEVNULL)
            # Use the below to show the output and diagnose any errors you might be getting. (Comment out the above first)
            # subprocess.run(compiled_command)

    print('\n\nSIMSWAP BATCH: FINISHED.\n\n')
elif not selectedface:
    print('WARNING: No selected face found.  Did you pass a parameter?  Correct syntax is python batch_swimswap.py john')
elif(len(inputvideos) == 0):
    print('WARNING: No input videos found in',video_input_path)

You'll need to put it into the same directory as /simswap. Set save the file above (i.e. batch_simswap.py) and run it from the simswap directory like python batch_simswap bob.

Note: Make sure you edit the file first to set up the directories. You'll need to put your faces inside the ./input_faces path (again, inside the simswap directory) and change the video input path and the video output path. I added a feature today that creates a new folder with the face name and date i.e. c:/simswap/output/bob/09-26-2021. So all new videos go in their own folder, under the face name. I also created a script to speed up the multispecific faces if anyone wants that too.

Thanks so much! I tried it on batch processing videos, which worked great. I tried fiddling with your script so that it would work with batch processing images (pic a to pic b) but kept running into errors. Any chance you could adjust your script for images?

drzodozo avatar Dec 17 '21 17:12 drzodozo

@drzodozo I've tried writing the script that batch process images but for some reason the actual image isn't being processed due to errors. It queues it up and everything just doesnt actually do it. Here is the code:

import pathlib
import sys
import os
from os import path
import subprocess
from datetime import date


## ------------------------------
## Paths / Directories.  Change as needed.
## ------------------------------
faces_input_path = './input_faces'
images_input_path = 'p:/imgs/simswap/input'
images_output_path = 'p:/imgs/simswap'



## ------------------------------
## Input Face
## ------------------------------
try:
    face = sys.argv[1]
except IndexError:
    face = ''

## ------------------------------
## Set Arg[2] to show only generated commands (useful for creating a batch file to run overnight)
## ------------------------------
try:
    generate_commands_only = sys.argv[2]
except IndexError:
    generate_commands_only = 0






selectedface = ''
# simswap_command = "python test_video_swapsingle.py --isTrain false --use_mask --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path ./__input_selected_face__ --video_path __input_video_file__ --output_path __output_file_name__ --temp_path ./temp_results --no_simswaplogo"
# simswap_command = "python test_wholeimage_swapmulti.py --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path ./__input_selected_face__ --pic_b_path __input_selected_image__ --output_path __output_file_name__"
# simswap_command = "python test_wholeimage_swapmulti.py --use_mask  --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path __input_selected_face__ --pic_b_path __input_selected_image__ --output_path __output_file_name__"
simswap_command = "python test_wholeimage_swapsingle.py --isTrain false --use_mask  --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path __input_selected_image__ --pic_b_path __input_selected_face__ --temp_path ./temp_results --output_path __output_file_name__ --no_simswaplogo"
exit = 0

print('\n')



## ------------------------------
## PATH CHECKS
## ------------------------------
if not path.exists(faces_input_path): 
    print('WARNING: Cannot find ',faces_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(faces_input_path)
        print("\t", faces_input_path, "has been created. Please put some JPG/PNG files in there to start.")
    except:
        print("\t", "Unable to create ouput directory:",faces_input_path)
    exit = 1

if not path.exists(images_input_path):
    print('WARNING: Cannot find ',images_input_path, 'directory.  Attempting to create..')
    try:
        os.mkdir(images_input_path)
        print("\t", images_input_path, "has been created. Please put some MP4 files in there to start.")
    except:
        print("\t", "Unable to create input path directory:",images_input_path)
    exit = 1

if exit: sys.exit()




## ------------------------------
## Find file for faces
## ------------------------------
for file in pathlib.Path(faces_input_path).iterdir():
    if file.is_file():
        if face in str(file):
            selectedface = str(file)
            break

## ------------------------------
## Find input images(s)
## ------------------------------
inputimages = []
for file in pathlib.Path(images_input_path).iterdir():
    if file.is_file():
        if '.jpg' in str(file):
            inputimages.append(file)
        # if '.webm' in str(file):
        #     newfilename = str(file).replace(".webm",".mp4")
        #     os.rename(file, newfilename)
        #     inputimages.append(newfilename)

## ------------------------------
## Generate & Run Each Command for every image
## ------------------------------
if selectedface and (len(inputimages) > 0):
    print('Selected Face:')
    print('\t',selectedface)
    print('Input Images: ')
    for imagefile in inputimages:
        print('\t', imagefile)

    counter = 0

    today = date.today()

    for imagefile in inputimages:
        output_image_file_path = images_output_path + "/" + face + "/" + today.strftime("%m-%d-%y") + "/"
        output_image_filename = os.path.basename(imagefile)
        compiled_command = simswap_command.replace('__input_selected_face__', selectedface.replace('\\','/'))
        compiled_command = compiled_command.replace('__input_selected_image__', '"' + str(imagefile).replace('\\','/') + '"')
        compiled_command = compiled_command.replace('__output_file_name__', output_image_file_path + '"' + output_image_filename + '"')
        
        counter += 1
        
        # Check if the folder exists, if not, create it.
        if not path.exists(output_image_file_path):
            try:
                os.makedirs(output_image_file_path)
                print(" [Successfully created directory:", output_image_file_path,"]")
            except OSError as exc:
                print(" [Unable to create directory: " + output_image_file_path + " Error: "+exc+"]")
                sys.exit()

        
        if generate_commands_only:
            print(compiled_command)
        else:

            print('\n----------------------------------')
            print(" PROCESSING: " + os.path.basename(imagefile) + " with face: " + face +" (Video " + str(counter) + " of " + str(len(inputimages)) + ")")
            print(' Output filename: ' + output_image_file_path + output_image_filename)
            print('----------------------------------')

            subprocess.run(compiled_command, stdout=subprocess.DEVNULL)
            os.remove(imagefile)
            # Use the below to show the output and diagnose any errors you might be getting. (Comment out the above first)
            # subprocess.run(compiled_command)

    print('\n\nSIMSWAP BATCH: FINISHED.\n\n')
    # subprocess.Popen(r'explorer /select "'+output_image_file_path+'"')
    if not generate_commands_only: 
        os.startfile(os.path.realpath(output_image_file_path))

elif not selectedface:
    print('WARNING: No selected face found.  Did you pass a parameter?  Correct syntax is python batch_swimswap.py john')
elif(len(inputimages) == 0):
    print('WARNING: No input videos found in',images_input_path)

If you get it running, let me know. It is just a modified version of the video one. There are different simswap_command vars that could try swapping in and out to see if they work okay.

chud37 avatar Jan 02 '22 19:01 chud37

@drzodozo I've tried writing the script that batch process images but for some reason the actual image isn't being processed due to errors. It queues it up and everything just doesnt actually do it. Here is the code:

If you get it running, let me know. It is just a modified version of the video one. There are different simswap_command vars that could try swapping in and out to see if they work okay.

Thanks, @chud37. I had the same issues with the errors regarding patches and write permissions when I tried tweaking your original code. When I swap images manually, they get outputted correctly, but get the same patch error messages (they don't seem to affect the output).

But when I try the batch process script (that I tweaked), I get the same permission errors and nothing seems to happen. The folders are being written with the correct dates so I'm dumbfounded by the write permission error. I'll try your new script and see what happens.

drzodozo avatar Jan 04 '22 17:01 drzodozo

Tried your script, and unfortunately ran into the same problems. The folders write fine, but the output image file just isn't there.

drzodozo avatar Jan 05 '22 02:01 drzodozo

@drzodozo I've tried writing the script that batch process images but for some reason the actual image isn't being processed due to errors. It queues it up and everything just doesnt actually do it. Here is the code:

If you get it running, let me know. It is just a modified version of the video one. There are different simswap_command vars that could try swapping in and out to see if they work okay.

Hi! First of all, I want to say big thank @chud37 for sharing my batch processing script with everyone, it really helps me out very often! I modified the script to fit my needs and I also want to share what I got. My version of the script is adopted for the latest version of SimSwap with the ability to choose between models - 224 and 512. First, in order not to edit existed files, you need to create a scripts in the SimSwap root folder with the name test_batch_wholeimage_swapsingle.py

'''
Author: Naiyuan liu
Github: https://github.com/NNNNAI
Date: 2021-11-23 17:03:58
LastEditors: Naiyuan liu
LastEditTime: 2021-11-24 19:19:43
Description: 
'''
import cv2
import torch
import fractions
import numpy as np
from PIL import Image
import torch.nn.functional as F
from torchvision import transforms
from models.models import create_model
from options.test_options import TestOptions
from insightface_func.face_detect_crop_single import Face_detect_crop
from util.reverse2original import reverse2wholeimage
import os
from util.add_watermark import watermark_image
from util.norm import SpecificNorm
from parsing_model.model import BiSeNet

def lcm(a, b): return abs(a * b) / fractions.gcd(a, b) if a and b else 0

transformer_Arcface = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])

def _totensor(array):
    tensor = torch.from_numpy(array)
    img = tensor.transpose(0, 1).transpose(0, 2).contiguous()
    return img.float().div(255)
if __name__ == '__main__':
    opt = TestOptions().parse()

    start_epoch, epoch_iter = 1, 0
    crop_size = opt.crop_size

    torch.nn.Module.dump_patches = True
	
    if crop_size == 512:
        opt.which_epoch = 550000
        opt.name = '512'
        mode = 'ffhq'
    else:
        mode = 'None'				 
    logoclass = watermark_image('./simswaplogo/simswaplogo.png')
    model = create_model(opt)
    model.eval()

    spNorm =SpecificNorm()
    app = Face_detect_crop(name='antelope', root='./insightface_func/models')
    app.prepare(ctx_id= 0, det_thresh=0.6, det_size=(640,640),mode=mode)

    with torch.no_grad():
        pic_a = opt.pic_a_path

        img_a_whole = cv2.imread(pic_a)
        img_a_align_crop, _ = app.get(img_a_whole,crop_size)
        img_a_align_crop_pil = Image.fromarray(cv2.cvtColor(img_a_align_crop[0],cv2.COLOR_BGR2RGB)) 
        img_a = transformer_Arcface(img_a_align_crop_pil)
        img_id = img_a.view(-1, img_a.shape[0], img_a.shape[1], img_a.shape[2])

        # convert numpy to tensor
        img_id = img_id.cuda()

        #create latent id
        img_id_downsample = F.interpolate(img_id, size=(112,112))
        latend_id = model.netArc(img_id_downsample)
        latend_id = F.normalize(latend_id, p=2, dim=1)


        ############## Forward Pass ######################

        pic_b = opt.pic_b_path
        img_b_whole = cv2.imread(pic_b)

        img_b_align_crop_list, b_mat_list = app.get(img_b_whole,crop_size)
        # detect_results = None
        swap_result_list = []

        b_align_crop_tenor_list = []

        for b_align_crop in img_b_align_crop_list:

            b_align_crop_tenor = _totensor(cv2.cvtColor(b_align_crop,cv2.COLOR_BGR2RGB))[None,...].cuda()

            swap_result = model(None, b_align_crop_tenor, latend_id, None, True)[0]
            swap_result_list.append(swap_result)
            b_align_crop_tenor_list.append(b_align_crop_tenor)

        if opt.use_mask:
            n_classes = 19
            net = BiSeNet(n_classes=n_classes)
            net.cuda()
            save_pth = os.path.join('./parsing_model/checkpoint', '79999_iter.pth')
            net.load_state_dict(torch.load(save_pth))
            net.eval()
        else:
            net =None

        reverse2wholeimage(b_align_crop_tenor_list, swap_result_list, b_mat_list, crop_size, img_b_whole, logoclass, \
            os.path.join(opt.output_path), opt.no_simswaplogo,pasring_model =net,use_mask=opt.use_mask, norm = spNorm)

        print(' ')

        print('************ Done ! ************')

and batch_wholeimage_swapsingle.py

import os
import pathlib
import argparse
import subprocess
from os import path
from pathlib import Path
from datetime import datetime

faces_input_path = './simswap_batch_input_faces'
files_input_path = './simswap_batch_input_files'
image_output_path = './simswap_batch_img_result'

parser = argparse.ArgumentParser()
parser.add_argument('--crop_size', type=int, default=224, help='Crop of size of input image')
parser.add_argument("--face", type=str, default='', help="The name of face wich will be used for face swap")
args = parser.parse_args()

crop_size = args.crop_size
face = args.face

selectedface = ''
simswap_command = "python -W ignore test_batch_wholeimage_swapsingle.py --isTrain false --use_mask --crop_size __crop_size__  --name people --Arc_path arcface_model/arcface_checkpoint.tar --pic_a_path __input_selected_face__ --pic_b_path __input_image_file__ --output_path __output_file_name__ --no_simswaplogo"

simswap_command = simswap_command.replace('__crop_size__', str(crop_size))
exit = 0

## PATH CHECKS
if not path.exists(faces_input_path):
       os.mkdir(faces_input_path)
else:
    if path.exists(faces_input_path):
       pass

if not path.exists(files_input_path):
       os.mkdir(files_input_path)
else:
    if path.exists(files_input_path):
       pass
       
if not path.exists(image_output_path): 
       os.mkdir(image_output_path)
else:
    if path.exists(image_output_path):
       pass

## Find file for faces
for file in pathlib.Path(faces_input_path).iterdir():
    if file.is_file():
        if face in str(file):
            selectedface = str(file)

## Find input image(s)
inputimages = []
for file in pathlib.Path(files_input_path).iterdir():
    if file.is_file():
        if '.jpg' in str(file): inputimages.append(file)
        elif '.jpeg' in str(file): inputimages.append(file)
        elif '.png' in str(file): inputimages.append(file)

## Generate & Run Each Command for every image
if selectedface and (len(inputimages) > 0):
    print('\r')
    print('Selected Face:')
    print('\r',os.path.basename(selectedface))
    print('\r')
    print('\r')
    print('Input Images: ')
    for imagefile in inputimages:
        print('\r',os.path.basename(imagefile))

    counter = 0

    today = datetime.now().strftime

    for imagefile in inputimages:
        output_image_file_path = image_output_path + "/"
        output_image_filename = Path(selectedface).stem + '_' + today("(%H.%M.%S)") + '_' + Path(imagefile).stem + '.jpg'
        compiled_command = simswap_command.replace('__input_selected_face__', '"' + selectedface.replace('\\','/') + '"')
        compiled_command = compiled_command.replace('__input_image_file__', '"' + str(imagefile).replace('\\','/') + '"')
        compiled_command = compiled_command.replace('__output_file_name__', output_image_file_path + '"' + output_image_filename + '"')

        counter += 1

        print('\r')
        print("PROCESSING: " + os.path.basename(imagefile) + " with face: " + os.path.basename(selectedface) + " (Image " + str(counter) + " of " + str(len(inputimages)) + ")")
        print('\r','Output filename: ' + output_image_file_path + output_image_filename)
        print('\r')

        # Check if the folder exists, if not, create it.
        if not path.exists(output_image_file_path):
               os.mkdir(output_image_file_path)
        else:
            if path.exists(output_image_file_path):
               pass

        subprocess.run(compiled_command, shell=True, stdout=subprocess.DEVNULL)

    print('\n\nSIMSWAP BATCH: FINISHED.\n')
elif not selectedface:
    print('\r')
    print('WARNING: No selected face found')
elif(len(inputimages) == 0):
    print('\r')
    print('WARNING: No input images found in',files_input_path)

Then go to the SimSwap folder and run python batch_wholeimage_swapsingle.py. After first run in the SimSwap folder will be created new folders: simswap_batch_img_result, simswap_batch_input_faces and simswap_batch_input_files. Put in simswap_batch_input_faces image with face and destination image in simswap_batch_input_files. Then run python batch_wholeimage_swapsingle.py again. Swaped images will be saved in simswap_batch_img_result folder with names like Iron_man_(15.49.13)_multi_people.jpg, where (15.49.13) - is the time of file creaton. You can also run a script with options: --crop_size 224 or 512 and --face (name of the specific face). If you run script without this options, will be used default 224. Example: python batch_wholeimage_swapsingle.py will run with default options, python batch_wholeimage_swapsingle.py --crop_size 512 --face Iron_man will swap images with crop size 512 and specific name of the face. Also you can combine options, like python batch_wholeimage_swapsingle.py --face Iron_man or python batch_wholeimage_swapsingle.py --crop_size 512. Tested on GTX 1060 6GB, Windows 10 and Debian WSL2

netrunner-exe avatar Jan 05 '22 14:01 netrunner-exe

Wonderful--works perfectly!

drzodozo avatar Jan 06 '22 19:01 drzodozo

@netrunner-exe I tried your script but it failed with this error:

Traceback (most recent call last):
  File "test_batch_wholeimage_swapsingle.py", line 68, in <module>
    img_id = img_id.cuda()
  File "/root/anaconda3/envs/simswap/lib/python3.6/site-packages/torch/cuda/__init__.py", line 164, in _lazy_init
    raise AssertionError("Torch not compiled with CUDA enabled")
AssertionError: Torch not compiled with CUDA enabled

How could it be solved?

I'm running under WSL 2 on Windows 10, and I have not any CUDA/NVIDIA card in my PC.

pidgeon777 avatar Jan 21 '22 03:01 pidgeon777

EDIT: I found the issue.

The content of your script, test_batch_wholeimage_swapsingle.py, is taken from test_wholeimage_swapsingle.py.

The fact is that test_wholeimage_swapsingle.py has recently been updated by the original author to also consider those cases where CUDA is not available. For example, it went from:

img_id = img_id.cuda()

to:

img_id = img_id.to(torch.device('cuda:0' if torch.cuda.is_available() else 'cpu'))

and similar changes elsewhere in the script.

Here how test_batch_wholeimage_swapsingle should be to be aligned with the last version:

'''
Author: Naiyuan liu
Github: https://github.com/NNNNAI
Date: 2021-11-23 17:03:58
LastEditors: Naiyuan liu
LastEditTime: 2021-11-24 19:19:43
Description: 
'''

import cv2
import torch
import fractions
import numpy as np
from PIL import Image
import torch.nn.functional as F
from torchvision import transforms
from models.models import create_model
from options.test_options import TestOptions
from insightface_func.face_detect_crop_single import Face_detect_crop
from util.reverse2original import reverse2wholeimage
import os
from util.add_watermark import watermark_image
from util.norm import SpecificNorm
from parsing_model.model import BiSeNet

def lcm(a, b): return abs(a * b) / fractions.gcd(a, b) if a and b else 0

transformer_Arcface = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])

def _totensor(array):
    tensor = torch.from_numpy(array)
    img = tensor.transpose(0, 1).transpose(0, 2).contiguous()
    return img.float().div(255)
if __name__ == '__main__':
    opt = TestOptions().parse()

    start_epoch, epoch_iter = 1, 0
    crop_size = opt.crop_size

    torch.nn.Module.dump_patches = True
    if crop_size == 512:
        opt.which_epoch = 550000
        opt.name = '512'
        mode = 'ffhq'
    else:
        mode = 'None'				 
    logoclass = watermark_image('./simswaplogo/simswaplogo.png')
    model = create_model(opt)
    model.eval()

    spNorm =SpecificNorm()
    app = Face_detect_crop(name='antelope', root='./insightface_func/models')
    app.prepare(ctx_id= 0, det_thresh=0.6, det_size=(640,640),mode=mode)

    with torch.no_grad():
        pic_a = opt.pic_a_path

        img_a_whole = cv2.imread(pic_a)
        img_a_align_crop, _ = app.get(img_a_whole,crop_size)
        img_a_align_crop_pil = Image.fromarray(cv2.cvtColor(img_a_align_crop[0],cv2.COLOR_BGR2RGB)) 
        img_a = transformer_Arcface(img_a_align_crop_pil)
        img_id = img_a.view(-1, img_a.shape[0], img_a.shape[1], img_a.shape[2])

        # convert numpy to tensor
        img_id = img_id.to(torch.device('cuda:0' if torch.cuda.is_available() else 'cpu'))

        #create latent id
        img_id_downsample = F.interpolate(img_id, size=(112,112))
        latend_id = model.netArc(img_id_downsample)
        latend_id = F.normalize(latend_id, p=2, dim=1)


        ############## Forward Pass ######################

        pic_b = opt.pic_b_path
        img_b_whole = cv2.imread(pic_b)

        img_b_align_crop_list, b_mat_list = app.get(img_b_whole,crop_size)
        # detect_results = None
        swap_result_list = []

        b_align_crop_tenor_list = []

        for b_align_crop in img_b_align_crop_list:

            b_align_crop_tenor = _totensor(cv2.cvtColor(b_align_crop,cv2.COLOR_BGR2RGB))[None,...].to(torch.device('cuda:0' if torch.cuda.is_available() else 'cpu'))

            swap_result = model(None, b_align_crop_tenor, latend_id, None, True)[0]
            swap_result_list.append(swap_result)
            b_align_crop_tenor_list.append(b_align_crop_tenor)

        if opt.use_mask:
            n_classes = 19
            net = BiSeNet(n_classes=n_classes)
            net.to(torch.device('cuda:0' if torch.cuda.is_available() else 'cpu'))
            save_pth = os.path.join('./parsing_model/checkpoint', '79999_iter.pth')
            net.load_state_dict(torch.load(save_pth)) if torch.cuda.is_available() else net.load_state_dict(torch.load(save_pth, map_location=torch.device('cpu')))
            net.eval()
        else:
            net =None

        reverse2wholeimage(b_align_crop_tenor_list, swap_result_list, b_mat_list, crop_size, img_b_whole, logoclass, \
            os.path.join(opt.output_path), opt.no_simswaplogo,pasring_model =net,use_mask=opt.use_mask, norm = spNorm)

        print(' ')

        print('************ Done ! ************')

At the end, the base and modified scripts are identical except for the following which goes from:

os.path.join(opt.output_path, 'result_whole_swapsingle.jpg'), opt.no_simswaplogo,pasring_model =net,use_mask=opt.use_mask, norm = spNorm)

to:

os.path.join(opt.output_path), opt.no_simswaplogo,pasring_model =net,use_mask=opt.use_mask, norm = spNorm)

pidgeon777 avatar Jan 21 '22 04:01 pidgeon777

Hi! First of all, I want to say big thank @chud37 for sharing my batch processing script with everyone, it really helps me out very often!

Sorry - Just to clarify - I wrote that script I posted? If it helps you then great. I use it on videos all the time. Some day soon I'm going to give the 512 version a try.

chud37 avatar Jan 21 '22 08:01 chud37

Hey all, so sorry for the late reply after starting this thread. I tried out the code and it works perfectly. SUCH a timesaver. Thankyou so much :)

Wythneth avatar Mar 31 '22 23:03 Wythneth

Thanks for sharing this you guys, so I modified the code so that the model just initializes once then goes through the folders and saves the result instead of calling command for every new inputs.

Average time of a python command on 1 image Tesla P100 16GB is about 12s while keeping the model idle reduces processing time for each image to ~2s. Another thing I notice that on a P100 16GB, GPU utilization is mostly < 25% while occupied is always < 3GB. This suggest that we can initialize at least 4 models on a GPU and distribute input images via threading. I will try to combine our ideas to work in a more universal way for other tests too!

'''Author: Naiyuan liu
Github: https://github.com/NNNNAI
Date: 2021-11-23 17:03:58
LastEditors: Naiyuan liu
LastEditTime: 2021-11-24 19:19:43
Description: 
'''
import cv2
import torch
import fractions
import numpy as np
from PIL import Image
import torch.nn.functional as F
from torchvision import transforms
from models.models import create_model
from options.test_options import TestOptions
from insightface_func.face_detect_crop_single import Face_detect_crop
from util.reverse2original import reverse2wholeimage
import os
from util.add_watermark import watermark_image
from util.norm import SpecificNorm
from parsing_model.model import BiSeNet

def lcm(a, b): return abs(a * b) / fractions.gcd(a, b) if a and b else 0

transformer_Arcface = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])

def _totensor(array):
    tensor = torch.from_numpy(array)
    img = tensor.transpose(0, 1).transpose(0, 2).contiguous()
    return img.float().div(255)
if __name__ == '__main__':
    opt = TestOptions().parse()
    start_epoch, epoch_iter = 1, 0
    crop_size = opt.crop_size

    torch.nn.Module.dump_patches = True
    if crop_size == 512:
        opt.which_epoch = 550000
        opt.name = '512'
        mode = 'ffhq'
    else:
        mode = 'None'
    logoclass = watermark_image('./simswaplogo/simswaplogo.png')
    model = create_model(opt)
    model.eval()

    spNorm =SpecificNorm()
    app = Face_detect_crop(name='antelope', root='./insightface_func/models')
    app.prepare(ctx_id= 0, det_thresh=0.6, det_size=(640,640),mode=mode)

    ####### Process dir #######
    path_b = opt.pic_b_path
    images_b = []
    for dirs, folders, files in os.walk(path_b):
      for file in files:
        if '.jpg' in file:
          images_b.append(dirs+file) 
    ###########################

    with torch.no_grad():
        pic_a = opt.pic_a_path

        img_a_whole = cv2.imread(pic_a)
        img_a_align_crop, _ = app.get(img_a_whole,crop_size)
        img_a_align_crop_pil = Image.fromarray(cv2.cvtColor(img_a_align_crop[0],cv2.COLOR_BGR2RGB)) 
        img_a = transformer_Arcface(img_a_align_crop_pil)
        img_id = img_a.view(-1, img_a.shape[0], img_a.shape[1], img_a.shape[2])

        # convert numpy to tensor
        img_id = img_id.cuda()

        #create latent id
        img_id_downsample = F.interpolate(img_id, size=(112,112))
        latend_id = model.netArc(img_id_downsample)
        latend_id = F.normalize(latend_id, p=2, dim=1)


        ############## Forward Pass ######################

        #pic_b = opt.pic_b_path
        for pic_b in images_b:
          img_b_whole = cv2.imread(pic_b)

          img_b_align_crop_list, b_mat_list = app.get(img_b_whole,crop_size)
          # detect_results = None
          swap_result_list = []

          b_align_crop_tenor_list = []

          for b_align_crop in img_b_align_crop_list:

              b_align_crop_tenor = _totensor(cv2.cvtColor(b_align_crop,cv2.COLOR_BGR2RGB))[None,...].cuda()

              swap_result = model(None, b_align_crop_tenor, latend_id, None, True)[0]
              swap_result_list.append(swap_result)
              b_align_crop_tenor_list.append(b_align_crop_tenor)

          if opt.use_mask:
              n_classes = 19
              net = BiSeNet(n_classes=n_classes)
              net.cuda()
              save_pth = os.path.join('./parsing_model/checkpoint', '79999_iter.pth')
              net.load_state_dict(torch.load(save_pth))
              net.eval()
          else:
              net =None

          reverse2wholeimage(b_align_crop_tenor_list, swap_result_list, b_mat_list, crop_size, img_b_whole, logoclass, \
              os.path.join(opt.output_path, '{}'.format(pic_b.split('/')[-1])), opt.no_simswaplogo,pasring_model =net,use_mask=opt.use_mask, norm = spNorm)

          print(' ')

          print('************ Done ! ************')

minhtcai avatar Jun 21 '22 11:06 minhtcai

Hi everyone - I've actually forked Simswap to create a new Repo: BatchSimSwap which is does many things like automated batch video swapping, swapping from a website that contains images, swapping a folder of images etc. I've changed the above script I wrote to be OOP so there are global options and variables and good debug error messages to. I'm still working on it but its growing each day. You can find it here:

https://github.com/chud37/BatchSimSwap

chud37 avatar Sep 18 '22 16:09 chud37

[chud37] Thank you. I think you have better describe how to use your fork. I see this number of bat files but a bit lost. Can you put such examples for every each one into your descriprion? Also you can put some exapmle files to see the progress and results

SerZhyAle avatar Sep 18 '22 23:09 SerZhyAle

@SerZhyAle Yes I have only just started the probject a few days a go. Give me a week to get it together and I'll have good documentation too. Im also working on supressing a lot of the useless warning messages too, which makes using SimSwap a lot nicer. So far the only available functions are bs-url {name} {url} and bs-video 1 bob (This command will make batch processing look for the following folder: batch_processing/input/input_1 and will then convert all videos inside there to the face bob.jpg (stored in batch_processing/input_faces/bob.jpg`))

This should give you something to get started with.

chud37 avatar Sep 19 '22 06:09 chud37