glucauze / sd-webui-faceswaplab

Extended faceswap extension for StableDiffusion web-ui with multiple faceswaps, inpainting, checkpoints, ....
https://glucauze.github.io/sd-webui-faceswaplab/
GNU Affero General Public License v3.0
731 stars 97 forks source link

Replace Face based on size binning #2

Open Oceanswave opened 1 year ago

Oceanswave commented 1 year ago

Is your feature request related to a problem? Please describe. Often a face that is detected isn't the face that I'd like to replace. Face Similarity/Filtering helps, but often I want to replace a face given the actual face size.

Often times a subject face I'd like to swap is the subject, and thus in the foreground, and large. Secondary faces appear in the background, and are smaller.

Describe the solution you'd like Given a small/medium/large 'Size' setting on a Face Swap Unit, Loop through the detected faces in the generated image. Create a histogram of these faces. Bin the faces into small/medium/large bins. Swap the face in the specified size bin at the specified index.

An optional Face Swap Unit setting would sort each bin by either the detected generated face age or the face's euclidean distance from the generated image center.

Psudocode:

# Calculate the width of the image and determine the image center
image_height, image_width = img_data.shape[:2]
image_center = (image_width // 2, image_height // 2)

# Calculate areas and categorize bounding boxes
areas = [(face.bbox[2] - face.bbox[0]) * (face.bbox[3] - face.bbox[1]) for face in gender_faces]

# Use numpy histogram to categorize into 3 bins
_, bin_edges = np.histogram(areas, bins=3)

# Place the faces in bins
bins = {'small': [], 'medium': [], 'large': []}
for face in gender_faces:
    area = (face.bbox[2] - face.bbox[0]) * (face.bbox[3] - face.bbox[1])
    if area < bin_edges[1]:
        bins['small'].append(face)
    elif area < bin_edges[2]:
        bins['medium'].append(face)
    else:
        bins['large'].append(face)

# Sort bins by setting
sorted_bins = {}
for size in ['large', 'medium', 'small']:
    if (sort = "center")
    # sort by distance from center
      sorted_bins[size] = sorted(
        bins[size], key=lambda face: ((face.bbox[2] + face.bbox[0]) / 2 - image_center[0]) ** 2 + ((face.bbox[3] + face.bbox[1]) / 2 - image_center[1]) ** 2
    # )
    else (sort = "age")
    # sort by age ascending
      sorted_bins[size] = sorted(bins[size], key=lambda face: face.age)

Describe alternatives you've considered Face similarity, however this doesn't work on novel faces. Adding a named person, e.g. Albert Einstein, sometimes skews the generated image to contain particulars of that person/training that are undesirable in some instances or make it difficult to combine with other aspects contained in the prompt.

Additional context Upon request.

glucauze commented 1 year ago

It's an interesting approach indeed. I think I've pretty much got the idea. From a coding standpoint, it's certainly doable even though it does require quite a lot of adaptations. At first glance, I would say it requires:

A potentially annoying point is the ergonomics of the interface to allow this choice in a comprehensible way. I think we need to keep the interface relatively simple (it's already pretty complicated ^^). Perhaps a checkbox.

I'm not saying that it's not doable or that I won't do it. But it's just too many modifications for now. Let's just say it's a little too ambitious for the moment. However, if you come up with a working prototype, why not :)

drdancm commented 10 months ago

This problem comes up with photos of an audience with the subject of interest in the foreground, face is large, but the FaceSwap finds really small faces and it is very hard to even count how many of the background faces are going to be targeted.

It's not easy because partial faces are sometimes targeted, and other times they are not.

I suppose it is not possible to solve this an other problems by (User Option) simply having the user draw a virtual x across the target face(s) or some sort of mark, maybe even M for Male and F for Female.