project_anon / utils.py
intuitive262's picture
Removed the pesky comment, my prof told me to add to display him how you push code to an HF Space.<sigh>
d379057
import cv2
from ultralight import UltraLightDetector
from ultralight.utils import draw_faces
import time
import os
import asyncio
import numpy as np
def load_caffe_models():
models_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "age_gender_models")
age_net = cv2.dnn.readNet(
os.path.join(models_dir, "age_net.caffemodel"),
os.path.join(models_dir, "age_deploy.prototxt")
)
gender_net = cv2.dnn.readNet(
os.path.join(models_dir, "gender_net.caffemodel"),
os.path.join(models_dir, "gender_deploy.prototxt")
)
return age_net, gender_net
async def detect_faces_frame(detector, frame=None):
if frame is None:
print("No frames obtained!")
return list()
else:
# define age and gender list
age_list = ['0-2', '4-6', '8-12', '15-20', '25-32', '38-43', '48-53', '60+']
gender_list = ['Male', 'Female']
# detect the faces and load age & gender detection models
boxes, scores = detector.detect_one(frame)
age_model, gender_model = load_caffe_models()
results = []
for i, box in enumerate(boxes):
x1, y1, x2, y2 = box.astype(int)
padding_x = int((x2 - x1) * 0.15)
padding_y = int((y2 - y1) * 0.15)
height, width = frame.shape[:2]
x1_pad = max(0, x1 - padding_x)
y1_pad = max(0, y1 - padding_y)
x2_pad = min(width, x2 + padding_x)
y2_pad = min(height, y2 + padding_y)
box = np.array([x1_pad, y1_pad, x2_pad, y2_pad])
face_img = frame[y1_pad:y2_pad, x1_pad:x2_pad]
if face_img.shape[0] < 10 or face_img.shape[1] < 10:
continue
blob = cv2.dnn.blobFromImage(
face_img, 1.0, (227, 227),
(78.4263377603, 87.7689143744, 114.895847746),
swapRB=False
)
gender_model.setInput(blob)
gender_preds = gender_model.forward()
gender = gender_list[gender_preds[0].argmax()]
gender_confidence = float(gender_preds[0].max())
age_model.setInput(blob)
age_preds = age_model.forward()
age = age_list[age_preds[0].argmax()]
age_confidence = float(age_preds[0].max())
results.append({
'index': i,
'box': box.tolist(),
'score': float(scores[i]),
'gender': gender,
'gender_confidence': gender_confidence,
'age': age,
'age_confidence': age_confidence
})
return results
def apply_black_patch(frame, face_img, color=(0,0,0)):
"""Apply black patch to face region"""
if frame is None or not face_img:
return frame
x1, y1, x2, y2 = map(int, face_img["box"])
frame[y1:y2, x1:x2] = color
return frame
def apply_gaussian_blur(frame, face_img, blur_factor=40):
"""Apply strong Gaussian blur to face region"""
if frame is None or not face_img:
return frame
x1, y1, x2, y2 = map(int, face_img['box'])
face_region = frame[y1:y2, x1:x2]
# Ensure blur_factor is odd (requirement for GaussianBlur)
if blur_factor % 2 == 0:
blur_factor += 1
# Apply blur
blurred = cv2.GaussianBlur(face_region, (blur_factor, blur_factor), 0)
frame[y1:y2, x1:x2] = blurred
return frame
def apply_pixelation(frame, face_img, blocks=8):
"""Apply pixelation effect to face region"""
if frame is None or not face_img:
return frame
x1, y1, x2, y2 = map(int, face_img['box'])
face_region = frame[y1:y2, x1:x2]
height, width = face_region.shape[:2]
# Create heavy pixelation (small number of blocks = larger pixels)
temp = cv2.resize(face_region, (blocks, blocks), interpolation=cv2.INTER_LINEAR)
pixelated = cv2.resize(temp, (width, height), interpolation=cv2.INTER_NEAREST)
frame[y1:y2, x1:x2] = pixelated
return frame
async def apply_blur(
detected_faces, # Can not be None, mandatory argument
frame=None,
filters=None,
selected_faces=[],
operation=0, # default Gaussian Blur(High Kernel, blur factor 30); Other values are: 1 -> Black Patch(Simple Occlusion), 2 -> Pixelation(Heavy Mosaicing)
output_path_root=None
):
# suppose i'm processing the video, how can i play it while processing it? also, post processing how do i play it? i'd be uing flask as the backend
"""
if filters is None:
# blur all faces
else:
if filters["age"] is None or len(filters["age"]) == 0:
# blur faces based on gender
elif filters["gender"] is None or len(filters["gender"]) == 0:
# blur faces based on age
else:
# blur faces based on both age and gender
# Implement only if you have time
if selected_faces is not None:
# blur selected_faces
"""
if filters is None:
# blur all faces
for face_img in detected_faces:
selected_faces.append({"box": face_img["box"]})
else:
if len(filters["gender"]) != 0:
for face_img in detected_faces:
if face_img["gender"] in filters["gender"]:
selected_faces.append({"box": face_img["box"]})
if len(filters["age"]) != 0:
for face_img in detected_faces:
if face_img["age"] in filters["age"]:
selected_faces.append({"box": face_img["box"]})
if len(selected_faces) != 0:
for face_img in selected_faces:
if operation == 0:
frame = apply_gaussian_blur(frame, face_img=face_img)
elif operation == 1:
frame = apply_black_patch(frame, face_img=face_img)
elif operation == 2:
frame = apply_pixelation(frame, face_img=face_img)
return frame
async def process_input(
image_path=None,
video_path=None,
output_path_root=None,
filters=None,
operation=0,
selected_faces=[]
):
detector = UltraLightDetector()
if image_path is not None:
output_path = f"{output_path_root}/image/output_image.jpeg"
frame = cv2.imread(image_path)
predictions = await detect_faces_frame(frame=frame, detector=detector)
frame = await apply_blur(
predictions,
frame=frame,
filters=filters,
selected_faces=selected_faces,
operation=operation,
output_path_root=output_path_root
)
cv2.imwrite(output_path, frame)
print("Output saved successfully!")
cv2.imshow("Result Image", frame)
cv2.waitKey(0)
elif video_path is not None:
output_path = f"{output_path_root}/video/output_video.mp4"
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print(f"Error: Could not open video {video_path}")
return [], []
org_fps = cap.get(cv2.CAP_PROP_FPS)
frame_skip = max(1, round(org_fps / 30))
frame_count = 0
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, org_fps, (width, height))
all_predictions = []
while True:
ret, frame = cap.read()
if not ret:
break
if frame_count % frame_skip == 0:
predictions = await detect_faces_frame(frame=frame, detector=detector)
all_predictions.append(predictions)
out.write(frame)
frame_count += 1
cap.release()
out.release()
print(f"Video processing complete. Output saved to {output_path}")
else:
print("Error: No input provided")
cv2.destroyAllWindows()
if __name__ == "__main__":
image_path = r"D:\hackathons\we_hack_2025\project_anon\trials\teenage_girls.png"
output_path_root = r"D:\hackathons\we_hack_2025\project_anon\output"
asyncio.run(process_input(image_path=image_path, output_path_root=output_path_root, operation=2))