HeshamAI commited on
Commit
8b6f24e
·
verified ·
1 Parent(s): 371ca0c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +187 -70
app.py CHANGED
@@ -12,7 +12,6 @@ import time
12
  import traceback
13
  from functools import wraps
14
  import sys
15
- from openpyxl.styles import Font, Alignment
16
 
17
  print("Starting imports completed...")
18
 
@@ -134,6 +133,7 @@ class DicomAnalyzer:
134
  except Exception as e:
135
  print(f"Error loading DICOM file: {str(e)}")
136
  return None, f"Error loading DICOM file: {str(e)}"
 
137
  def normalize_image(self, image):
138
  try:
139
  normalized = cv2.normalize(
@@ -320,6 +320,7 @@ class DicomAnalyzer:
320
  except Exception as e:
321
  print(f"Error analyzing ROI: {str(e)}")
322
  return self.display_image, f"Error analyzing ROI: {str(e)}"
 
323
  def add_formulas_to_template(self, ws, row_pair, col_group, red_font):
324
  """
325
  Inserts SNR (first row) and CNR (second row) formulas with IFERROR.
@@ -349,18 +350,21 @@ class DicomAnalyzer:
349
  except Exception as e:
350
  logger.error(f"Error adding formulas: {str(e)}")
351
 
 
 
 
352
  def save_formatted_results(self, output_path):
353
  try:
354
  if not self.results:
355
  return None, "No results to save"
356
 
 
357
  wb = openpyxl.Workbook()
358
  ws = wb.active
359
- red_font = Font(color="FF0000")
360
- center_alignment = Alignment(horizontal='center')
361
-
362
  headers = ['Area', 'Mean', 'StdDev', 'Min', 'Max']
363
-
364
  column_groups = [
365
  ('B', 'C', 'D', 'E', 'F'), ('H', 'I', 'J', 'K', 'L'),
366
  ('N', 'O', 'P', 'Q', 'R'), ('T', 'U', 'V', 'W', 'X'),
@@ -370,86 +374,199 @@ class DicomAnalyzer:
370
  ('BJ', 'BK', 'BL', 'BM', 'BN'), ('BP', 'BQ', 'BR', 'BS', 'BT'),
371
  ('BV', 'BW', 'BX', 'BY', 'BZ')
372
  ]
 
 
 
 
 
 
 
 
 
 
 
373
 
374
- # ... [Keep existing column group setup identical] ...
375
-
376
- # ========== New Average Section ==========
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  start_row = 35
378
 
379
- # Create headers with merged cells
380
- ws.merge_cells(f'D{start_row}:E{start_row}')
381
- ws.merge_cells(f'F{start_row}:G{start_row}')
382
- ws.merge_cells(f'H{start_row}:I{start_row}')
383
-
384
- # Header content
385
- ws[f'C{start_row}'] = "1-AVG"
386
- ws[f'D{start_row}'] = "AVG MEAN"
387
- ws[f'F{start_row}'] = "AVG STDDEV"
388
- ws[f'H{start_row}'] = "AVG CNR"
389
-
390
- # Style headers
391
- header_font = Font(color="FF0000", bold=True)
392
- for col in ['C', 'D', 'F', 'H']:
393
- cell = ws[f'{col}{start_row}']
394
- cell.font = header_font
395
- cell.alignment = center_alignment
396
-
397
- # Phantom sizes data
398
- phantom_sizes = [
 
 
399
  '(7.0mm)', '(6.5mm)', '(6.0mm)', '(5.5mm)', '(5.0mm)',
400
  '(4.5mm)', '(4.0mm)', '(3.5mm)', '(3.0mm)', '(2.5mm)'
401
  ]
402
 
403
- # Sample data - replace with your actual calculations
404
- mean_averages = [-106.7269, -43.7258, -85.0408, -80.4591, -122.682,
405
- -89.2099, -129.4907, -58.9815, -91.0587, -88.1428]
406
-
407
- stddev_averages = [32.8073, 36.2411, 39.8299, 27.474, 30.6955,
408
- 28.7136, 46.8527, 50.7066, 34.3092, 18.9154]
409
-
410
- cnr_averages = [-9.6798, -1.2638, -6.0479, -5.2765, -11.9543,
411
- -0.3536, -3.4107, 4.9012, -1.3516, 8.6012]
412
-
413
- # Add data rows
414
- for idx, size in enumerate(phantom_sizes):
415
- current_row = start_row + 1 + idx
416
 
417
- # Phantom size label
418
- ws[f'C{current_row}'] = size
419
- ws[f'C{current_row}'].font = red_font
420
- ws[f'C{current_row}'].alignment = center_alignment
421
 
422
- # Mean average
423
- ws.merge_cells(f'D{current_row}:E{current_row}')
424
- mean_cell = ws[f'D{current_row}']
425
- mean_cell.value = mean_averages[idx]
426
- mean_cell.number_format = '0.0000'
427
- mean_cell.alignment = center_alignment
 
 
 
 
 
 
428
 
429
- # StdDev average
430
- ws.merge_cells(f'F{current_row}:G{current_row}')
431
- stddev_cell = ws[f'F{current_row}']
432
- stddev_cell.value = stddev_averages[idx]
433
- stddev_cell.number_format = '0.0000'
434
- stddev_cell.alignment = center_alignment
435
 
436
- # CNR average
437
- ws.merge_cells(f'H{current_row}:I{current_row}')
438
- cnr_cell = ws[f'H{current_row}']
439
- cnr_cell.value = cnr_averages[idx]
440
- cnr_cell.number_format = '0.0000'
441
- cnr_cell.alignment = center_alignment
442
-
443
- # Adjust column widths
444
- for col in ['C', 'D', 'F', 'H']:
445
- ws.column_dimensions[col].width = 12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
 
447
  wb.save(output_path)
448
  return output_path, f"Results saved successfully ({len(self.results)} measurements)"
449
-
450
  except Exception as e:
451
  logger.error(f"Error saving formatted results: {str(e)}")
452
  return None, f"Error saving results: {str(e)}"
 
453
 
454
  def _write_result_to_cells(self, ws, result, cols, row):
455
  center_alignment = openpyxl.styles.Alignment(horizontal='center')
@@ -566,7 +683,7 @@ def create_interface():
566
  - Use Zoom In/Out buttons or Reset View to adjust zoom level.
567
  - Use Reset All to clear all measurements.
568
  - "Save Results": basic Excel with raw data.
569
- - "Save Formatted Results": Excel with advanced formatting & formulas.
570
  """)
