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()