Spaces:
Runtime error
Runtime error
xiaoming32236046
commited on
Commit
•
40be5d0
1
Parent(s):
70f3e38
Update app.py
Browse files
app.py
CHANGED
@@ -1,148 +1,60 @@
|
|
1 |
-
import numpy as np
|
2 |
-
import cv2
|
3 |
-
import matplotlib.pyplot as plt
|
4 |
import gradio as gr
|
5 |
-
import
|
6 |
-
import
|
7 |
-
import
|
8 |
-
|
9 |
-
def calculate_snr(image, roi_json):
|
10 |
-
roi_points = json.loads(roi_json)
|
11 |
-
|
12 |
-
# 创建临时文件来保存上传的图像
|
13 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_file:
|
14 |
-
temp_filename = temp_file.name
|
15 |
-
cv2.imwrite(temp_filename, image)
|
16 |
-
|
17 |
-
# 读取图像
|
18 |
-
img = cv2.imread(temp_filename, cv2.IMREAD_GRAYSCALE)
|
19 |
-
|
20 |
-
# 计算信号和背景区域
|
21 |
-
signal_mask = np.zeros(img.shape, np.uint8)
|
22 |
-
cv2.fillPoly(signal_mask, [np.array(roi_points)], 255)
|
23 |
-
signal = cv2.bitwise_and(img, img, mask=signal_mask)
|
24 |
-
|
25 |
-
background_mask = cv2.bitwise_not(signal_mask)
|
26 |
-
background = cv2.bitwise_and(img, img, mask=background_mask)
|
27 |
-
|
28 |
-
# 计算信号区域的平均强度
|
29 |
-
signal_mean = np.mean(signal[signal_mask == 255])
|
30 |
-
|
31 |
-
# 计算背景区域的标准差
|
32 |
-
background_std = np.std(background[background_mask == 255])
|
33 |
-
|
34 |
-
# 计算SNR
|
35 |
-
snr = signal_mean / background_std if background_std != 0 else float('inf')
|
36 |
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
plt.imshow(signal, cmap='gray')
|
41 |
-
plt.title('Signal ROI')
|
42 |
-
plt.subplot(122)
|
43 |
-
plt.imshow(background, cmap='gray')
|
44 |
-
plt.title('Background ROI')
|
45 |
|
46 |
-
#
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
)
|
60 |
-
|
61 |
-
# 自定义HTML组件和JavaScript代码
|
62 |
-
html_code = """
|
63 |
-
<div>
|
64 |
-
<canvas id="roi-canvas" width="500" height="500" style="border:1px solid #000000;"></canvas>
|
65 |
-
<button onclick="startDrawing()">Start Drawing</button>
|
66 |
-
<button onclick="stopDrawing()">Stop Drawing</button>
|
67 |
-
<button onclick="clearCanvas()">Clear</button>
|
68 |
-
<textarea id="roi-points" style="display:none;"></textarea>
|
69 |
-
</div>
|
70 |
-
<script>
|
71 |
-
let canvas = document.getElementById('roi-canvas');
|
72 |
-
let ctx = canvas.getContext('2d');
|
73 |
-
let roi = [];
|
74 |
-
let drawing = false;
|
75 |
-
|
76 |
-
canvas.addEventListener('mousedown', (e) => {
|
77 |
-
drawing = true;
|
78 |
-
roi.push({x: e.offsetX, y: e.offsetY});
|
79 |
-
});
|
80 |
-
|
81 |
-
canvas.addEventListener('mousemove', (e) => {
|
82 |
-
if (drawing) {
|
83 |
-
let lastPoint = roi[roi.length - 1];
|
84 |
-
ctx.beginPath();
|
85 |
-
ctx.moveTo(lastPoint.x, lastPoint.y);
|
86 |
-
ctx.lineTo(e.offsetX, e.offsetY);
|
87 |
-
ctx.strokeStyle = 'green';
|
88 |
-
ctx.lineWidth = 2;
|
89 |
-
ctx.stroke();
|
90 |
-
ctx.closePath();
|
91 |
-
roi.push({x: e.offsetX, y: e.offsetY});
|
92 |
-
}
|
93 |
-
});
|
94 |
-
|
95 |
-
canvas.addEventListener('mouseup', () => {
|
96 |
-
drawing = false;
|
97 |
-
document.getElementById('roi-points').value = JSON.stringify(roi);
|
98 |
-
});
|
99 |
-
|
100 |
-
function startDrawing() {
|
101 |
-
drawing = true;
|
102 |
-
}
|
103 |
-
|
104 |
-
function stopDrawing() {
|
105 |
-
drawing = false;
|
106 |
-
}
|
107 |
-
|
108 |
-
function clearCanvas() {
|
109 |
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
110 |
-
roi = [];
|
111 |
-
document.getElementById('roi-points').value = '';
|
112 |
-
}
|
113 |
-
</script>
|
114 |
-
"""
|
115 |
-
|
116 |
-
# 创建Gradio接口
|
117 |
-
with gr.Blocks() as demo:
|
118 |
-
with gr.Row():
|
119 |
-
image_input = gr.Image(label="上传图像")
|
120 |
-
roi_output = gr.HTML(html_code, label="绘制ROI区域")
|
121 |
-
roi_data = gr.Textbox(label="ROI Data", visible=False)
|
122 |
-
|
123 |
-
calculate_button = gr.Button("计算SNR")
|
124 |
-
result_text = gr.Textbox(label="结果")
|
125 |
-
result_image = gr.Image(label="ROI 图像")
|
126 |
-
|
127 |
-
def extract_roi_data(html_output):
|
128 |
-
return html_output
|
129 |
-
|
130 |
-
image_input.change(
|
131 |
-
fn=lambda x: "",
|
132 |
-
inputs=image_input,
|
133 |
-
outputs=roi_output
|
134 |
-
)
|
135 |
-
|
136 |
-
roi_output.change(
|
137 |
-
fn=extract_roi_data,
|
138 |
-
inputs=roi_output,
|
139 |
-
outputs=roi_data
|
140 |
-
)
|
141 |
-
|
142 |
-
calculate_button.click(
|
143 |
-
fn=calculate_snr,
|
144 |
-
inputs=[image_input, roi_data],
|
145 |
-
outputs=[result_text, result_image]
|
146 |
-
)
|
147 |
|
148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
import numpy as np
|
3 |
+
from PIL import Image, ImageDraw
|
4 |
+
import io
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
+
def calculate_snr(image, roi_mask):
|
7 |
+
# Convert image to numpy array
|
8 |
+
img_array = np.array(image)
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
+
# Create ROI and background masks
|
11 |
+
roi = img_array * roi_mask
|
12 |
+
bg = img_array * (1 - roi_mask)
|
13 |
+
|
14 |
+
# Calculate mean and standard deviation
|
15 |
+
roi_mean = np.mean(roi[roi != 0])
|
16 |
+
bg_mean = np.mean(bg[bg != 0])
|
17 |
+
bg_std = np.std(bg[bg != 0])
|
18 |
+
|
19 |
+
# Calculate SNR
|
20 |
+
snr = (roi_mean - bg_mean) / bg_std
|
21 |
+
|
22 |
+
return snr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
+
def process_image(input_image, roi_coordinates):
|
25 |
+
image = Image.open(io.BytesIO(input_image))
|
26 |
+
|
27 |
+
# Create a mask for the ROI
|
28 |
+
mask = Image.new('L', image.size, 0)
|
29 |
+
draw = ImageDraw.Draw(mask)
|
30 |
+
draw.polygon(roi_coordinates, fill=255)
|
31 |
+
|
32 |
+
# Convert mask to binary numpy array
|
33 |
+
mask_array = np.array(mask) / 255
|
34 |
+
|
35 |
+
# Calculate SNR
|
36 |
+
snr = calculate_snr(image.convert('L'), mask_array)
|
37 |
+
|
38 |
+
# Visualize the ROI on the image
|
39 |
+
overlay = Image.new('RGBA', image.size, (0, 0, 0, 0))
|
40 |
+
draw = ImageDraw.Draw(overlay)
|
41 |
+
draw.polygon(roi_coordinates, fill=(255, 0, 0, 64))
|
42 |
+
result_image = Image.alpha_composite(image.convert('RGBA'), overlay)
|
43 |
+
|
44 |
+
return result_image, f"SNR: {snr:.2f}"
|
45 |
+
|
46 |
+
iface = gr.Interface(
|
47 |
+
fn=process_image,
|
48 |
+
inputs=[
|
49 |
+
gr.Image(type="numpy", label="Upload Fluorescence Image"),
|
50 |
+
gr.ImageMask(label="Draw ROI", source="upload")
|
51 |
+
],
|
52 |
+
outputs=[
|
53 |
+
gr.Image(type="pil", label="Result"),
|
54 |
+
gr.Textbox(label="Signal-to-Noise Ratio (SNR)")
|
55 |
+
],
|
56 |
+
title="Fluorescence Staining Quality Assessment",
|
57 |
+
description="Upload a fluorescence image and draw the region of interest (ROI) to calculate the Signal-to-Noise Ratio (SNR)."
|
58 |
+
)
|
59 |
+
|
60 |
+
iface.launch()
|