571
 
572
  def update_diameter(x):
@@ -696,4 +813,4 @@ if __name__ == "__main__":
696
  print(f"Error launching application: {str(e)}")
697
  logger.error(f"Error launching application: {str(e)}")
698
  logger.error(traceback.format_exc())
699
- raise e
 
12
  import traceback
13
  from functools import wraps
14
  import sys
 
15
 
16
  print("Starting imports completed...")
17
 
 
133
  except Exception as e:
134
  print(f"Error loading DICOM file: {str(e)}")
135
  return None, f"Error loading DICOM file: {str(e)}"
136
+
137
  def normalize_image(self, image):
138
  try:
139
  normalized = cv2.normalize(
 
320
  except Exception as e:
321
  print(f"Error analyzing ROI: {str(e)}")
322
  return self.display_image, f"Error analyzing ROI: {str(e)}"
323
+
324
  def add_formulas_to_template(self, ws, row_pair, col_group, red_font):
325
  """
326
  Inserts SNR (first row) and CNR (second row) formulas with IFERROR.
 
350
  except Exception as e:
351
  logger.error(f"Error adding formulas: {str(e)}")
352
 
353
+ ########################################################################
354
+ # نفس الدالة الأصلية، لكن نهاية الدالة تضع الجدول في الصف 35 بالشكل المطلوب
355
+ ########################################################################
356
  def save_formatted_results(self, output_path):
357
  try:
358
  if not self.results:
359
  return None, "No results to save"
360
 
361
+ # هنا كل شيء مثل كودك: تنشئ Workbook جديد، تصنع الشيت، تضع الهيدرز...
362
  wb = openpyxl.Workbook()
363
  ws = wb.active
364
+ red_font = openpyxl.styles.Font(color="FF0000")
365
+ center_alignment = openpyxl.styles.Alignment(horizontal='center')
366
+
367
  headers = ['Area', 'Mean', 'StdDev', 'Min', 'Max']
 
368
  column_groups = [
369
  ('B', 'C', 'D', 'E', 'F'), ('H', 'I', 'J', 'K', 'L'),
370
  ('N', 'O', 'P', 'Q', 'R'), ('T', 'U', 'V', 'W', 'X'),
 
374
  ('BJ', 'BK', 'BL', 'BM', 'BN'), ('BP', 'BQ', 'BR', 'BS', 'BT'),
375
  ('BV', 'BW', 'BX', 'BY', 'BZ')
376
  ]
377
+
378
+ for cols in column_groups:
379
+ for i, header in enumerate(headers):
380
+ cell = ws[f"{cols[i]}1"]
381
+ cell.value = header
382
+ cell.alignment = center_alignment
383
+
384
+ row_pairs = [
385
+ (2, 3), (5, 6), (8, 9), (11, 12), (14, 15),
386
+ (17, 18), (20, 21), (23, 24), (26, 27), (29, 30)
387
+ ]
388
 
389
+ phantom_sizes = [
390
+ '(7mm)', '(6.5mm)', '(6mm)', '(5.5mm)', '(5mm)',
391
+ '(4.5mm)', '(4mm)', '(3.5mm)', '(3mm)', '(2.5mm)'
392
+ ]
393
+
394
+ # كتابة أسماء الفانتوم باللون الأحمر في العمود A (قبل الصف الأول)
395
+ for i, size in enumerate(phantom_sizes):
396
+ header_cell = ws.cell(row=row_pairs[i][0]-1, column=1, value=size)
397
+ header_cell.font = red_font
398
+ header_cell.alignment = center_alignment
399
+
400
+ # توزيع نتائج ROI في هذه الصفوف والأعمدة كما في كودك
401
+ result_idx = 0
402
+ current_col_group = 0
403
+ current_row_pair = 0
404
+
405
+ while result_idx < len(self.results):
406
+ if current_row_pair >= len(row_pairs):
407
+ break
408
+
409
+ cols = column_groups[current_col_group]
410
+ rows = row_pairs[current_row_pair]
411
+
412
+ if result_idx < len(self.results):
413
+ result = self.results[result_idx]
414
+ self._write_result_to_cells(ws, result, cols, rows[0])
415
+ result_idx += 1
416
+
417
+ if result_idx < len(self.results):
418
+ result = self.results[result_idx]
419
+ self._write_result_to_cells(ws, result, cols, rows[1])
420
+ result_idx += 1
421
+
422
+ self.add_formulas_to_template(ws, rows, cols, red_font)
423
+
424
+ current_col_group += 1
425
+ if current_col_group >= len(column_groups):
426
+ current_col_group = 0
427
+ current_row_pair += 1
428
+
429
+ # ضبط المحاذاة للخلايا التي كُتبت بالفعل
430
+ for cols in column_groups:
431
+ for col in cols:
432
+ for row in range(2, 31):
433
+ cell = ws[f"{col}{row}"]
434
+ if cell.value is not None:
435
+ cell.alignment = center_alignment
436
+
437
+ ################################################################
438
+ # وهنا بدلًا من وضع جداول STDDEV/Mean/CNR منفصلة،
439
+ # نضع الجدول المدمج "1-AVG" من الصف 35 مثل الصورة التي أرسلتها
440
+ ################################################################
441
+
442
+ # سنستخدم نفس فكرة الجدول بالدمج من D35:E35, F35:G35, H35:I35
443
  start_row = 35
444
 
445
+ # ضع عنوان "1-AVG" في C35
446
+ ws['C35'] = "1-AVG"
447
+ ws['C35'].alignment = center_alignment
448
+
449
+ # ادمج الخلايا الخاصة بالعناوين
450
+ ws.merge_cells('D35:E35')
451
+ ws.merge_cells('F35:G35')
452
+ ws.merge_cells('H35:I35')
453
+
454
+ # ضع العناوين باللون الأحمر
455
+ avg_headers = {
456
+ 'D35': 'AVG MEAN',
457
+ 'F35': 'AVG STDDEV',
458
+ 'H35': 'AVG CNR'
459
+ }
460
+ for c_ref, text_val in avg_headers.items():
461
+ ws[c_ref] = text_val
462
+ ws[c_ref].font = red_font
463
+ ws[c_ref].alignment = center_alignment
464
+
465
+ # نفس أسماء الفانتوم
466
+ phantom_sizes2 = [
467
  '(7.0mm)', '(6.5mm)', '(6.0mm)', '(5.5mm)', '(5.0mm)',
468
  '(4.5mm)', '(4.0mm)', '(3.5mm)', '(3.0mm)', '(2.5mm)'
469
  ]
470
 
471
+ for i, p_size in enumerate(phantom_sizes2):
472
+ row = start_row + i + 1 # 36..45
 
 
 
 
 
 
 
 
 
 
 
473
 
474
+ # ادمج لكل صف: D-E ، F-G ، H-I
475
+ ws.merge_cells(f'D{row}:E{row}')
476
+ ws.merge_cells(f'F{row}:G{row}')
477
+ ws.merge_cells(f'H{row}:I{row}')
478
 
479
+ # اكتب اسم الفانتوم باللون الأحمر في العمود C
480
+ size_cell = ws[f'C{row}']
481
+ size_cell.value = p_size
482
+ size_cell.font = red_font
483
+ size_cell.alignment = center_alignment
484
+
485
+ # لكي نحسب الـAVG الحقيقي من الصفوف 2..3 إلخ،
486
+ # نستخدم row_pairs[i] إن أردت. أو كما في المثال الأصلي:
487
+ if i < len(row_pairs):
488
+ (raw_row1, raw_row2) = row_pairs[i]
489
+ else:
490
+ continue # لو عندك 10 فقط
491
 
492
+ # لنفترض أننا نقرأ من نفس الأعمدة اللي فيها mean & std
493
+ # نفترض عندنا على الأقل عمود mean_col = cols[1], stddev_col = cols[2]
494
+ # لكن عن��ك عدة col groups؛ إذا تريد تجمع من الأول فقط:
495
+ # أو خذ فكرة snippetك السابق:
 
 
496
 
497
+ mean_values = []
498
+ stddev_values = []
499
+ cnr_values = []
500
+
501
+ # Example: لو تحب تجمع من نفس الـ column_groups الأولى بس
502
+ for group in column_groups:
503
+ mean_col = group[1] # 'C','I','O'...الخ
504
+ std_col = group[2] # 'D','J','P'...الخ
505
+
506
+ # raw_row1 = الصف الأول
507
+ # raw_row2 = الصف الثاني
508
+ m1 = ws[f"{mean_col}{raw_row1}"].value
509
+ m2 = ws[f"{mean_col}{raw_row2}"].value
510
+ std2 = ws[f"{std_col}{raw_row2}"].value
511
+
512
+ try:
513
+ m1 = float(m1) if m1 not in [None,''] else None
514
+ m2 = float(m2) if m2 not in [None,''] else None
515
+ std2 = float(std2) if std2 not in [None,''] else None
516
+ except:
517
+ m1,m2,std2 = None,None,None
518
+ if (m1 is not None) and (m2 is not None) and (std2 is not None) and (std2!=0):
519
+ mean_values.append(m1)
520
+ stddev_values.append(std2)
521
+ cnr_values.append((m1 - m2)/std2)
522
+
523
+ # الآن نحسب المتوسط
524
+ if len(mean_values) > 0:
525
+ final_mean = sum(mean_values)/len(mean_values)
526
+ else:
527
+ final_mean = None
528
+
529
+ if len(stddev_values) > 0:
530
+ final_std = sum(stddev_values)/len(stddev_values)
531
+ else:
532
+ final_std = None
533
+
534
+ if len(cnr_values) > 0:
535
+ final_cnr = sum(cnr_values)/len(cnr_values)
536
+ else:
537
+ final_cnr = None
538
+
539
+ # نكتبها في الخلايا المدمجة
540
+ if final_mean is not None:
541
+ ws[f'D{row}'].value = final_mean
542
+ ws[f'D{row}'].alignment = center_alignment
543
+ ws[f'D{row}'].number_format = '0.0000'
544
+
545
+ if final_std is not None:
546
+ ws[f'F{row}'].value = final_std
547
+ ws[f'F{row}'].alignment = center_alignment
548
+ ws[f'F{row}'].number_format = '0.0000'
549
+
550
+ if final_cnr is not None:
551
+ ws[f'H{row}'].value = final_cnr
552
+ ws[f'H{row}'].alignment = center_alignment
553
+ ws[f'H{row}'].number_format = '0.0000'
554
+
555
+ # أخيراً، ضع الحدود حول C35..I45
556
+ thin_side = openpyxl.styles.Side(style='thin')
557
+ border = openpyxl.styles.Border(
558
+ left=thin_side, right=thin_side, top=thin_side, bottom=thin_side
559
+ )
560
+ for r in range(35, 46):
561
+ for c in ['C','D','E','F','G','H','I']:
562
+ ws[f'{c}{r}'].border = border
563
 
564
  wb.save(output_path)
565
  return output_path, f"Results saved successfully ({len(self.results)} measurements)"
 
566
  except Exception as e:
567
  logger.error(f"Error saving formatted results: {str(e)}")
568
  return None, f"Error saving results: {str(e)}"
569
+ ########################################################################
570
 
571
  def _write_result_to_cells(self, ws, result, cols, row):
572
  center_alignment = openpyxl.styles.Alignment(horizontal='center')
 
683
  - Use Zoom In/Out buttons or Reset View to adjust zoom level.
684
  - Use Reset All to clear all measurements.
685
  - "Save Results": basic Excel with raw data.
686
+ - "Save Formatted Results": Excel with advanced formatting & the 1-AVG table.
687
  """)
688
 
689
  def update_diameter(x):
 
813
  print(f"Error launching application: {str(e)}")
814
  logger.error(f"Error launching application: {str(e)}")
815
  logger.error(traceback.format_exc())
816
+ raise e