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