ahmedxeno commited on
Commit
f850371
·
verified ·
1 Parent(s): 6435e65

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -62
app.py CHANGED
@@ -1,81 +1,75 @@
1
  import cv2
2
  import numpy as np
3
- import gradio as gr
4
  import pywt
5
  from skimage import exposure
 
6
  from PIL import Image
 
7
 
8
- def musica_enhancement(img):
9
- # Convert PIL Image to NumPy array
10
- img = np.array(img)
11
-
12
- # Convert from RGB to grayscale if needed
13
- if len(img.shape) == 3:
14
- img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
15
 
16
  # Normalize to [0, 1]
17
- img_norm = img.astype(np.float32) / 255.0
18
 
19
- # 1. Wavelet Decomposition
20
- coeffs = pywt.wavedec2(img_norm, 'bior1.3', level=3)
 
 
 
 
 
21
  cA3, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1) = coeffs
 
 
 
22
 
23
- # 2. Frequency Band Processing
24
- cD1 = pywt.threshold(cD1, 0.05*np.max(cD1), mode='soft')
25
- cD2 = pywt.threshold(cD2, 0.07*np.max(cD2), mode='soft')
26
- cH1 = cH1 * 1.2
27
- cV1 = cV1 * 1.2
28
-
29
- # 3. Reconstruction with Clipping
30
- coeffs_enhanced = [cA3, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)]
31
- img_recon = pywt.waverec2(coeffs_enhanced, 'bior1.3')
32
- img_recon = np.clip(img_recon, 0, 1)
33
 
34
- # 4. Adaptive CLAHE
35
- entropy = -np.sum(img_recon * np.log2(img_recon + 1e-7))
36
- clip_limit = 0.02 if entropy > 7 else 0.05
37
- img_clahe = exposure.equalize_adapthist(img_recon, clip_limit=clip_limit, kernel_size=64)
38
 
39
- # 5. Gamma Correction
40
- p5, p95 = np.percentile(img_clahe, (5, 95))
41
  gamma = 0.7 if (p95 - p5) < 0.3 else 0.9
42
- img_gamma = exposure.adjust_gamma(img_clahe, gamma=gamma)
43
 
44
- # 6. Edge Enhancement
45
- img_gamma_8bit = (img_gamma * 255).astype(np.uint8)
46
- img_bgr = cv2.cvtColor(img_gamma_8bit, cv2.COLOR_GRAY2BGR)
47
- img_sharp = cv2.detailEnhance(img_bgr, sigma_s=12, sigma_r=0.15)
48
- img_sharp = cv2.cvtColor(img_sharp, cv2.COLOR_BGR2RGB)
49
-
50
- return img_sharp
51
 
52
- def process_image(input_img):
53
- # Convert Gradio input (PIL Image) to NumPy array
54
- input_img = np.array(input_img)
55
 
56
- # Enhance the image
57
- enhanced_img = musica_enhancement(input_img)
58
-
59
- # Convert enhanced image back to PIL for display
60
- enhanced_img = Image.fromarray(enhanced_img)
61
-
62
- return input_img, enhanced_img
63
 
64
- # Gradio Interface
65
- with gr.Blocks() as demo:
66
- gr.Markdown("# X-ray Enhancement (MUSICA®-Style)")
67
- gr.Markdown("Upload a TIFF, JPEG, or PNG X-ray image to enhance it using multi-scale wavelet processing and adaptive contrast adjustment.")
68
-
69
- with gr.Row():
70
- input_image = gr.Image(label="Upload X-ray (TIFF or JPEG/PNG)")
71
- output_original = gr.Image(label="Original Image")
72
- output_enhanced = gr.Image(label="Enhanced Image")
73
-
74
- submit_button = gr.Button("Enhance")
75
- submit_button.click(
76
- fn=process_image,
77
- inputs=input_image,
78
- outputs=[output_original, output_enhanced]
79
- )
80
 
81
- demo.launch()
 
1
  import cv2
2
  import numpy as np
3
+ import matplotlib.pyplot as plt
4
  import pywt
5
  from skimage import exposure
6
+ import gradio as gr
7
  from PIL import Image
8
+ from io import BytesIO
9
 
10
+ def process_tiff(file):
11
+ # Load 16-bit TIFF
12
+ img = cv2.imread(file.name, cv2.IMREAD_ANYDEPTH | cv2.IMREAD_GRAYSCALE)
13
+ if img is None:
14
+ raise gr.Error("Could not read TIFF file. Ensure it's 16-bit grayscale.")
 
 
15
 
16
  # Normalize to [0, 1]
17
+ img_norm = img.astype(np.float32) / 65535.0
18
 
19
+ # Wavelet decomposition
20
+ try:
21
+ coeffs = pywt.wavedec2(img_norm, 'bior1.3', level=3)
22
+ except ValueError as e:
23
+ raise gr.Error(f"Image dimensions must be divisible by 8. {str(e)}")
24
+
25
+ # Processing coefficients (same as original)
26
  cA3, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1) = coeffs
27
+ cD1 = pywt.threshold(cD1, 0.05*np.max(cD1), 'soft')
28
+ cD2 = pywt.threshold(cD2, 0.07*np.max(cD2), 'soft')
29
+ cH1 *= 1.2; cV1 *= 1.2
30
 
31
+ # Reconstruction
32
+ recon = pywt.waverec2([cA3, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)], 'bior1.3')
33
+ recon = np.clip(recon, 0, 1)
 
 
 
 
 
 
 
34
 
35
+ # CLAHE
36
+ entropy = -np.sum(recon * np.log2(recon + 1e-7))
37
+ clahe_img = exposure.equalize_adapthist(recon, clip_limit=0.02 if entropy >7 else 0.05, kernel_size=64)
 
38
 
39
+ # Gamma correction
40
+ p5, p95 = np.percentile(clahe_img, (5, 95))
41
  gamma = 0.7 if (p95 - p5) < 0.3 else 0.9
42
+ gamma_img = exposure.adjust_gamma(clahe_img, gamma)
43
 
44
+ # Sharpening
45
+ sharp = cv2.detailEnhance(cv2.cvtColor((gamma_img*255).astype(np.uint8), cv2.COLOR_GRAY2BGR),
46
+ sigma_s=12, sigma_r=0.15)
47
+ sharp = cv2.cvtColor(sharp, cv2.COLOR_BGR2GRAY)
 
 
 
48
 
49
+ # Prepare outputs
50
+ original_display = (np.clip(img/np.percentile(img, 99.5), 0, 1)*255).astype(np.uint8)
 
51
 
52
+ buf = BytesIO()
53
+ plt.hist(sharp.ravel(), bins=256, range=(0, 255))
54
+ plt.title("Enhanced Histogram")
55
+ plt.savefig(buf, format='png', bbox_inches='tight')
56
+ plt.close()
57
+ hist_img = Image.open(buf)
 
58
 
59
+ return original_display, sharp, hist_img
60
+
61
+ # Create Gradio interface
62
+ interface = gr.Interface(
63
+ fn=process_tiff,
64
+ inputs=gr.File(label="Upload TIFF", file_types=[".tif", ".tiff"]),
65
+ outputs=[
66
+ gr.Image(label="Original (Clipped)"),
67
+ gr.Image(label="Enhanced Image"),
68
+ gr.Image(label="Histogram")
69
+ ],
70
+ title="MUSICA Image Enhancement",
71
+ description="Upload 16-bit grayscale TIFF for enhancement using wavelet-based processing",
72
+ allow_flagging="never"
73
+ )
 
74
 
75
+ interface.launch()