HeshamAI commited on
Commit
a5178c2
·
verified ·
1 Parent(s): b2ca0ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +192 -22
app.py CHANGED
@@ -61,11 +61,10 @@ class DicomAnalyzer:
61
  self.pan_y = 0
62
  self.max_pan_x = 0
63
  self.max_pan_y = 0
64
-
65
- # Main circle color remains yellow (BGR):
66
- self.CIRCLE_COLOR = (0, 255, 255)
67
- # Small circles inside the main circle will be white (BGR):
68
- self.SMALL_CIRCLES_COLOR = (255, 255, 255)
69
  print("DicomAnalyzer initialized...")
70
 
71
  def save_results(self):
@@ -296,7 +295,7 @@ class DicomAnalyzer:
296
 
297
  dx = X - x
298
  dy = Y - y
299
- dist_squared = dx*dx + dy*dy
300
 
301
  mask = np.zeros((height, width), dtype=bool)
302
  mask[dist_squared <= r_squared] = True
@@ -377,15 +376,195 @@ class DicomAnalyzer:
377
  try:
378
  if not self.results:
379
  return None, "No results to save"
380
- # ... your existing logic ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  return output_path, f"Results saved successfully ({len(self.results)} measurements)"
 
382
  except Exception as e:
383
  logger.error(f"Error saving formatted results: {str(e)}")
384
  return None, f"Error saving results: {str(e)}"
385
 
386
  def _write_result_to_cells(self, ws, result, cols, row):
387
- # ... your existing logic ...
388
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
 
390
  def format_results(self):
391
  """Returns a string representation of self.results for display."""
@@ -436,19 +615,8 @@ class DicomAnalyzer:
436
  def create_interface():
437
  print("Creating interface...")
438
  analyzer = DicomAnalyzer()
439
-
440
- # Instead of just #image_display { outline: none; },
441
- # we add custom CSS to set the canvas cursor to your icons8 red crosshair.
442
- custom_css = """
443
- #image_display {
444
- outline: none;
445
- }
446
- #image_display canvas {
447
- cursor: url("https://img.icons8.com/?size=100&id=83985&format=png&color=FA5252"), crosshair !important;
448
- }
449
- """
450
-
451
- with gr.Blocks(css=custom_css) as interface:
452
  gr.Markdown("# DICOM Image Analyzer")
453
 
454
  with gr.Row():
@@ -475,6 +643,7 @@ def create_interface():
475
  elem_id="image_display"
476
  )
477
 
 
478
  with gr.Row():
479
  zero_btn = gr.Button("Add Zero Row")
480
  zero2_btn = gr.Button("Add Two Zero Rows")
@@ -554,6 +723,7 @@ def create_interface():
554
  outputs=image_display
555
  )
