-
-
Notifications
You must be signed in to change notification settings - Fork 350
add real time face blurring script #411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ChrisEssomba
wants to merge
19
commits into
DhanushNehru:main
Choose a base branch
from
ChrisEssomba:new-script
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
2807975
add real time face blurring script
ChrisEssomba 06edf46
Update readme
ChrisEssomba 9a30978
Merge branch 'main' into new-script
ChrisEssomba e452ff2
Real Time Face Blurring script
ChrisEssomba 8266a36
copilot corrections
ChrisEssomba 4a5ee0c
Revert "copilot corrections"
ChrisEssomba ea141c4
copilot corrections
ChrisEssomba a9e69cf
Update Real-Time-Face-Blurring-Tool/readme
ChrisEssomba 4eaf971
Update Real-Time-Face-Blurring-Tool/main.py
ChrisEssomba 2ede0b3
Update Real-Time-Face-Blurring-Tool/main.py
ChrisEssomba a82cbce
Update Real-Time-Face-Blurring-Tool/main.py
ChrisEssomba 882022f
update readme file
ChrisEssomba 6554608
update main
ChrisEssomba b7e283b
update main.py
ChrisEssomba 319f580
update main.py
ChrisEssomba b11fbf6
update main.py
ChrisEssomba a92b016
update the readme file
ChrisEssomba dea5923
update the readme file
ChrisEssomba 3fc57af
update main.py
ChrisEssomba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# Real-Time Face Blurring Tool | ||
|
||
A robust Python application for anonymizing faces in images, videos, and live webcam feeds using OpenCV's deep neural network (DNN) module. | ||
|
||
## Features | ||
|
||
- **Multi-source processing**: | ||
- 📷 Single image processing | ||
- 🎥 Video file processing | ||
- 🌐 Live webcam feed processing | ||
- **Advanced face detection** using Caffe-based DNN model | ||
- **Adjustable parameters**: | ||
- Blur strength (kernel size) | ||
- Detection confidence threshold | ||
- **Automatic output organization**: | ||
- `./output_images/` for processed images | ||
- `./output_videos/` for processed videos | ||
- **Progress tracking** for video processing | ||
- **Graceful resource handling** with proper cleanup | ||
|
||
## Requirements | ||
|
||
- Python 3.6+ | ||
- Required packages: | ||
```bash | ||
pip install opencv-python numpy | ||
``` | ||
|
||
## Installation | ||
|
||
Clone the repository and install dependencies: | ||
|
||
```bash | ||
git clone https://github.com/yourusername/Real-Time-Face-Blurring-Tool.git | ||
cd Real-Time-Face-Blurring-Tool | ||
pip install -r requirements.txt | ||
``` | ||
|
||
## Model Files | ||
|
||
Download the following files and place them in the correct folders: | ||
|
||
- `deploy.prototxt.txt` → `protocol/` folder | ||
- `res10_300x300_ssd_iter_140000_fp16.caffemodel` → `model/` folder | ||
|
||
You can download them from [OpenCV's GitHub repository](https://github.com/opencv/opencv/tree/master/samples/dnn/face_detector). | ||
|
||
## Usage | ||
|
||
Process an image: | ||
|
||
```bash | ||
python main.py --image path/to/image.jpg | ||
``` | ||
|
||
Process a video: | ||
|
||
```bash | ||
python main.py --video path/to/video.mp4 | ||
``` | ||
|
||
Process webcam feed: | ||
|
||
```bash | ||
python main.py --webcam | ||
``` | ||
|
||
### Optional Arguments | ||
|
||
- `--blur` Blur kernel size (odd integer, default: 61) | ||
- `--confidence` Face detection confidence threshold (default: 0.5) | ||
|
||
## Output | ||
|
||
- Processed images are saved in `./output_images/` with `_blurred` appended to the filename. | ||
- Processed videos are saved in `./output_videos/` with `_blurred` appended to the filename. | ||
|
||
## Troubleshooting | ||
|
||
- **Model file not found:** Make sure you downloaded the model files and placed them in the correct folders. | ||
- **Webcam not detected:** Ensure your webcam is connected and not used by another application. | ||
- **Permission errors:** Run your terminal or IDE as administrator if you encounter permission issues writing output files. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
import os | ||
import cv2 | ||
import numpy as np | ||
import logging | ||
from pathlib import Path | ||
|
||
# Configuration | ||
DEFAULT_BLUR_STRENGTH = 61 # Must be odd | ||
DEFAULT_CONFIDENCE_THRESHOLD = 0.5 | ||
OUTPUT_IMAGE_FOLDER = "./output_images/" | ||
OUTPUT_VIDEO_FOLDER = "./output_videos/" | ||
WEBCAM_RESOLUTION = (640, 480) | ||
INPUT_SIZE = (300, 300) | ||
MEAN_VALUES = (104.0, 177.0, 123.0) | ||
MODEL_PROTOTXT = "deploy.prototxt.txt" | ||
MODEL_WEIGHTS = "res10_300x300_ssd_iter_140000_fp16.caffemodel" | ||
|
||
# Setup logging | ||
logging.basicConfig(level=logging.INFO) | ||
logger = logging.getLogger(__name__) | ||
|
||
# Load DNN model once | ||
def load_face_detection_model(): | ||
"""Loads the pre-trained face detection model.""" | ||
try: | ||
base_dir = Path(__file__).parent | ||
prototxt_path = str(base_dir / "protocol" / MODEL_PROTOTXT) | ||
model_path = str(base_dir / "model" / MODEL_WEIGHTS) | ||
|
||
if not os.path.exists(prototxt_path): | ||
raise FileNotFoundError(f"Prototxt file not found at {prototxt_path}") | ||
if not os.path.exists(model_path): | ||
raise FileNotFoundError(f"Model weights not found at {model_path}") | ||
|
||
return cv2.dnn.readNetFromCaffe(prototxt_path, model_path) | ||
except Exception as e: | ||
logger.error(f"Failed to load model: {e}") | ||
raise | ||
|
||
face_net = load_face_detection_model() | ||
|
||
def save_video(video, output_path, default_fps=30, default_res=WEBCAM_RESOLUTION): | ||
""" | ||
Initializes a video writer object to save processed video frames. | ||
|
||
Args: | ||
video: OpenCV video capture object | ||
output_path: Path to save the output video | ||
default_fps: Fallback FPS if not detected | ||
default_res: Fallback resolution if not detected | ||
|
||
Returns: | ||
cv2.VideoWriter object | ||
""" | ||
try: | ||
fps = video.get(cv2.CAP_PROP_FPS) | ||
if not fps or fps <= 1: | ||
fps = default_fps | ||
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH)) or default_res[0] | ||
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)) or default_res[1] | ||
|
||
fourcc = cv2.VideoWriter_fourcc(*'mp4v') | ||
return cv2.VideoWriter(output_path, fourcc, fps, (width, height)) | ||
except Exception as e: | ||
logger.error(f"Failed to initialize video writer: {e}") | ||
raise | ||
|
||
def blur_faces(image, confidence_threshold=DEFAULT_CONFIDENCE_THRESHOLD, | ||
blur_strength=DEFAULT_BLUR_STRENGTH): | ||
""" | ||
Detects and blurs faces in an image. | ||
|
||
Args: | ||
image: Input image (numpy array) | ||
confidence_threshold: Minimum confidence for face detection (0-1) | ||
blur_strength: Kernel size for Gaussian blur (must be odd) | ||
|
||
Returns: | ||
Image with blurred faces (numpy array) | ||
""" | ||
if image is None: | ||
raise ValueError("Input image cannot be None") | ||
|
||
if blur_strength % 2 == 0: | ||
blur_strength += 1 # Ensure odd kernel size | ||
logger.debug(f"Adjusted blur strength to {blur_strength} to make it odd") | ||
|
||
(h, w) = image.shape[:2] | ||
|
||
try: | ||
blob = cv2.dnn.blobFromImage( | ||
cv2.resize(image,INPUT_SIZE), | ||
1.0, | ||
INPUT_SIZE, | ||
MEAN_VALUES | ||
) | ||
|
||
face_net.setInput(blob) | ||
detections = face_net.forward() | ||
|
||
for i in range(detections.shape[2]): | ||
confidence = detections[0, 0, i, 2] | ||
|
||
if confidence > confidence_threshold: | ||
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) | ||
(startX, startY, endX, endY) = box.astype("int") | ||
|
||
# Ensure coordinates stay within image bounds | ||
startX, startY = max(0, startX), max(0, startY) | ||
endX, endY = min(w, endX), min(h, endY) | ||
# Validate ROI dimensions | ||
if endY > startY and endX > startX: | ||
# Extract and blur face ROI | ||
face_roi = image[startY:endY, startX:endX] | ||
blurred_face = cv2.GaussianBlur(face_roi, (blur_strength, blur_strength), 0) | ||
image[startY:endY, startX:endX] = blurred_face | ||
|
||
except Exception as e: | ||
logger.error(f"Error during face blurring: {e}") | ||
raise | ||
|
||
return image | ||
|
||
def blur_faces_images(image_path): | ||
"""Processes an image file and saves the blurred version.""" | ||
try: | ||
if not os.path.exists(image_path): | ||
raise FileNotFoundError(f"Image not found at {image_path}") | ||
|
||
image = cv2.imread(image_path) | ||
if image is None: | ||
raise ValueError(f"Failed to load image from {image_path}") | ||
|
||
blurred_image = blur_faces(image) | ||
|
||
os.makedirs(OUTPUT_IMAGE_FOLDER, exist_ok=True) | ||
filename, ext = os.path.splitext(os.path.basename(image_path)) | ||
output_path = os.path.join(OUTPUT_IMAGE_FOLDER, f"{filename}_blurred{ext}") | ||
|
||
if not cv2.imwrite(output_path, blurred_image): | ||
raise IOError(f"Failed to save image to {output_path}") | ||
|
||
logger.info(f"Successfully saved blurred image to {output_path}") | ||
|
||
except Exception as e: | ||
logger.error(f"Error processing image: {e}") | ||
raise | ||
|
||
def process_video_stream(input_source=None, is_webcam=False): | ||
""" | ||
Processes either a video file or webcam stream with face blurring. | ||
|
||
Args: | ||
input_source: Path to video file (if not webcam) | ||
is_webcam: Boolean flag for webcam processing | ||
""" | ||
try: | ||
os.makedirs(OUTPUT_VIDEO_FOLDER, exist_ok=True) | ||
|
||
if is_webcam: | ||
video = cv2.VideoCapture(0) | ||
if not video.isOpened(): | ||
raise ValueError("Unable to access the webcam.") | ||
video.set(cv2.CAP_PROP_FRAME_WIDTH, WEBCAM_RESOLUTION[0]) | ||
video.set(cv2.CAP_PROP_FRAME_HEIGHT, WEBCAM_RESOLUTION[1]) | ||
output_path = os.path.join(OUTPUT_VIDEO_FOLDER, "webcam_blurred.mp4") | ||
logger.info("Starting webcam processing...") | ||
else: | ||
if not os.path.exists(input_source): | ||
raise FileNotFoundError(f"Video file not found at {input_source}") | ||
video = cv2.VideoCapture(input_source) | ||
if not video.isOpened(): | ||
raise ValueError(f"Unable to open video file: {input_source}") | ||
name = os.path.basename(input_source) | ||
output_path = os.path.join(OUTPUT_VIDEO_FOLDER, f"{os.path.splitext(name)[0]}_blurred.mp4") | ||
logger.info(f"Processing video file: {input_source}") | ||
|
||
out = save_video(video, output_path) | ||
frame_count = 0 | ||
total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT)) if not is_webcam else -1 | ||
|
||
try: | ||
while True: | ||
ret, frame = video.read() | ||
if not ret: | ||
break | ||
|
||
frame_count += 1 | ||
if not is_webcam and frame_count % 10 == 0: | ||
logger.info(f"Processing frame {frame_count}/{total_frames}") | ||
|
||
blurred_frame = blur_faces(frame) | ||
cv2.imshow('Blurred Feed', blurred_frame) | ||
|
||
if cv2.waitKey(1) & 0xFF == ord('q'): | ||
logger.info("User requested early termination") | ||
break | ||
|
||
out.write(blurred_frame) | ||
|
||
finally: | ||
out.release() | ||
video.release() | ||
cv2.destroyAllWindows() | ||
logger.info(f"Successfully saved video to {output_path}") | ||
|
||
except Exception as e: | ||
logger.error(f"Error processing video: {e}") | ||
raise | ||
|
||
def main(): | ||
"""Command line interface for the face blurring application.""" | ||
import argparse | ||
|
||
parser = argparse.ArgumentParser( | ||
description="Face blurring application that processes images, videos, or webcam streams" | ||
) | ||
parser.add_argument('--image', help='Path to input image') | ||
parser.add_argument('--video', help='Path to input video') | ||
parser.add_argument('--webcam', action='store_true', help='Use webcam') | ||
|
||
args = parser.parse_args() | ||
|
||
try: | ||
if args.image: | ||
blur_faces_images(args.image) | ||
elif args.video: | ||
process_video_stream(args.video, is_webcam=False) | ||
elif args.webcam: | ||
process_video_stream(is_webcam=True) | ||
else: | ||
logger.warning("No input source specified. Use --image, --video, or --webcam") | ||
|
||
except Exception as e: | ||
logger.error(f"Application error: {e}") | ||
return 1 | ||
|
||
return 0 | ||
|
||
if __name__ == "__main__": | ||
exit(main()) |
Binary file added
BIN
+5.1 MB
Real-Time-Face-Blurring-Tool/model/res10_300x300_ssd_iter_140000_fp16.caffemodel
Binary file not shown.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Loading the model at module level without error handling could cause the entire module to fail if model files are missing. Consider adding try-catch blocks and proper error handling.
Copilot uses AI. Check for mistakes.