Holgers Sammelsurium

Fotografie, Reisen, Nerdkrams

Gesichter automatisch mit Python „Blurren“

Ich bin generell kein großer Freund von Menschen auf Fotos, also Menschen, die irgendwie zufällig mit ins Bild geraten sind, weil sie in der Nähe dessen standen, was ich fotografieren will. Von den ästhetischen Gründen abgesehen, sind Bilder mit Menschen auch eine rechtliche Grauzone und mir ist nicht klar wann ich ein Bild noch im Web verwenden kann und wann eben nicht mehr. Manche Fotografen argumentieren, dass die künstlerische Freiheit das Recht auf das eigene Bild übersteigt, ich halte das aber für schwierig und habe keine Lust vor den Kadi gezerrt zu werden.

Ich bin die Tage mal auf die Idee gekommen zu suchen welche Software automatisch Gesichter in Fotos erkennen und diese „blurren“ oder verpixeln kann. In Photoshop geht sowas natürlich auch, aber man muss es halt selbst tun. Ein Bild mit so einer Verfremdung zu zeigen ist zwar nicht ganz so sexy, aber vermutlich schon weniger Grauzone als das Bild mit erkennbarem Gesicht.

Zu meiner Verwunderung gibt es da gar nicht so viel, ich fand v.a. Handy Apps, was aber nicht das ist, was ich haben will.

Zu meiner großen Freude fand ich auch eine Python Bibliothek OpenCV, die mit fertig trainierten Modellen Face Detection betreiben kann. Das finde ich viel besser, da ich ohnehin schon Skripte nutze, um Fotos zu verkleinern und mit einem Rahmen „aufzuhübschen“. Zu OpenCV gibt es viele Tutorials, in einem davon fand ich lauffähigen Code, der mehr oder weniger schon das macht, was ich will. Den habe ich mir dann kopiert und in mein Skript eingebaut.

Per pip3 muss man noch einige Abhängigkeiten installieren (pip3 install Pillow numpy opencv-python) und auch die folgenden beiden Dateien (das Modell) runterladen und irgendwo abspeichern.

  • https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt
  • https://raw.githubusercontent.com/opencv/opencv_3rdparty/dnn_samples_face_detector_20180205_fp16/
    res10_300x300_ssd_iter_140000_fp16.caffemodel

Das Skript rechnet das Eingabebild herunter und macht die Face Detection auf dem kleinen Bild. Es kann vorkommen, dass Gesichter nicht zuverlässig erkannt werden, wenn diese ohnehin schon relativ klein auf dem ursprünglich großen Bild sind. (300, 300), wie ursprünglich im Skript vorgeschlagen, funktionierte bei mir nicht gut. Die Größe (600, 600) funktioniert hingegen gut und treibt die Rechenzeit auch nicht ins Unendliche.

import cv2
import numpy as np
import glob
from PIL import Image, ImageOps

# https://www.thepythoncode.com/article/blur-faces-in-images-using-opencv-in-python
def blurFaces(image):
    h, w = image.shape[:2]
    kernel_width = (w // 7) | 1
    kernel_height = (h // 7) | 1
    blob = cv2.dnn.blobFromImage(image, 1.0, (600, 600), (104.0, 177.0, 123.0))
    model.setInput(blob)
    output = np.squeeze(model.forward())
    for i in range(0, output.shape[0]):
        confidence = output[i, 2]
        if confidence > 0.4:
            box = output[i, 3:7] * np.array([w, h, w, h])
            start_x, start_y, end_x, end_y = box.astype(int)
            face = image[start_y: end_y, start_x: end_x]
            face = cv2.GaussianBlur(face, (kernel_width, kernel_height), 0)
            image[start_y: end_y, start_x: end_x] = face
    return image

def resizeAndAddBorder(cv2_image, longestside):
    numpy_array = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
    img = Image.fromarray(numpy_array)
    w, h, = img.size

    if w >= h:
        x = w/longestside
        w = longestside
        h = round(h/x)
    else:
        x = h/longestside
        h = longestside
        w = round(w/x)

    img = img.resize((w, h))
    img = ImageOps.expand(img, border=1, fill='white')
    img = ImageOps.expand(img, border=1, fill='black')
    img = ImageOps.expand(img, border=25, fill='white')
    return img


prototxt_path = "pfad/nach/deploy.prototxt"
model_path = "pfad/nach/res10_300x300_ssd_iter_140000_fp16.caffemodel"
model = cv2.dnn.readNetFromCaffe(prototxt_path, model_path)

files = glob.glob("*.jpg")

for file in files:
    tmp = file.split(".")
    out = f"{tmp[0]}-processed.{tmp[1]}"
    image = cv2.imread(file)
    image = blurFaces(image)
    img = resizeAndAddBorder(image, 1200)
    img.save(out)

Beitrag veröffentlicht am

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert