|
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): |
|
|
|
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') |
|
nose_cascade = cv2.CascadeClassifier('haarcascade_mcs_nose.xml') |
|
|
|
|
|
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) |
|
|
|
|
|
faces = face_cascade.detectMultiScale(gray, 1.3, 5) |
|
|
|
for (x, y, w, h) in faces: |
|
|
|
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: |
|
|
|
nose_region = image[y+ny:y+ny+nh, x+nx:x+nx+nw] |
|
|
|
|
|
thicken_factor = 1.5 |
|
new_width = int(nw * thicken_factor) |
|
|
|
|
|
thickened_nose = cv2.resize(nose_region, (new_width, nh), interpolation=cv2.INTER_LINEAR) |
|
|
|
|
|
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) |
|
|
|
|
|
left_offset = (new_width - nw) // 2 |
|
|
|
|
|
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 |
|
|
|
|
|
alpha = 0.7 |
|
|
|
|
|
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") |
|
|
|
|
|
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." |
|
) |
|
|
|
|
|
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) |
|
|
|
|
|
with st.spinner("Processing..."): |
|
|
|
output_image = detect_nose_and_realistically_thicken(image_np) |
|
|
|
|
|
st.image(output_image, caption="Output Image", use_column_width=True) |
|
|
|
|
|
output_image_rgb = cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB) |
|
|
|
|
|
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) |
|
|
|
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.") |
|
|
|
|
|
output_dir = 'output_images' |
|
os.makedirs(output_dir, exist_ok=True) |
|
|
|
|
|
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) |
|
|
|
|
|
output_image_rgb = cv2.cvtColor(output_image, cv2.COLOR_BGR2RGB) |
|
|
|
|
|
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) |
|
|
|
|
|
progress_bar.progress((i + 1) / len(uploaded_files)) |
|
|
|
st.success("Nose thickening applied to all images! You can download them below.") |
|
|
|
|
|
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() |
|
|