pavansuresh commited on
Commit
8c7fc4b
·
verified ·
1 Parent(s): 17e5143

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -92
app.py CHANGED
@@ -20,11 +20,6 @@ logger = logging.getLogger(__name__)
20
  ocr_model = PaddleOCR(use_textline_orientation=True, lang='en')
21
 
22
  def analyze_uv_coverage(img, brightness_threshold=150, kernel_size=5, apply_blur=True, adaptive_thresh=False):
23
- """
24
- Analyze UV sterilization coverage by thresholding the grayscale image.
25
- Optional adaptive thresholding and Gaussian blur for noise reduction.
26
- Morphological operations clean the mask for better accuracy.
27
- """
28
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
29
 
30
  if apply_blur:
@@ -39,21 +34,17 @@ def analyze_uv_coverage(img, brightness_threshold=150, kernel_size=5, apply_blur
39
  else:
40
  _, binary_mask = cv2.threshold(gray, brightness_threshold, 255, cv2.THRESH_BINARY)
41
 
42
- # Morphological opening (erosion followed by dilation) to remove noise
43
  kernel = np.ones((kernel_size, kernel_size), np.uint8)
44
  binary_mask = cv2.morphologyEx(binary_mask, cv2.MORPH_OPEN, kernel, iterations=1)
45
-
46
- # Morphological closing (dilation followed by erosion) to close small holes inside foreground
47
  binary_mask = cv2.morphologyEx(binary_mask, cv2.MORPH_CLOSE, kernel, iterations=1)
48
 
49
  total_pixels = binary_mask.size
50
  sterilized_pixels = cv2.countNonZero(binary_mask)
51
  coverage_percent = (sterilized_pixels / total_pixels) * 100
52
 
53
- # Create overlay for visualization: Green = sterilized, Red = unsterilized
54
  overlay = img.copy()
55
- overlay[binary_mask == 255] = [0, 255, 0] # Green
56
- overlay[binary_mask == 0] = [0, 0, 255] # Red
57
 
58
  annotated_img = cv2.addWeighted(img, 0.6, overlay, 0.4, 0)
59
 
@@ -62,7 +53,6 @@ def analyze_uv_coverage(img, brightness_threshold=150, kernel_size=5, apply_blur
62
  def create_pdf_report(coverage_percent, extracted_texts, annotated_image_path, output_path):
63
  pdf = FPDF()
64
  pdf.add_page()
65
-
66
  pdf.set_font("Arial", 'B', 16)
67
  pdf.cell(200, 10, txt="UV Sterilization Report", ln=True, align='C')
68
  pdf.ln(10)
@@ -70,12 +60,10 @@ def create_pdf_report(coverage_percent, extracted_texts, annotated_image_path, o
70
  pdf.set_font("Arial", size=12)
71
  pdf.cell(0, 10, f"Sterilization Coverage: {coverage_percent:.2f}%", ln=True)
72
  pdf.ln(5)
73
-
74
  pdf.cell(0, 10, "Extracted Text from Image (OCR):", ln=True)
75
  pdf.set_font("Arial", size=10)
76
  if extracted_texts:
77
  for text in extracted_texts:
78
- # Filter out very short or empty OCR texts to improve clarity
79
  if len(text.strip()) > 1:
80
  pdf.multi_cell(0, 8, f"- {text}")
81
  else:
@@ -84,14 +72,9 @@ def create_pdf_report(coverage_percent, extracted_texts, annotated_image_path, o
84
  pdf.ln(10)
85
  pdf.cell(0, 10, "Annotated Image:", ln=True)
86
  pdf.image(annotated_image_path, x=10, y=pdf.get_y(), w=pdf.w - 20)
87
-
88
  pdf.output(output_path)
89
 
90
- # New function to upload image to Salesforce and get URL (adapted from reference code)
91
  def upload_image_to_salesforce(image_path, image_name, record_id=None):
92
- """
93
- Upload the image to Salesforce as a ContentVersion and return a public URL.
94
- """
95
  try:
96
  sf = Salesforce(
97
  username=os.environ['SF_USERNAME'],
@@ -99,75 +82,45 @@ def upload_image_to_salesforce(image_path, image_name, record_id=None):
99
  security_token=os.environ['SF_SECURITY_TOKEN'],
100
  domain=os.environ.get('SF_DOMAIN', 'login')
101
  )
102
- logger.debug(f"Uploading image {image_name} for record ID: {record_id}")
103
-
104
- # Read the image file and encode it as base64
105
  with open(image_path, "rb") as f:
106
  image_data = f.read()
107
-
108
  encoded_image_data = base64.b64encode(image_data).decode('utf-8')
109
-
110
- # Create a ContentVersion in Salesforce
111
  content_version_data = {
112
  "Title": image_name,
113
  "PathOnClient": image_name,
114
  "VersionData": encoded_image_data,
115
  }
116
-
117
  if record_id:
118
  content_version_data["FirstPublishLocationId"] = record_id
119
-
120
  content_version = sf.ContentVersion.create(content_version_data)
121
  content_version_id = content_version["id"]
122
- logger.info(f"Image uploaded to Salesforce with ContentVersion ID: {content_version_id}")
123
-
124
- # Generate the public URL for the image
125
  image_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{content_version_id}"
126
- logger.debug(f"Generated image URL: {image_url}")
127
  return image_url
128
  except Exception as e:
129
  logger.error(f"Error uploading image to Salesforce: {str(e)}", exc_info=True)
130
  raise
131
 
132
  def upload_image_and_get_url(image_path):
133
- """
134
- Upload the image to Salesforce and return a public URL.
135
- """
136
  from datetime import datetime
137
  import uuid
138
-
139
- # Generate a unique filename to avoid conflicts
140
  unique_filename = f"{uuid.uuid4().hex}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.jpg"
141
-
142
- # Upload the image to Salesforce and get the URL
143
- try:
144
- image_url = upload_image_to_salesforce(image_path, unique_filename)
145
- return image_url
146
- except Exception as e:
147
- logger.error(f"Failed to upload image to Salesforce: {e}")
148
- raise
149
 
150
  def save_record_to_salesforce(annotated_image_url, coverage_percent, original_image_pil, compliance_threshold=80):
151
  sf = Salesforce(
152
  username=os.environ['SF_USERNAME'],
153
  password=os.environ['SF_PASSWORD'],
154
  security_token=os.environ['SF_SECURITY_TOKEN'],
155
- domain=os.environ.get('SF_DOMAIN', 'login') # 'test' for sandbox
156
  )
157
-
158
- # Save original image temporarily, upload it, get URL
159
  with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_orig_img_file:
160
  original_image_pil.save(temp_orig_img_file.name, format="JPEG")
161
  temp_orig_img_path = temp_orig_img_file.name
162
-
163
  original_image_url = upload_image_and_get_url(temp_orig_img_path)
164
  os.unlink(temp_orig_img_path)
165
-
166
  compliance_status = 'Pass' if coverage_percent >= compliance_threshold else 'Fail'
167
- technician_id = os.environ.get('SF_TECHNICIAN_ID') # Salesforce UserId lookup
168
-
169
  record_name = f"UV Verification - {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}"
170
-
171
  sf.UV_Verification__c.create({
172
  'Name': record_name,
173
  'Annotated_Image__c': annotated_image_url,
@@ -178,20 +131,15 @@ def save_record_to_salesforce(annotated_image_url, coverage_percent, original_im
178
  'Verified_On__c': datetime.utcnow().isoformat()
179
  })
180
 
181
- def process_image(input_img, brightness_threshold=150):
182
  img = cv2.cvtColor(np.array(input_img), cv2.COLOR_RGB2BGR)
183
-
184
- # Resize large images for faster processing, preserving aspect ratio
185
  max_dim = 640
186
  h, w = img.shape[:2]
187
  if max(h, w) > max_dim:
188
  scale = max_dim / max(h, w)
189
  img = cv2.resize(img, (int(w * scale), int(h * scale)))
190
-
191
  start_time = time.time()
192
  ocr_result = ocr_model.ocr(img)
193
- ocr_time = time.time() - start_time
194
-
195
  extracted_texts = []
196
  for line in ocr_result:
197
  if line:
@@ -199,49 +147,49 @@ def process_image(input_img, brightness_threshold=150):
199
  text = word_info[1][0].strip()
200
  if len(text) > 1:
201
  extracted_texts.append(text)
202
-
203
  annotated_img, coverage_percent = analyze_uv_coverage(img, brightness_threshold)
204
-
205
  with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_img_file:
206
  cv2.imwrite(temp_img_file.name, annotated_img)
207
  annotated_img_path = temp_img_file.name
208
-
209
  temp_pdf_file = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
210
  temp_pdf_file.close()
211
  create_pdf_report(coverage_percent, extracted_texts, annotated_img_path, temp_pdf_file.name)
212
-
213
- # Upload annotated image and get URL
214
  annotated_image_url = upload_image_and_get_url(annotated_img_path)
215
-
216
- # Save record in Salesforce
217
  save_record_to_salesforce(annotated_image_url, coverage_percent, input_img)
218
-
219
  annotated_img_rgb = cv2.cvtColor(annotated_img, cv2.COLOR_BGR2RGB)
220
-
221
  report_text = f"UV Sterilization Coverage: {coverage_percent:.2f}%"
222
-
223
- # Clean up temp image file after PDF generation
224
  os.unlink(annotated_img_path)
225
-
226
- return annotated_img_rgb, report_text, temp_pdf_file.name
227
-
228
- # Gradio Interface
229
- iface = gr.Interface(
230
- fn=process_image,
231
- inputs=[
232
- gr.Image(type="pil", label="Upload Post-UV Sterilization Image"),
233
- gr.Slider(50, 255, value=150, step=1, label="Brightness Threshold")
234
- ],
235
- outputs=[
236
- gr.Image(type="numpy", label="Annotated Image"),
237
- gr.Textbox(label="UV Sterilization Report", lines=5),
238
- gr.File(label="Download PDF Report")
239
- ],
240
- title="UV Sterilization Coverage Analyzer",
241
- description="Upload a post-UV sterilization image to analyze surface coverage and generate a compliance report."
242
- )
243
-
244
- iface.queue() # Enable request queuing to improve UX on heavy processing
245
-
246
- if __name__ == "__main__":
247
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
20
  ocr_model = PaddleOCR(use_textline_orientation=True, lang='en')
21
 
22
  def analyze_uv_coverage(img, brightness_threshold=150, kernel_size=5, apply_blur=True, adaptive_thresh=False):
 
 
 
 
 
23
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
24
 
25
  if apply_blur:
 
34
  else:
35
  _, binary_mask = cv2.threshold(gray, brightness_threshold, 255, cv2.THRESH_BINARY)
36
 
 
37
  kernel = np.ones((kernel_size, kernel_size), np.uint8)
38
  binary_mask = cv2.morphologyEx(binary_mask, cv2.MORPH_OPEN, kernel, iterations=1)
 
 
39
  binary_mask = cv2.morphologyEx(binary_mask, cv2.MORPH_CLOSE, kernel, iterations=1)
40
 
41
  total_pixels = binary_mask.size
42
  sterilized_pixels = cv2.countNonZero(binary_mask)
43
  coverage_percent = (sterilized_pixels / total_pixels) * 100
44
 
 
45
  overlay = img.copy()
46
+ overlay[binary_mask == 255] = [0, 255, 0]
47
+ overlay[binary_mask == 0] = [0, 0, 255]
48
 
49
  annotated_img = cv2.addWeighted(img, 0.6, overlay, 0.4, 0)
50
 
 
53
  def create_pdf_report(coverage_percent, extracted_texts, annotated_image_path, output_path):
54
  pdf = FPDF()
55
  pdf.add_page()
 
56
  pdf.set_font("Arial", 'B', 16)
57
  pdf.cell(200, 10, txt="UV Sterilization Report", ln=True, align='C')
58
  pdf.ln(10)
 
60
  pdf.set_font("Arial", size=12)
61
  pdf.cell(0, 10, f"Sterilization Coverage: {coverage_percent:.2f}%", ln=True)
62
  pdf.ln(5)
 
63
  pdf.cell(0, 10, "Extracted Text from Image (OCR):", ln=True)
64
  pdf.set_font("Arial", size=10)
65
  if extracted_texts:
66
  for text in extracted_texts:
 
67
  if len(text.strip()) > 1:
68
  pdf.multi_cell(0, 8, f"- {text}")
69
  else:
 
72
  pdf.ln(10)
73
  pdf.cell(0, 10, "Annotated Image:", ln=True)
74
  pdf.image(annotated_image_path, x=10, y=pdf.get_y(), w=pdf.w - 20)
 
75
  pdf.output(output_path)
76
 
 
77
  def upload_image_to_salesforce(image_path, image_name, record_id=None):
 
 
 
78
  try:
79
  sf = Salesforce(
80
  username=os.environ['SF_USERNAME'],
 
82
  security_token=os.environ['SF_SECURITY_TOKEN'],
83
  domain=os.environ.get('SF_DOMAIN', 'login')
84
  )
 
 
 
85
  with open(image_path, "rb") as f:
86
  image_data = f.read()
 
87
  encoded_image_data = base64.b64encode(image_data).decode('utf-8')
 
 
88
  content_version_data = {
89
  "Title": image_name,
90
  "PathOnClient": image_name,
91
  "VersionData": encoded_image_data,
92
  }
 
93
  if record_id:
94
  content_version_data["FirstPublishLocationId"] = record_id
 
95
  content_version = sf.ContentVersion.create(content_version_data)
96
  content_version_id = content_version["id"]
 
 
 
97
  image_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{content_version_id}"
 
98
  return image_url
99
  except Exception as e:
100
  logger.error(f"Error uploading image to Salesforce: {str(e)}", exc_info=True)
101
  raise
102
 
103
  def upload_image_and_get_url(image_path):
 
 
 
104
  from datetime import datetime
105
  import uuid
 
 
106
  unique_filename = f"{uuid.uuid4().hex}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.jpg"
107
+ return upload_image_to_salesforce(image_path, unique_filename)
 
 
 
 
 
 
 
108
 
109
  def save_record_to_salesforce(annotated_image_url, coverage_percent, original_image_pil, compliance_threshold=80):
110
  sf = Salesforce(
111
  username=os.environ['SF_USERNAME'],
112
  password=os.environ['SF_PASSWORD'],
113
  security_token=os.environ['SF_SECURITY_TOKEN'],
114
+ domain=os.environ.get('SF_DOMAIN', 'login')
115
  )
 
 
116
  with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_orig_img_file:
117
  original_image_pil.save(temp_orig_img_file.name, format="JPEG")
118
  temp_orig_img_path = temp_orig_img_file.name
 
119
  original_image_url = upload_image_and_get_url(temp_orig_img_path)
120
  os.unlink(temp_orig_img_path)
 
121
  compliance_status = 'Pass' if coverage_percent >= compliance_threshold else 'Fail'
122
+ technician_id = os.environ.get('SF_TECHNICIAN_ID')
 
123
  record_name = f"UV Verification - {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}"
 
124
  sf.UV_Verification__c.create({
125
  'Name': record_name,
126
  'Annotated_Image__c': annotated_image_url,
 
131
  'Verified_On__c': datetime.utcnow().isoformat()
132
  })
133
 
134
+ def process_image(input_img, brightness_threshold=150, slider_state=gr.State()):
135
  img = cv2.cvtColor(np.array(input_img), cv2.COLOR_RGB2BGR)
 
 
136
  max_dim = 640
137
  h, w = img.shape[:2]
138
  if max(h, w) > max_dim:
139
  scale = max_dim / max(h, w)
140
  img = cv2.resize(img, (int(w * scale), int(h * scale)))
 
141
  start_time = time.time()
142
  ocr_result = ocr_model.ocr(img)
 
 
143
  extracted_texts = []
144
  for line in ocr_result:
145
  if line:
 
147
  text = word_info[1][0].strip()
148
  if len(text) > 1:
149
  extracted_texts.append(text)
 
150
  annotated_img, coverage_percent = analyze_uv_coverage(img, brightness_threshold)
 
151
  with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_img_file:
152
  cv2.imwrite(temp_img_file.name, annotated_img)
153
  annotated_img_path = temp_img_file.name
 
154
  temp_pdf_file = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
155
  temp_pdf_file.close()
156
  create_pdf_report(coverage_percent, extracted_texts, annotated_img_path, temp_pdf_file.name)
 
 
157
  annotated_image_url = upload_image_and_get_url(annotated_img_path)
 
 
158
  save_record_to_salesforce(annotated_image_url, coverage_percent, input_img)
 
159
  annotated_img_rgb = cv2.cvtColor(annotated_img, cv2.COLOR_BGR2RGB)
 
160
  report_text = f"UV Sterilization Coverage: {coverage_percent:.2f}%"
 
 
161
  os.unlink(annotated_img_path)
162
+ slider_state = brightness_threshold
163
+ return annotated_img_rgb, report_text, temp_pdf_file.name, slider_state
164
+
165
+ with gr.Blocks(title="UV Sterilization Coverage Analyzer") as demo:
166
+ gr.Markdown("## UV Sterilization Coverage Analyzer")
167
+ gr.Markdown("Upload a post-UV sterilization image to analyze surface coverage and generate a compliance report.")
168
+ with gr.Row():
169
+ with gr.Column(scale=1):
170
+ image_input = gr.Image(type="pil", label="Upload Post-UV Sterilization Image")
171
+ brightness_slider = gr.Slider(50, 255, value=150, step=1, label="Brightness Threshold")
172
+ with gr.Row():
173
+ clear_btn = gr.Button("Clear")
174
+ submit_btn = gr.Button("Submit", variant="primary")
175
+ with gr.Column(scale=1):
176
+ annotated_output = gr.Image(type="numpy", label="Annotated Image")
177
+ report_text = gr.Textbox(label="UV Sterilization Report", lines=5)
178
+ pdf_output = gr.File(label="Download PDF Report")
179
+
180
+ def reset_slider(_: Image.Image):
181
+ return gr.update(value=150)
182
+
183
+ def clear_all():
184
+ return None, 150, None, "", None
185
+
186
+ image_input.change(fn=reset_slider, inputs=image_input, outputs=brightness_slider)
187
+ submit_btn.click(fn=process_image,
188
+ inputs=[image_input, brightness_slider],
189
+ outputs=[annotated_output, report_text, pdf_output, brightness_slider])
190
+ clear_btn.click(fn=clear_all,
191
+ inputs=[],
192
+ outputs=[image_input, brightness_slider, annotated_output, report_text, pdf_output])
193
+
194
+ demo.queue()
195
+ demo.launch()