HeshamAI commited on
Commit
f46e9e2
·
verified ·
1 Parent(s): ce34862

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -29
app.py CHANGED
@@ -324,6 +324,8 @@ class DicomAnalyzer:
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.
 
 
327
  """
328
  try:
329
  base_col = col_group[1] # Mean column
@@ -331,7 +333,7 @@ class DicomAnalyzer:
331
 
332
  row1, row2 = row_pair
333
 
334
- # SNR formula
335
  formula1 = f"=IFERROR({base_col}{row1}/{std_col}{row1},\"\")"
336
  formula_col = get_column_letter(column_index_from_string(col_group[-1]) + 1)
337
  cell1 = ws[f"{formula_col}{row1}"]
@@ -339,7 +341,7 @@ class DicomAnalyzer:
339
  cell1.font = red_font
340
  cell1.alignment = openpyxl.styles.Alignment(horizontal='center')
341
 
342
- # CNR formula
343
  formula2 = f"=IFERROR(({base_col}{row1}-{base_col}{row2})/{std_col}{row2},\"\")"
344
  cell2 = ws[f"{formula_col}{row2}"]
345
  cell2.value = formula2
@@ -371,27 +373,32 @@ class DicomAnalyzer:
371
  ('BV', 'BW', 'BX', 'BY', 'BZ')
372
  ]
373
 
 
374
  for cols in column_groups:
375
  for i, header in enumerate(headers):
376
  cell = ws[f"{cols[i]}1"]
377
  cell.value = header
378
  cell.alignment = center_alignment
379
 
 
380
  row_pairs = [
381
  (2, 3), (5, 6), (8, 9), (11, 12), (14, 15),
382
  (17, 18), (20, 21), (23, 24), (26, 27), (29, 30)
383
  ]
384
 
 
385
  phantom_sizes = [
386
  '(7mm)', '(6.5mm)', '(6mm)', '(5.5mm)', '(5mm)',
387
  '(4.5mm)', '(4mm)', '(3.5mm)', '(3mm)', '(2.5mm)'
388
  ]
389
 
 
390
  for i, size in enumerate(phantom_sizes):
391
  header_cell = ws.cell(row=row_pairs[i][0]-1, column=1, value=size)
392
  header_cell.font = red_font
393
  header_cell.alignment = center_alignment
394
 
 
395
  result_idx = 0
396
  current_col_group = 0
397
  current_row_pair = 0
@@ -413,6 +420,7 @@ class DicomAnalyzer:
413
  self._write_result_to_cells(ws, result, cols, rows[1])
414
  result_idx += 1
415
 
 
416
  self.add_formulas_to_template(ws, rows, cols, red_font)
417
 
418
  current_col_group += 1
@@ -420,6 +428,7 @@ class DicomAnalyzer:
420
  current_col_group = 0
421
  current_row_pair += 1
422
 
 
423
  for cols in column_groups:
424
  for col in cols:
425
  for row in range(2, 31):
@@ -427,11 +436,12 @@ class DicomAnalyzer:
427
  if cell.value is not None:
428
  cell.alignment = center_alignment
429
 
430
- # الآن نضع جدول 1-AVG من الصف 35 إلى 45
431
  start_row = 35
432
  ws['C35'] = "1-AVG"
433
  ws['C35'].alignment = center_alignment
434
 
 
435
  ws.merge_cells('D35:E35')
436
  ws.merge_cells('F35:G35')
437
  ws.merge_cells('H35:I35')
@@ -446,14 +456,17 @@ class DicomAnalyzer:
446
  ws[c_ref].font = red_font
447
  ws[c_ref].alignment = center_alignment
448
 
 
449
  phantom_sizes2 = [
450
  '(7.0mm)', '(6.5mm)', '(6.0mm)', '(5.5mm)', '(5.0mm)',
451
  '(4.5mm)', '(4.0mm)', '(3.5mm)', '(3.0mm)', '(2.5mm)'
452
  ]
453
 
 
454
  for i, p_size in enumerate(phantom_sizes2):
455
- row = start_row + i + 1 # من 36..45
456
 
 
457
  ws.merge_cells(f'D{row}:E{row}')
458
  ws.merge_cells(f'F{row}:G{row}')
459
  ws.merge_cells(f'H{row}:I{row}')
@@ -472,33 +485,44 @@ class DicomAnalyzer:
472
  stddev_values = []
473
  cnr_values = []
474
 
 
 
475
  for group in column_groups:
476
- mean_col = group[1] # ex. 'C'
477
- std_col = group[2] # ex. 'D'
 
 
 
 
 
 
 
 
 
 
478
 
479
- m1 = ws[f"{mean_col}{raw_row1}"].value
480
- m2 = ws[f"{mean_col}{raw_row2}"].value
481
-
482
- # في السابق كانت:
483
- # std2 = ws[f"{std_col}{raw_row2}"].value
484
- # لكنك تريد أخذ stddev من الصف الأول (raw_row1):
485
- std2 = ws[f"{std_col}{raw_row1}"].value # <-- التعديل هنا
486
 
 
487
  try:
488
- m1 = float(m1) if m1 not in [None,''] else None
489
- m2 = float(m2) if m2 not in [None,''] else None
490
- std2 = float(std2) if std2 not in [None,''] else None
491
  except:
492
- m1,m2,std2 = None,None,None
493
- if (m1 is not None) and (m2 is not None) and (std2 is not None) and (std2!=0):
494
- mean_values.append(m1)
495
- stddev_values.append(std2)
496
- cnr_values.append((m1 - m2)/std2)
 
 
 
497
 
498
- # نحسب المتوسط
499
- final_mean = (sum(mean_values)/len(mean_values)) if mean_values else None
500
- final_std = (sum(stddev_values)/len(stddev_values)) if stddev_values else None
501
- final_cnr = (sum(cnr_values)/len(cnr_values)) if cnr_values else None
502
 
503
  if final_mean is not None:
504
  ws[f'D{row}'].value = final_mean
@@ -515,6 +539,7 @@ class DicomAnalyzer:
515
  ws[f'H{row}'].alignment = center_alignment
516
  ws[f'H{row}'].number_format = '0.0000'
517
 
 
518
  thin_side = openpyxl.styles.Side(style='thin')
519
  border = openpyxl.styles.Border(
520
  left=thin_side, right=thin_side, top=thin_side, bottom=thin_side
@@ -578,17 +603,14 @@ class DicomAnalyzer:
578
  return image, self.format_results()
579
 
580
  def undo_last(self, image):
581
- if not self.results: # لو مفيش نتائج أصلاً
582
  return self.update_display(), self.format_results()
583
 
584
  last_result = self.results[-1]
585
- # نتحقق إذا كان آخر إجراء قياس حقيقي أم صف صفري
586
  is_measurement = last_result['Point'] != '(0, 0)'
587
 
588
- # نمسح آخر نتيجة
589
  self.results.pop()
590
 
591
- # لو كان قياس حقيقي، نمسح العلامة المقابلة له
592
  if is_measurement and self.marks:
593
  self.marks.pop()
594
 
 
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.
327
+ SNR => row1
328
+ CNR => row2
329
  """
