He estado escribiendo blogs sobre cafés y restaurantes durante mucho tiempo, pero me resultaba muy tedioso poner mosaico a las caras cada vez que subía fotos.
Naver y Tistory también ofrecen soporte para mosaicos automáticos, pero si hay 30 fotos, tienes que presionar cada una y la tasa de reconocimiento no era buena.
Así que decidí hacerlo por mi cuenta.
1. Estructura de Carpetas
La estructura de carpetas es la siguiente.
Dentro de la carpeta llamada masaic hay carpetas y fotos separadas por cada café.
Se exploran estas rutas para aplicar el mosaico a las imágenes.
root
├─ face.py
└─ mosaic
├─ Revisión Cafetería Fuerte Canguro
│ └─ imagenes.png
└─ Revisión Cafetería Débil Canguro
└─ imagenes.jpg2. Modelo de Aprendizaje
No tiene sentido entrenar un modelo de reconocimiento facial solo para un blog.
Afortunadamente, alguien generoso ya ha entrenado un modelo para el reconocimiento facial.
Podemos descargar el modelo con un clic.
3. Cargar Imágenes
Primero, intentemos cargar imágenes con pathlib y opencv.
El problema es que opencv no reconoce rutas con caracteres en coreano.
Podemos resolver esto creando una función.
from pathlib import Path
import cv2
def imread(file, flags=cv2.IMREAD_COLOR, dtype=np.uint8):
try:
n = np.fromfile(file, dtype)
img = cv2.imdecode(n, flags)
return img
except Exception as e:
print(e)
return None
def imwrite(file, img, params=None):
try:
suffix = Path(file).suffix
result, n = cv2.imencode(suffix, img, params)
if result:
with open(file, mode='w+b') as f:
n.tofile(f)
return True
else:
return False
except Exception as e:
print(e)
return FalseY usando iterdir e is_dir con pathlib, podemos revisar los archivos internos con un bucle for anidado.
Solo carguemos archivos de imagen cuando la extensión sea de un archivo de imagen.
Como a veces YOLO también se equivoca al hacer el mosaico, también creamos una carpeta de respaldo.
rootpath = Path.cwd()
blur_ratio = 100
folders = Path.cwd()
for folder in folders.iterdir():
if folder.is_dir():
backupFolder = folder / "backup"
backupFolder.mkdir(exist_ok=True)
for imgPath in folder.iterdir():
if imgPath.suffix == ".png" or imgPath.suffix ==".jpg" or imgPath.suffix ==".JPG" or imgPath.suffix ==".jpeg" or imgPath.suffix ==".PNG":
img = imread(str(imgPath))4. Detección de Rostros
El código de detección de rostros disponible en GitHub es muy sencillo.
Cargamos la imagen y el modelo de aprendizaje, luego calculamos con model.predict y recorremos el interior para recuperar la posición del rostro.
from pathlib import Path
import matplotlib.pyplot as plt
import cv2
import numpy as np
from ultralytics import YOLO
cwd = Path.cwd()
model = YOLO(cwd / 'yolov11n-face.pt')
picture = cv2.imread(cwd "/faces.jpg")
results = model.predict(picture)
# iterate detection results
for model in results:
img = np.copy(model.orig_img)
para = model.boxes
# iterate each object contour
for box in para:
x1, y1, x2, y2 = box.xyxy[0]
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
h, w = y2-y1, x2-x1
picture = cv2.rectangle(picture, (x1,y1), (x2,y2), (255,0,0), 3)
picture = cv2.cvtColor(picture,cv2.COLOR_BGR2RGB)
plt.imshow(picture)
plt.show()Al ejecutar la imagen de ejemplo y el código, podemos obtener los siguientes resultados.

5. Finalizando el Código
Después de encontrar rostros con el código anterior, en lugar de dibujar un cuadro, haciendo un desenfoque, el mosaico automático se completa.
El desenfoque se realiza desenfocando la imagen con cv2.blur y reemplazando la imagen en esa ubicación con la desenfocada.
A continuación se muestra el código completo.
from pathlib import Path
import cv2
import numpy as np
from ultralytics import YOLO
def imread(file, flags=cv2.IMREAD_COLOR, dtype=np.uint8):
try:
n = np.fromfile(file, dtype)
img = cv2.imdecode(n, flags)
return img
except Exception as e:
print(e)
return None
def imwrite(file, img, params=None):
try:
suffix = Path(file).suffix
result, n = cv2.imencode(suffix, img, params)
if result:
with open(file, mode='w+b') as f:
n.tofile(f)
return True
else:
return False
except Exception as e:
print(e)
return False
rootpath = Path.cwd()
model = YOLO(rootpath/'yolov11n-face.pt')
blur_ratio = 100
folders = Path(rootpath/"mosaic")
for folder in folders.iterdir():
if folder.is_dir():
backupFolder = folder / "backup"
backupFolder.mkdir(exist_ok=True)
for imgPath in folder.iterdir():
if imgPath.suffix == ".png" or imgPath.suffix ==".jpg" or imgPath.suffix ==".JPG" or imgPath.suffix ==".jpeg" or imgPath.suffix ==".PNG":
img = imread(str(imgPath))
backupImgPath = backupFolder / f"{imgPath.stem}.webp"
imwrite(str(backupImgPath), img, [cv2.IMWRITE_WEBP_QUALITY, 90])
results = model.predict(img, show=False)
boxes = results[0].boxes.xyxy.cpu().tolist()
for box in boxes:
obj = img[int(box[1]):int(box[3]), int(box[0]):int(box[2])]
blur_obj = cv2.blur(obj, (blur_ratio, blur_ratio))
img[int(box[1]):int(box[3]), int(box[0]):int(box[2])] = blur_obj
# iterate detection results
newImgPath = imgPath.parent / f"{imgPath.stem}.webp"
imgPath.unlink()
imwrite(str(newImgPath), img, [cv2.IMWRITE_WEBP_QUALITY, 90])
댓글을 불러오는 중...