File size: 3,188 Bytes
0821733
 
6065bc2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752b574
6065bc2
752b574
6065bc2
752b574
6065bc2
 
 
752b574
6065bc2
 
 
752b574
6065bc2
 
1713c80
6065bc2
 
1713c80
6065bc2
 
 
 
 
 
 
 
 
1713c80
 
6065bc2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96ac448
6065bc2
 
 
 
 
 
 
752b574
6065bc2
 
40be5d0
6065bc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import numpy as np
import cv2
import matplotlib.pyplot as plt
import gradio as gr
import tempfile
import os
from PIL import Image, ImageDraw

def calculate_snr(channel, rois):
    signal_mask = np.zeros(channel.shape, np.uint8)
    for roi in rois:
        cv2.fillPoly(signal_mask, [np.array(roi)], 255)
    signal = cv2.bitwise_and(channel, channel, mask=signal_mask)

    background_mask = cv2.bitwise_not(signal_mask)
    background = cv2.bitwise_and(channel, channel, mask=background_mask)

    signal_mean = np.mean(signal[signal_mask == 255])
    background_std = np.std(background[background_mask == 255])

    snr = signal_mean / background_std if background_std != 0 else float('inf')

    return signal_mean, background_std, snr, signal, background

def process_image(image, roi_sketch):
    if image is None or roi_sketch is None:
        return None, None

    # Convert sketch to binary mask
    mask = np.array(roi_sketch)
    _, binary_mask = cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY)

    # Find contours in the binary mask
    contours, _ = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Convert contours to list of ROIs
    rois = [contour.squeeze().tolist() for contour in contours if len(contour) > 2]

    # Convert image to numpy array
    img_array = np.array(image)

    if len(img_array.shape) == 2:
        channels = [img_array]
        channel_names = ['灰度']
    else:
        channels = cv2.split(img_array)
        channel_names = ['Red', 'Green', 'Blue']

    results = []
    plt.figure(figsize=(5*len(channels), 10))

    for i, (channel, name) in enumerate(zip(channels, channel_names)):
        signal_mean, background_std, snr, signal, background = calculate_snr(channel, rois)
        
        results.append(f"{name} channel:\n"
                       f"信号平均强度(Signal): {signal_mean:.2f}\n"
                       f"背景标准差(Noise): {background_std:.2f}\n"
                       f"信噪比(SNR): {snr:.2f}\n")

        plt.subplot(2, len(channels), i+1)
        plt.imshow(signal, cmap='gray')
        plt.title(f'{name} Signal ROI')
        plt.subplot(2, len(channels), i+1+len(channels))
        plt.imshow(background, cmap='gray')
        plt.title(f'{name} Background ROI')

    result_filename = tempfile.mktemp(suffix='.png')
    plt.savefig(result_filename)
    plt.close()

    return ("\n".join(results), result_filename)

with gr.Blocks() as demo:
    gr.Markdown("# 图像SNR计算器")
    gr.Markdown("上传一张图像,在第二个框中绘制多个感兴趣区域,结果会实时更新。支持单通道和多通道图像。")
    
    with gr.Row():
        input_image = gr.Image(label="上传图像", type="numpy")
        roi_sketch = gr.Sketchpad(label="绘制ROI", type="numpy", shape=(256, 256))
    
    with gr.Row():
        result_text = gr.Textbox(label="结果")
        result_image = gr.Image(label="ROI 图像")

    inputs = [input_image, roi_sketch]
    outputs = [result_text, result_image]

    input_image.change(process_image, inputs=inputs, outputs=outputs)
    roi_sketch.change(process_image, inputs=inputs, outputs=outputs)

demo.launch()