Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| from fpdf import FPDF | |
| import tempfile | |
| import os | |
| from paddleocr import PaddleOCR | |
| import time | |
| from simple_salesforce import Salesforce | |
| from datetime import datetime | |
| import boto3 | |
| # Initialize PaddleOCR once with updated parameters | |
| ocr_model = PaddleOCR(use_textline_orientation=True, lang='en') | |
| def upload_image_and_get_url(image_path): | |
| """ | |
| Upload the image to AWS S3 and return the public URL. | |
| """ | |
| s3_client = boto3.client( | |
| 's3', | |
| aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'], # Set environment variable | |
| aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'], # Set environment variable | |
| region_name=os.environ['AWS_REGION'] # Set environment variable | |
| ) | |
| # Define the S3 bucket name | |
| bucket_name = 'your-bucket-name' | |
| # Generate a unique key for the image (e.g., using the file name) | |
| image_key = f"images/{os.path.basename(image_path)}" | |
| # Upload the image to S3 | |
| s3_client.upload_file(image_path, bucket_name, image_key) | |
| # Construct the public URL for the uploaded image | |
| image_url = f"https://{bucket_name}.s3.{os.environ['AWS_REGION']}.amazonaws.com/{image_key}" | |
| return image_url | |
| def analyze_uv_coverage(img, brightness_threshold=150, kernel_size=5, apply_blur=True, adaptive_thresh=False): | |
| """ | |
| Analyze UV sterilization coverage by thresholding the grayscale image. | |
| Optional adaptive thresholding and Gaussian blur for noise reduction. | |
| Morphological operations clean the mask for better accuracy. | |
| """ | |
| gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
| if apply_blur: | |
| gray = cv2.GaussianBlur(gray, (5, 5), 0) | |
| if adaptive_thresh: | |
| binary_mask = cv2.adaptiveThreshold( | |
| gray, 255, | |
| cv2.ADAPTIVE_THRESH_GAUSSIAN_C, | |
| cv2.THRESH_BINARY, | |
| 11, 2) | |
| else: | |
| _, binary_mask = cv2.threshold(gray, brightness_threshold, 255, cv2.THRESH_BINARY) | |
| # Morphological opening (erosion followed by dilation) to remove noise | |
| kernel = np.ones((kernel_size, kernel_size), np.uint8) | |
| binary_mask = cv2.morphologyEx(binary_mask, cv2.MORPH_OPEN, kernel, iterations=1) | |
| # Morphological closing (dilation followed by erosion) to close small holes inside foreground | |
| binary_mask = cv2.morphologyEx(binary_mask, cv2.MORPH_CLOSE, kernel, iterations=1) | |
| total_pixels = binary_mask.size | |
| sterilized_pixels = cv2.countNonZero(binary_mask) | |
| coverage_percent = (sterilized_pixels / total_pixels) * 100 | |
| # Create overlay for visualization: Green = sterilized, Red = unsterilized | |
| overlay = img.copy() | |
| overlay[binary_mask == 255] = [0, 255, 0] # Green | |
| overlay[binary_mask == 0] = [0, 0, 255] # Red | |
| annotated_img = cv2.addWeighted(img, 0.6, overlay, 0.4, 0) | |
| return annotated_img, coverage_percent | |
| def create_pdf_report(coverage_percent, extracted_texts, annotated_image_path, output_path): | |
| pdf = FPDF() | |
| pdf.add_page() | |
| pdf.set_font("Arial", 'B', 16) | |
| pdf.cell(200, 10, txt="UV Sterilization Report", ln=True, align='C') | |
| pdf.ln(10) | |
| pdf.set_font("Arial", size=12) | |
| pdf.cell(0, 10, f"Sterilization Coverage: {coverage_percent:.2f}%", ln=True) | |
| pdf.ln(5) | |
| pdf.cell(0, 10, "Extracted Text from Image (OCR):", ln=True) | |
| pdf.set_font("Arial", size=10) | |
| if extracted_texts: | |
| for text in extracted_texts: | |
| # Filter out very short or empty OCR texts to improve clarity | |
| if len(text.strip()) > 1: | |
| pdf.multi_cell(0, 8, f"- {text}") | |
| else: | |
| pdf.cell(0, 8, "No text detected.", ln=True) | |
| pdf.ln(10) | |
| pdf.cell(0, 10, "Annotated Image:", ln=True) | |
| pdf.image(annotated_image_path, x=10, y=pdf.get_y(), w=pdf.w - 20) | |
| pdf.output(output_path) | |
| def save_record_to_salesforce(annotated_image_url, coverage_percent, original_image_pil, compliance_threshold=80): | |
| sf = Salesforce( | |
| username=os.environ['SF_USERNAME'], | |
| password=os.environ['SF_PASSWORD'], | |
| security_token=os.environ['SF_SECURITY_TOKEN'], | |
| domain=os.environ.get('SF_DOMAIN', 'login') # 'test' for sandbox | |
| ) | |
| # Save original image temporarily, upload it, get URL | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_orig_img_file: | |
| original_image_pil.save(temp_orig_img_file.name, format="JPEG") | |
| temp_orig_img_path = temp_orig_img_file.name | |
| original_image_url = upload_image_and_get_url(temp_orig_img_path) | |
| os.unlink(temp_orig_img_path) | |
| compliance_status = 'Pass' if coverage_percent >= compliance_threshold else 'Fail' | |
| technician_id = os.environ.get('SF_TECHNICIAN_ID') # Salesforce UserId lookup | |
| record_name = f"UV Verification - {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}" | |
| sf.UV_Verification__c.create({ | |
| 'Name': record_name, | |
| 'Annotated_Image__c': annotated_image_url, | |
| 'Coverage_Percentage__c': round(coverage_percent, 2), | |
| 'Original_Image__c': original_image_url, # Correct field API name here | |
| 'Compliance_Status__c': compliance_status, | |
| 'Technician_ID__c': technician_id, | |
| 'Verified_On__c': datetime.utcnow().isoformat() | |
| }) | |
| def process_image(input_img, brightness_threshold=150): | |
| img = cv2.cvtColor(np.array(input_img), cv2.COLOR_RGB2BGR) | |
| # Resize large images for faster processing, preserving aspect ratio | |
| max_dim = 640 | |
| h, w = img.shape[:2] | |
| if max(h, w) > max_dim: | |
| scale = max_dim / max(h, w) | |
| img = cv2.resize(img, (int(w * scale), int(h * scale))) | |
| start_time = time.time() | |
| ocr_result = ocr_model.ocr(img) | |
| ocr_time = time.time() - start_time | |
| extracted_texts = [] | |
| for line in ocr_result: | |
| if line: | |
| for word_info in line: | |
| text = word_info[1][0].strip() | |
| if len(text) > 1: | |
| extracted_texts.append(text) | |
| annotated_img, coverage_percent = analyze_uv_coverage(img, brightness_threshold) | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_img_file: | |
| cv2.imwrite(temp_img_file.name, annotated_img) | |
| annotated_img_path = temp_img_file.name | |
| temp_pdf_file = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") | |
| temp_pdf_file.close() | |
| create_pdf_report(coverage_percent, extracted_texts, annotated_img_path, temp_pdf_file.name) | |
| # Upload annotated image and get URL | |
| annotated_image_url = upload_image_and_get_url(annotated_img_path) | |
| # Save record in Salesforce | |
| save_record_to_salesforce(annotated_image_url, coverage_percent, input_img) | |
| annotated_img_rgb = cv2.cvtColor(annotated_img, cv2.COLOR_BGR2RGB) | |
| report_text = f"UV Sterilization Coverage: {coverage_percent:.2f}%" | |
| # Clean up temp image file after PDF generation | |
| os.unlink(annotated_img_path) | |
| return annotated_img_rgb, report_text, temp_pdf_file.name | |
| iface = gr.Interface( | |
| fn=process_image, | |
| inputs=[ | |
| gr.Image(type="pil", label="Upload Post-UV Sterilization Image"), | |
| gr.Slider(50, 255, value=150, step=1, label="Brightness Threshold") | |
| ], | |
| outputs=[ | |
| gr.Image(type="numpy", label="Annotated Image"), | |
| gr.Textbox(label="UV Sterilization Report", lines=5), | |
| gr.File(label="Download PDF Report") | |
| ], | |
| title="UV Sterilization Coverage Analyzer", | |
| description="Upload a post-UV sterilization image to analyze surface coverage and generate a compliance report." | |
| ) | |
| iface.queue() # Enable request queuing to improve UX on heavy processing | |
| if __name__ == "__main__": | |
| iface.launch() |