''' an image processing tool that allows users to upload microscope images, adjust the view with zoom and enhancement controls, and save the processed image along with annotations. The tool uses OpenCV for image processing and PIL for image enhancements. The processed image can be saved locally or exported as a zip file containing the processed image, description, and parameters. The tool also provides options to rename the processed image and associated files. The tool consists of the following components: 1. File Uploader: Allows users to upload microscope images in JPG or PNG format. 2. Image Controls: Provides sliders to adjust the zoom, contrast, brightness, and sharpness of the image. 3. Processed Image Display: Displays the processed image after applying the adjustments. 4. Original Image Display: Displays the original image uploaded by the user. 5. Save and Export Options: Allows users to add annotations, prepare a zip file for download, save the processed image locally, and rename the processed image and associated files. To run the tool: 1. Save the script as `cell_exp_past.py`. 2. Run the script in a Python environment. ```python streamlit run cell_exp_past.py ``` 3. Open the provided local URL in a web browser. 4. Upload microscope images and adjust the image view. 5. Apply adjustments and save the processed image with annotations. 6. Download the processed image and annotations as a zip file. 7. Save the processed image locally or rename the processed image and associated files. ''' import streamlit as st from PIL import Image, ImageEnhance import pandas as pd import numpy as np import io import os import tempfile import zipfile import json def zoom_at(img, x, y, zoom): ''' increase the zoom level of the image at a specific point (x, y). Parameters: img (PIL.Image): The input image. x (int): The x-coordinate of the point. y (int): The y-coordinate of the point. zoom (float): The zoom level. Returns: PIL.Image: The zoomed image. Examples: >>> img = Image.open('image.jpg') >>> zoomed_img = zoom_at(img, 100, 100, 2.0) ''' w, h = img.size zoom2 = zoom * 2 img = img.crop((x - w / zoom2, y - h / zoom2, x + w / zoom2, y + h / zoom2)) return img.resize((w, h), Image.LANCZOS) st.title("CLL Image Processing Tool") st.write('''This tool allows you to upload microscope images, adjust the view with zoom and enhancement controls, and save the processed image along with annotations. You can also export the processed image, description, and parameters as a zip file. ''') uploaded_files = st.file_uploader("Upload Images", accept_multiple_files=True, type="jpg") if uploaded_files: img_index = st.selectbox("Select Image", range(len(uploaded_files))) x = st.slider("X Coordinate", 0, 500, 205) y = st.slider("Y Coordinate", 0, 500, 250) zoom = st.slider("Zoom", 1.0, 10.0, 0.5) contrast = st.slider("Contrast", 0.0, 5.0, 1.0) brightness = st.slider("Brightness", 0.0, 5.0, 1.0) sharpness = st.slider("Sharpness", 0.0, 2.0, 1.0) save_image = st.checkbox("Save Image") img_data = uploaded_files[img_index].read() img = Image.open(io.BytesIO(img_data)).resize((500, 500)) img_zoomed = zoom_at(img, x, y, zoom) img_contrast = ImageEnhance.Contrast(img_zoomed).enhance(contrast) img_bright = ImageEnhance.Brightness(img_contrast).enhance(brightness) img_sharp = ImageEnhance.Sharpness(img_bright).enhance(sharpness) if save_image: processed_image_path = "image-processed.jpg" img_sharp.save(processed_image_path) st.session_state['processed_image_path'] = processed_image_path st.success(f"Image saved as {processed_image_path}") st.image(img_sharp, caption="Processed Image", use_container_width=True) description = st.text_area("Describe the image", "") if st.button("Save Description"): with tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt') as f: f.write(description) desc_file = f.name st.session_state['desc_file'] = desc_file st.success("Description saved.") if st.button("Save Image Parameters"): params = { "coordinates_x": x, "coordinates_y": y, "zoom": zoom, "contrast": contrast, "brightness": brightness, "sharpness": sharpness } with tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.json') as f: json.dump(params, f) params_file = f.name st.session_state['params_file'] = params_file st.success("Parameters saved.") if st.button("Rename Files"): file_ext = str(np.random.randint(100)) processed_image_path = st.session_state.get('processed_image_path', None) desc_file = st.session_state.get('desc_file', None) params_file = st.session_state.get('params_file', None) if processed_image_path and os.path.exists(processed_image_path): try: new_image_name = f"img_processed{file_ext}.jpg" os.rename(processed_image_path, new_image_name) st.session_state['processed_image_path'] = new_image_name # Update session state st.success(f"Image renamed to {new_image_name}") except FileNotFoundError: st.error(f"{processed_image_path} not found.") else: st.error("Processed image not found.") if params_file and os.path.exists(params_file): try: new_params_name = f"saved_image_parameters{file_ext}.json" os.rename(params_file, new_params_name) st.session_state['params_file'] = new_params_name # Update session state st.success(f"Parameters file renamed to {new_params_name}") except FileNotFoundError: st.error(f"{params_file} not found.") else: st.error("Saved image parameters file not found.") if desc_file and os.path.exists(desc_file): try: new_desc_name = f"saved_image_description{file_ext}.txt" os.rename(desc_file, new_desc_name) st.session_state['desc_file'] = new_desc_name # Update session state st.success(f"Description file renamed to {new_desc_name}") except FileNotFoundError: st.error(f"{desc_file} not found.") else: st.error("Saved image description file not found.") st.success("Files renamed successfully") if st.button("Export to ZIP"): desc_file = st.session_state.get('desc_file', None) params_file = st.session_state.get('params_file', None) processed_image_path = st.session_state.get('processed_image_path', None) with tempfile.NamedTemporaryFile(delete=False, suffix='.zip') as zipf: with zipfile.ZipFile(zipf.name, 'w') as z: files_added = False # Flag to check if any file is added if desc_file and os.path.exists(desc_file): z.write(desc_file, os.path.basename(desc_file)) files_added = True else: st.warning("Description file not found and was not added to the ZIP.") if params_file and os.path.exists(params_file): z.write(params_file, os.path.basename(params_file)) files_added = True else: st.warning("Parameters file not found and was not added to the ZIP.") if processed_image_path and os.path.exists(processed_image_path): z.write(processed_image_path, os.path.basename(processed_image_path)) files_added = True else: st.warning("Processed image not found and was not added to the ZIP.") # Check if the ZIP file has any content if os.path.getsize(zipf.name) > 0 and files_added: with open(zipf.name, 'rb') as f: st.download_button("Download ZIP", f, "annotations.zip") else: st.error("No files were added to the ZIP. Please ensure files are saved before exporting.")