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()