556
 
 
557
  zero_btn.click(
558
  fn=analyzer.add_zero_row,
559
  inputs=image_display,
 
61
  self.pan_y = 0
62
  self.max_pan_x = 0
63
  self.max_pan_y = 0
64
+ # Main circle color remains yellow:
65
+ self.CIRCLE_COLOR = (0, 255, 255) # BGR format
66
+ # Small circles inside the main circle will be white:
67
+ self.SMALL_CIRCLES_COLOR = (255, 255, 255) # BGR white
 
68
  print("DicomAnalyzer initialized...")
69
 
70
  def save_results(self):
 
295
 
296
  dx = X - x
297
  dy = Y - y
298
+ dist_squared = dx * dx + dy * dy
299
 
300
  mask = np.zeros((height, width), dtype=bool)
301
  mask[dist_squared <= r_squared] = True
 
376
  try:
377
  if not self.results:
378
  return None, "No results to save"
379
+
380
+ wb = openpyxl.Workbook()
381
+ ws = wb.active
382
+ red_font = openpyxl.styles.Font(color="FF0000")
383
+ center_alignment = openpyxl.styles.Alignment(horizontal='center')
384
+
385
+ # Column group headers
386
+ headers = ['Area', 'Mean', 'StdDev', 'Min', 'Max']
387
+
388
+ column_groups = [
389
+ ('B', 'C', 'D', 'E', 'F'), ('H', 'I', 'J', 'K', 'L'),
390
+ ('N', 'O', 'P', 'Q', 'R'), ('T', 'U', 'V', 'W', 'X'),
391
+ ('Z', 'AA', 'AB', 'AC', 'AD'), ('AF', 'AG', 'AH', 'AI', 'AJ'),
392
+ ('AL', 'AM', 'AN', 'AO', 'AP'), ('AR', 'AS', 'AT', 'AU', 'AV'),
393
+ ('AX', 'AY', 'AZ', 'BA', 'BB'), ('BD', 'BE', 'BF', 'BG', 'BH'),
394
+ ('BJ', 'BK', 'BL', 'BM', 'BN'), ('BP', 'BQ', 'BR', 'BS', 'BT'),
395
+ ('BV', 'BW', 'BX', 'BY', 'BZ')
396
+ ]
397
+
398
+ for cols in column_groups:
399
+ for i, header in enumerate(headers):
400
+ cell = ws[f"{cols[i]}1"]
401
+ cell.value = header
402
+ cell.alignment = center_alignment
403
+
404
+ row_pairs = [
405
+ (2, 3), (5, 6), (8, 9), (11, 12), (14, 15),
406
+ (17, 18), (20, 21), (23, 24), (26, 27), (29, 30)
407
+ ]
408
+
409
+ phantom_sizes = [
410
+ '(7mm)', '(6.5mm)', '(6mm)', '(5.5mm)', '(5mm)',
411
+ '(4.5mm)', '(4mm)', '(3.5mm)', '(3mm)', '(2.5mm)'
412
+ ]
413
+
414
+ # Set the phantom size row labels
415
+ for i, size in enumerate(phantom_sizes):
416
+ header_cell = ws.cell(row=row_pairs[i][0]-1, column=1, value=size)
417
+ header_cell.font = red_font
418
+ header_cell.alignment = center_alignment
419
+
420
+ # Fill the data from self.results
421
+ result_idx = 0
422
+ current_col_group = 0
423
+ current_row_pair = 0
424
+
425
+ while result_idx < len(self.results):
426
+ if current_row_pair >= len(row_pairs):
427
+ break
428
+
429
+ cols = column_groups[current_col_group]
430
+ rows = row_pairs[current_row_pair]
431
+
432
+ # First row
433
+ if result_idx < len(self.results):
434
+ result = self.results[result_idx]
435
+ self._write_result_to_cells(ws, result, cols, rows[0])
436
+ result_idx += 1
437
+
438
+ # Second row
439
+ if result_idx < len(self.results):
440
+ result = self.results[result_idx]
441
+ self._write_result_to_cells(ws, result, cols, rows[1])
442
+ result_idx += 1
443
+
444
+ # Add SNR/CNR formulas
445
+ self.add_formulas_to_template(ws, rows, cols, red_font)
446
+
447
+ current_col_group += 1
448
+ if current_col_group >= len(column_groups):
449
+ current_col_group = 0
450
+ current_row_pair += 1
451
+
452
+ # Center align all data cells
453
+ for cols in column_groups:
454
+ for col in cols:
455
+ for row in range(2, 31):
456
+ cell = ws[f"{col}{row}"]
457
+ if cell.value is not None:
458
+ cell.alignment = center_alignment
459
+
460
+ # Additional tables: StdDev Averages and CNR Averages
461
+ current_row = 32
462
+
463
+ # StdDev
464
+ stddev_header = ws.cell(row=current_row, column=1, value="StdDev Averages")
465
+ stddev_header.font = red_font
466
+ stddev_header.alignment = center_alignment
467
+ current_row += 1
468
+
469
+ for i, size in enumerate(phantom_sizes):
470
+ row_number = row_pairs[i][0]
471
+ stddev_values = []
472
+
473
+ for cols in column_groups:
474
+ stddev_col = cols[2] # The StdDev column
475
+ cell_value = ws[f"{stddev_col}{row_number}"].value
476
+ if cell_value not in [0, None, '']:
477
+ stddev_values.append(float(cell_value))
478
+
479
+ size_cell = ws.cell(row=current_row, column=1, value=size)
480
+ size_cell.alignment = center_alignment
481
+
482
+ if stddev_values:
483
+ avg_stddev = sum(stddev_values) / len(stddev_values)
484
+ avg_cell = ws.cell(row=current_row, column=2, value=avg_stddev)
485
+ avg_cell.number_format = '0.000'
486
+ avg_cell.alignment = center_alignment
487
+ current_row += 1
488
+
489
+ current_row += 2
490
+
491
+ # CNR
492
+ cnr_header = ws.cell(row=current_row, column=1, value="CNR Averages")
493
+ cnr_header.font = red_font
494
+ cnr_header.alignment = center_alignment
495
+ current_row += 1
496
+
497
+ for i, size in enumerate(phantom_sizes):
498
+ row_number = row_pairs[i][1]
499
+ cnr_cells = []
500
+
501
+ for cols in column_groups:
502
+ formula_col = get_column_letter(column_index_from_string(cols[-1]) + 1)
503
+ cnr_cell_ref = f"{formula_col}{row_number}"
504
+
505
+ # Read Mean1, Mean2, Std2 to skip zeros
506
+ mean_col = cols[1]
507
+ std_col = cols[2]
508
+
509
+ mean1_val = ws[f"{mean_col}{row_pairs[i][0]}"].value
510
+ mean2_val = ws[f"{mean_col}{row_pairs[i][1]}"].value
511
+ std2_val = ws[f"{std_col}{row_pairs[i][1]}"].value
512
+
513
+ try:
514
+ mean1_val = float(mean1_val) if mean1_val not in [None, ''] else 0
515
+ mean2_val = float(mean2_val) if mean2_val not in [None, ''] else 0
516
+ std2_val = float(std2_val) if std2_val not in [None, ''] else 0
517
+ except:
518
+ mean1_val, mean2_val, std2_val = 0, 0, 0
519
+
520
+ # If not all zero, add the cell reference
521
+ if not (mean1_val == 0 and mean2_val == 0 and std2_val == 0):
522
+ cnr_cells.append(cnr_cell_ref)
523
+
524
+ size_cell = ws.cell(row=current_row, column=1, value=size)
525
+ size_cell.alignment = center_alignment
526
+
527
+ if cnr_cells:
528
+ # Using AVERAGE(...) instead of AVERAGEIF
529
+ average_formula = f'=IFERROR(AVERAGE({",".join(cnr_cells)}), "")'
530
+
531
+ avg_cell = ws.cell(row=current_row, column=2)
532
+ avg_cell.value = average_formula
533
+ avg_cell.number_format = '0.000'
534
+ avg_cell.alignment = center_alignment
535
+
536
+ current_row += 1
537
+
538
+ # Align the extra rows
539
+ for row in range(32, current_row):
540
+ for col in range(1, 3):
541
+ cell = ws.cell(row=row, column=col)
542
+ cell.alignment = center_alignment
543
+
544
+ wb.save(output_path)
545
  return output_path, f"Results saved successfully ({len(self.results)} measurements)"
546
+
547
  except Exception as e:
548
  logger.error(f"Error saving formatted results: {str(e)}")
549
  return None, f"Error saving results: {str(e)}"
550
 
551
  def _write_result_to_cells(self, ws, result, cols, row):
552
+ """Helper method to write a single result to worksheet cells."""
553
+ center_alignment = openpyxl.styles.Alignment(horizontal='center')
554
+
555
+ value_mapping = {
556
+ 'Area': 'Area (mm²)',
557
+ 'Mean': 'Mean',
558
+ 'StdDev': 'StdDev',
559
+ 'Min': 'Min',
560
+ 'Max': 'Max'
561
+ }
562
+
563
+ for i, (header, key) in enumerate(value_mapping.items()):
564
+ cell = ws[f"{cols[i]}{row}"]
565
+ val = result[key]
566
+ cell.value = float(val) if val not in ['', None] else ''
567
+ cell.alignment = center_alignment
568
 
569
  def format_results(self):
570
  """Returns a string representation of self.results for display."""
 
615
  def create_interface():
616
  print("Creating interface...")
617
  analyzer = DicomAnalyzer()
618
+
619
+ with gr.Blocks(css="#image_display { outline: none; }") as interface:
 
 
 
 
 
 
 
 
 
 
 
620
  gr.Markdown("# DICOM Image Analyzer")
621
 
622
  with gr.Row():
 
643
  elem_id="image_display"
644
  )
645
 
646
+ # Removed the "Add Blank Row" button
647
  with gr.Row():
648
  zero_btn = gr.Button("Add Zero Row")
649
  zero2_btn = gr.Button("Add Two Zero Rows")
 
723
  outputs=image_display
724
  )
725
 
726
+ # Removed blank_btn
727
  zero_btn.click(
728
  fn=analyzer.add_zero_row,
729
  inputs=image_display,