File size: 7,445 Bytes
6d34a01 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
import cv2
import numpy as np
import streamlit as st
from PIL import Image
import os
import zipfile
def detect_nose_and_realistically_thicken(image):
# Load pre-trained classifiers for face and nose detection
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
nose_cascade = cv2.CascadeClassifier('haarcascade_mcs_nose.xml')
# Convert the image to grayscale for better detection
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Detect faces in the image
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in faces:
# For each face, detect the nose
face_region = gray[y:y+h, x:x+w]
noses = nose_cascade.detectMultiScale(face_region, 1.3, 5)
for (nx, ny, nw, nh) in noses:
# Get the nose region from the original image
nose_region = image[y+ny:y+ny+nh, x+nx:x+nx+nw]
# Thicken the nose by increasing its width symmetrically
thicken_factor = 1.5 # Adjust this value to control thickness
new_width = int(nw * thicken_factor)
# Create a thickened nose by resizing
thickened_nose = cv2.resize(nose_region, (new_width, nh), interpolation=cv2.INTER_LINEAR)
# Feather the edges of the thickened nose to blend with the face
mask = np.zeros_like(thickened_nose, dtype=np.float32)
center_x = new_width // 2
cv2.circle(mask, (center_x, nh // 2), int(min(new_width, nh) * 0.6), (1, 1, 1), -1, cv2.LINE_AA)
mask = cv2.GaussianBlur(mask, (21, 21), 10) # Feathering
# Calculate the offsets to center the thickened nose
left_offset = (new_width - nw) // 2
# Ensure not to go out of bounds
start_x = max(x + nx - left_offset, 0)
end_x = min(start_x + new_width, image.shape[1])
start_y = y + ny
end_y = start_y + nh
# Blend the thickened nose smoothly into the face
alpha = 0.7 # Controls transparency of thickened nose
# Blending with the feathered mask to smooth edges
image[start_y:end_y, start_x:end_x] = (
image[start_y:end_y, start_x:end_x].astype(np.float32) * (1 - mask) +
thickened_nose[:, :end_x - start_x].astype(np.float32) * mask
).astype(np.uint8)
return image
def main():
st.title("Nose Thickening App")
# Modal Popup for Instructions
with st.expander("Application of OpenCV for Nose thickening", expanded=False):
st.write(
"The application of OpenCV for nose thickening showcases the power of computer vision in image processing. By leveraging pre-trained classifiers like Haar cascades, the program effectively detects facial features, particularly the nose, within images. The algorithm then applies a thicken effect by resizing the detected nose region, ensuring a realistic blend with the surrounding facial features. This involves techniques such as Gaussian blurring to feather the edges of the modified area, resulting in a seamless transition. The integration with Streamlit allows users to easily upload images, apply the effect, and download the modified results, making sophisticated image manipulation accessible to a broader audience without requiring extensive programming knowledge. This demonstrates OpenCV's versatility in creative applications, from enhancing personal photos to providing entertainment or social media enhancements."
)
# Instructions sidebar
with st.sidebar:
st.header("Instructions")
st.write(
"1) If you choose only one image to upload, the results will be shown on display, and you can click the 'Download Images' button to download the processed images in zip format.\n"
"2) If you choose more than one image, it will not display any image as results; instead, it will directly show you the 'Download Images' button, and you can click on it to download the processed images in zip format."
)
uploaded_files = st.file_uploader("Upload Images", type=["jpg", "jpeg", "png"], accept_multiple_files=True)
if st.button("Thicken Nose"):
if len(uploaded_files) == 1:
image = Image.open(uploaded_files[0]).convert("RGB")
image_np = np.array(image)
# Create a progress spinner
with st.spinner("Processing..."):
# Apply the nose detection and thickening effect
output_image = detect_nose_and_realistically_thicken(image_np)
# Display the output image
st.image(output_image, caption="Output Image", use_column_width=True)
# Convert the output image to RGB for saving
output_image_rgb = cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB)
# Save the output image in the correct color format
original_filename = os.path.splitext(uploaded_files[0].name)[0]
output_path = f"{original_filename}_thickened_nose.jpg"
cv2.imwrite(output_path, output_image_rgb) # Save as RGB
st.success("Nose thickening applied! You can download the image below.")
st.download_button("Download Image", data=open(output_path, "rb").read(), file_name=output_path, mime='image/jpeg')
elif len(uploaded_files) > 1:
st.warning("Multiple images uploaded. No output will be displayed. Please download the images directly.")
# Save all images in the output directory
output_dir = 'output_images'
os.makedirs(output_dir, exist_ok=True)
# Create a progress bar
progress_bar = st.progress(0)
for i, uploaded_file in enumerate(uploaded_files):
image = Image.open(uploaded_file).convert("RGB")
image_np = np.array(image)
with st.spinner(f"Processing image {i + 1} of {len(uploaded_files)}..."):
output_image = detect_nose_and_realistically_thicken(image_np)
# Convert the output image to RGB for saving
output_image_rgb = cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB)
# Create a new filename based on the original
original_filename = os.path.splitext(uploaded_file.name)[0]
output_filename = f"{original_filename}_thickened_nose.jpg"
output_path = os.path.join(output_dir, output_filename)
cv2.imwrite(output_path, output_image_rgb) # Save as RGB
# Update progress bar
progress_bar.progress((i + 1) / len(uploaded_files))
st.success("Nose thickening applied to all images! You can download them below.")
# Zip the images for download
zip_file_path = 'output_images.zip'
with zipfile.ZipFile(zip_file_path, 'w') as zipf:
for uploaded_file in uploaded_files:
original_filename = os.path.splitext(uploaded_file.name)[0]
output_filename = f"{original_filename}_thickened_nose.jpg"
zipf.write(os.path.join(output_dir, output_filename), arcname=output_filename)
st.download_button("Download Images", data=open(zip_file_path, "rb").read(), file_name='output_images.zip', mime='application/zip')
if __name__ == "__main__":
main()
|