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