330
  try:
331
  base_col = col_group[1] # Mean column
 
333
 
334
  row1, row2 = row_pair
335
 
336
+ # SNR formula in row1
337
  formula1 = f"=IFERROR({base_col}{row1}/{std_col}{row1},\"\")"
338
  formula_col = get_column_letter(column_index_from_string(col_group[-1]) + 1)
339
  cell1 = ws[f"{formula_col}{row1}"]
 
341
  cell1.font = red_font
342
  cell1.alignment = openpyxl.styles.Alignment(horizontal='center')
343
 
344
+ # CNR formula in row2
345
  formula2 = f"=IFERROR(({base_col}{row1}-{base_col}{row2})/{std_col}{row2},\"\")"
346
  cell2 = ws[f"{formula_col}{row2}"]
347
  cell2.value = formula2
 
373
  ('BV', 'BW', 'BX', 'BY', 'BZ')
374
  ]
375
 
376
+ # Write main headers in each column group
377
  for cols in column_groups:
378
  for i, header in enumerate(headers):
379
  cell = ws[f"{cols[i]}1"]
380
  cell.value = header
381
  cell.alignment = center_alignment
382
 
383
+ # Pairs of rows for measurements
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 (used for labeling)
390
  phantom_sizes = [
391
  '(7mm)', '(6.5mm)', '(6mm)', '(5.5mm)', '(5mm)',
392
  '(4.5mm)', '(4mm)', '(3.5mm)', '(3mm)', '(2.5mm)'
393
  ]
394
 
395
+ # Put phantom size labels in column A (row-1 from the first measurement row)
396
  for i, size in enumerate(phantom_sizes):
397
  header_cell = ws.cell(row=row_pairs[i][0]-1, column=1, value=size)
398
  header_cell.font = red_font
399
  header_cell.alignment = center_alignment
400
 
401
+ # Write all self.results into the sheet, as in your original code
402
  result_idx = 0
403
  current_col_group = 0
404
  current_row_pair = 0
 
420
  self._write_result_to_cells(ws, result, cols, rows[1])
421
  result_idx += 1
422
 
423
+ # Add SNR/CNR formulas for these two rows
424
  self.add_formulas_to_template(ws, rows, cols, red_font)
425
 
426
  current_col_group += 1
 
428
  current_col_group = 0
429
  current_row_pair += 1
430
 
431
+ # Center-align all non-empty cells from row 2..30 in those columns
432
  for cols in column_groups:
433
  for col in cols:
434
  for row in range(2, 31):
 
436
  if cell.value is not None:
437
  cell.alignment = center_alignment
438
 
439
+ # Now create the 1-AVG table at row 35..45
440
  start_row = 35
441
  ws['C35'] = "1-AVG"
442
  ws['C35'].alignment = center_alignment
443
 
444
+ # Merge 3 sets of headers in row 35
445
  ws.merge_cells('D35:E35')
446
  ws.merge_cells('F35:G35')
447
  ws.merge_cells('H35:I35')
 
456
  ws[c_ref].font = red_font
457
  ws[c_ref].alignment = center_alignment
458
 
459
+ # We will re-use the same 10 phantom sizes
460
  phantom_sizes2 = [
461
  '(7.0mm)', '(6.5mm)', '(6.0mm)', '(5.5mm)', '(5.0mm)',
462
  '(4.5mm)', '(4.0mm)', '(3.5mm)', '(3.0mm)', '(2.5mm)'
463
  ]
464
 
465
+ # For each phantom row, read the same row_pairs to gather data
466
  for i, p_size in enumerate(phantom_sizes2):
467
+ row = start_row + i + 1 # 36..45
468
 
469
+ # Merge each row's 3 sets: (D-E), (F-G), (H-I)
470
  ws.merge_cells(f'D{row}:E{row}')
471
  ws.merge_cells(f'F{row}:G{row}')
472
  ws.merge_cells(f'H{row}:I{row}')
 
485
  stddev_values = []
486
  cnr_values = []
487
 
488
+ # We read from the same column groups.
489
+ # But now for CNR, we'll read from the formula column (the one add_formulas_to_template uses).
490
  for group in column_groups:
491
+ mean_col = group[1] # e.g. 'C'
492
+ std_col = group[2] # e.g. 'D'
493
+
494
+ # For MEAN, let's read row1 as before
495
+ val_mean = ws[f"{mean_col}{raw_row1}"].value
496
+ # For STDDEV, also row1 if you prefer
497
+ val_std = ws[f"{std_col}{raw_row1}"].value
498
+
499
+ # For CNR, the formula is placed in row2 in the "formula column" after group[-1].
500
+ # So let's find that column letter:
501
+ formula_col_index = column_index_from_string(group[-1]) + 1
502
+ formula_col = get_column_letter(formula_col_index)
503
 
504
+ # The formula was put in row2
505
+ val_cnr = ws[f"{formula_col}{raw_row2}"].value
 
 
 
 
 
506
 
507
+ # Convert them to float if possible
508
  try:
509
+ val_mean = float(val_mean) if val_mean not in [None, ''] else None
510
+ val_std = float(val_std) if val_std not in [None, ''] else None
511
+ val_cnr = float(val_cnr) if val_cnr not in [None, ''] else None
512
  except:
513
+ val_mean,val_std,val_cnr = None,None,None
514
+
515
+ if val_mean is not None:
516
+ mean_values.append(val_mean)
517
+ if val_std is not None:
518
+ stddev_values.append(val_std)
519
+ if val_cnr is not None:
520
+ cnr_values.append(val_cnr)
521
 
522
+ # Compute final averages
523
+ final_mean = sum(mean_values)/len(mean_values) if mean_values else None
524
+ final_std = sum(stddev_values)/len(stddev_values) if stddev_values else None
525
+ final_cnr = sum(cnr_values)/len(cnr_values) if cnr_values else None
526
 
527
  if final_mean is not None:
528
  ws[f'D{row}'].value = final_mean
 
539
  ws[f'H{row}'].alignment = center_alignment
540
  ws[f'H{row}'].number_format = '0.0000'
541
 
542
+ # Finally, border around C35..I45
543
  thin_side = openpyxl.styles.Side(style='thin')
544
  border = openpyxl.styles.Border(
545
  left=thin_side, right=thin_side, top=thin_side, bottom=thin_side
 
603
  return image, self.format_results()
604
 
605
  def undo_last(self, image):
606
+ if not self.results: # لا توجد نتائج
607
  return self.update_display(), self.format_results()
608
 
609
  last_result = self.results[-1]
 
610
  is_measurement = last_result['Point'] != '(0, 0)'
611
 
 
612
  self.results.pop()
613
 
 
614
  if is_measurement and self.marks:
615
  self.marks.pop()
616