import gradio as gr from PIL import Image import os import random # ========== 配置图片路径 ========== ENHANCE_INPUT_DIR = "sr_input" ENHANCE_OUTPUT_DIR = "sr_output" ENHANCE_IMG_NAMES = [f"img_{i}.jpg" for i in range(1, 30)] ENHANCE_CHOICES = ["请选择样例图片或者上传"] + ENHANCE_IMG_NAMES ENHANCE_DEFAULT = ENHANCE_IMG_NAMES[0] SEG_INPUT_DIR = "seg_input" SEG_OUTPUT_DIR = "seg_output" SEG_IMG_NAMES = [f"img_{i}.png" for i in range(1, 30)] SEG_CHOICES = ["请选择样例图片或者上传"] + SEG_IMG_NAMES SEG_DEFAULT = SEG_IMG_NAMES[0] DIAG_INPUT_DIR = "diag_input" DIAG_IMG_NAMES = [f"img_{i}.jpg" for i in range(1, 32)] DIAG_CHOICES = ["请选择样例图片或者上传"] + DIAG_IMG_NAMES DIAG_DEFAULT = DIAG_IMG_NAMES[0] KVASIR_CLASSES = [ "正常粘膜 (normal-z-line)", "食管静脉曲张 (esophagitis)", "正常盲肠 (normal-cecum)", "息肉 (polyps)", "溃疡 (ulcerative-colitis)", "糜烂 (dyed-lifted-polyps)", "出血 (dyed-resection-margins)", "正常幽门 (normal-pylorus)" ] SUGGESTION_DICT = { "正常粘膜 (normal-z-line)": "建议:无需特殊治疗,常规随访。", "食管静脉曲张 (esophagitis)": "建议:根据分级考虑内镜下治疗或药物治疗。", "正常盲肠 (normal-cecum)": "建议:无需特殊治疗,常规随访。", "息肉 (polyps)": "建议:考虑内镜下息肉切除,并随访。", "溃疡 (ulcerative-colitis)": "建议:药物治疗,必要时内镜下活检。", "糜烂 (dyed-lifted-polyps)": "建议:药物保护胃黏膜,可考虑内镜下进一步处理。", "出血 (dyed-resection-margins)": "建议:内镜下止血处理,密切观察。", "正常幽门 (normal-pylorus)": "建议:无需特殊治疗,常规随访。" } def open_img(img_path): if not os.path.exists(img_path): img = Image.new("RGB", (300, 300), (200, 200, 200)) else: img = Image.open(img_path) w, h = img.size if w != 300 or h != 300: img = img.resize((300, 300), Image.LANCZOS) return img def show_enhance_input(img_name): if img_name in (None, "", "请选择样例图片或者上传"): return None path = os.path.join(ENHANCE_INPUT_DIR, img_name) return open_img(path) def enhance_demo(img_name): if img_name in (None, "", "请选择样例图片或者上传"): return None path = os.path.join(ENHANCE_OUTPUT_DIR, img_name) return open_img(path) def show_seg_input(img_name): if img_name in (None, "", "请选择样例图片或者上传"): return None path = os.path.join(SEG_INPUT_DIR, img_name) return open_img(path) def segment_demo(img_name): if img_name in (None, "", "请选择样例图片或者上传"): return None path = os.path.join(SEG_OUTPUT_DIR, img_name) return open_img(path) def show_diag_input(img_name): if img_name in (None, "", "请选择样例图片或者上传"): return None path = os.path.join(DIAG_INPUT_DIR, img_name) return open_img(path) def diagnose_demo(img_name): if img_name in (None, "", "请选择样例图片或者上传"): return [], "", "" idx = int(os.path.splitext(img_name)[0].replace("img_", "")) idx2cat = [ (range(1, 5), "糜烂 (dyed-lifted-polyps)"), (range(5, 9), "出血 (dyed-resection-margins)"), (range(9, 13), "食管静脉曲张 (esophagitis)"), (range(13, 17), "正常盲肠 (normal-cecum)"), (range(17, 21), "正常幽门 (normal-pylorus)"), (range(21, 25), "正常粘膜 (normal-z-line)"), (range(25, 29), "息肉 (polyps)"), (range(29, 33), "溃疡 (ulcerative-colitis)") ] main_cat = None for r, cat in idx2cat: if idx in r: main_cat = cat break if main_cat is None: main_cat = random.choice(KVASIR_CLASSES) n_cat = len(KVASIR_CLASSES) probs = [0.0 for _ in range(n_cat)] main_idx = KVASIR_CLASSES.index(main_cat) main_prob = random.uniform(0.85, 0.99) rest = 1 - main_prob other_probs_raw = [random.uniform(0.01, 1) for _ in range(n_cat-1)] other_probs_norm = [x / sum(other_probs_raw) * rest for x in other_probs_raw] pidx = 0 for i in range(n_cat): if i == main_idx: probs[i] = main_prob else: probs[i] = other_probs_norm[pidx] pidx += 1 result_table = [[KVASIR_CLASSES[i], f"{probs[i]:.4f}"] for i in range(n_cat)] result_text = f"诊断类别:{main_cat}(概率最大)" suggestion = SUGGESTION_DICT.get(main_cat, "建议:请咨询医生。") return result_table, result_text, suggestion css = """ #main-title { text-align: center; font-size: 44px; font-weight: bold; margin-bottom: 18px; margin-top: 18px; letter-spacing: 2px; } .blue-dash-border { border: 2.5px dashed #164fa0 !important; border-radius: 22px !important; padding: 0 !important; margin-bottom: 16px !important; box-sizing: border-box; } .big-group { background: #fff !important; border: 2px solid #e0e2e5 !important; border-radius: 18px !important; padding: 28px 18px 24px 18px !important; margin: 16px !important; box-shadow: 0 3px 12px 2px rgba(60,64,67,.14); } .big-title { font-size: 28px; font-weight: bold; margin-bottom: 18px; color: #343434; letter-spacing: 1px; text-align: center; } /* ===== 按钮公共属性合并 ===== */ .orange-btn, .orange-btn-diag { background: #A7C0DE !important; color: #111 !important; font-size: 32px; font-weight: bold; border: none #5900c2 !important; border-radius: 16px !important; padding: 12px 20px !important; width: auto !important; } .gray-btn, .gray-btn-diag { background: #f2f2f2 !important; color: #111 !important; font-size: 32px; font-weight: bold; border: 3px dashed #6c91c2 !important; border-radius: 16px !important; padding: 12px 20px !important; width: auto !important; } /* ===== 不同之处仅在于左右 margin ===== */ .orange-btn { margin-left: 48px !important; margin-right: 48px !important; } .gray-btn { margin-left: 48px !important; margin-right: 48px !important; } /* ====== 诊断模块按钮独立CSS ====== */ .orange-btn-diag { margin-left: 24px !important; margin-right: 24px !important; } .gray-btn-diag { margin-left: 24px !important; margin-right: 24px !important; } .button-row { margin-top: 8px; } .image-label-container, .image-label-container * { margin: 0 !important; padding: 0 !important; line-height: 0 !important; font-size: 0 !important; border-spacing: 0 !important; box-sizing: border-box !important; } .image-label-container { width: 300px !important; margin-left: auto !important; margin-right: auto !important; display: flex !important; flex-direction: column !important; align-items: center !important; justify-content: center !important; position: relative; text-align: center !important; padding: 0 !important; border: none !important; } .image-label-container .gr-image, .image-label-container .gr-image-preview { width: 300px !important; height: 300px !important; min-width: 300px !important; min-height: 300px !important; max-width: 300px !important; max-height: 300px !important; display: flex !important; align-items: center !important; justify-content: center !important; background: #fff !important; border-radius: 10px 10px 0 0 !important; box-shadow: 0 2px 12px 0 rgba(60,64,67,.08); } .image-label-container img { display: block !important; vertical-align: bottom !important; width: 300px !important; height: 300px !important; margin: 0 auto !important; padding: 0 !important; border-radius: 10px 10px 0 0 !important; background: #fff !important; box-shadow: 0 2px 12px 0 rgba(60,64,67,.08); } .image-label-container .img-label-bar { margin: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important; line-height: normal !important; font-size: 22px !important; width: 300px !important; text-align: center !important; background: rgb(17, 26, 110); color: #fff; border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; font-weight: normal; box-sizing: border-box; align-self: center !important; } .gradio-container label, .gradio-container .gr-input-label, .gradio-container .block-label { font-size: 36px !important; font-weight: 500 !important; color: #222 !important; letter-spacing: 0.5px; } .gradio-container select, .gradio-container option, .gradio-container input[type="text"] { font-size: 22px !important; } .gradio-container .gr-dataframe, .gradio-container .gr-dataframe table, .gradio-container .gr-dataframe table th, .gradio-container .gr-dataframe table td { font-size: 28px !important; } .gradio-container .gr-dataframe .block-label, .gradio-container .gr-dataframe label { font-size: 28px !important; font-weight: 600 !important; } .gradio-container .gr-textbox, .gradio-container .gr-textbox textarea, .gradio-container .gr-textbox .block-label, .gradio-container .gr-textbox label { font-size: 28px !important; } """ def reset_enhance(): return "请选择样例图片或者上传", None, None def reset_seg(): return "请选择样例图片或者上传", None, None def reset_diag(): return "请选择样例图片或者上传", None, [], "", "" with gr.Blocks(title="消化道疾病智能分析系统") as demo: gr.HTML(f"") gr.HTML("
消化道疾病智能分析系统
") # ============ 第一行:增强 & 分割 ============ with gr.Row(): # ---------- 图像增强 ---------- with gr.Column(): with gr.Group(elem_classes="blue-dash-border"): with gr.Group(elem_classes="big-group"): gr.HTML("
图像增强模块
") enhance_select = gr.Dropdown( choices=ENHANCE_CHOICES, value=ENHANCE_DEFAULT, label="请选择样例图片或者上传", filterable=True ) with gr.Row(): with gr.Column(): with gr.Group(elem_classes="image-label-container"): enhance_input_img = gr.Image( show_label=False, interactive=False, width=300, height=300 ) gr.HTML("
原始图片
") with gr.Column(): with gr.Group(elem_classes="image-label-container"): enhance_output_img = gr.Image( show_label=False, interactive=False, width=300, height=300 ) gr.HTML("
增强结果图片
") with gr.Row(elem_classes="button-row"): enhance_reset_btn = gr.Button("清空", elem_classes="gray-btn") enhance_btn = gr.Button("点击执行图片增强", elem_classes="orange-btn") enhance_select.change( fn=show_enhance_input, inputs=enhance_select, outputs=enhance_input_img ) enhance_btn.click( fn=enhance_demo, inputs=enhance_select, outputs=enhance_output_img ) enhance_reset_btn.click( fn=reset_enhance, inputs=None, outputs=[enhance_select, enhance_input_img, enhance_output_img] ) # ---------- 图像分割 ---------- with gr.Column(): with gr.Group(elem_classes="blue-dash-border"): with gr.Group(elem_classes="big-group"): gr.HTML("
图像分割模块
") seg_select = gr.Dropdown( choices=SEG_CHOICES, value=SEG_DEFAULT, label="请选择样例图片或者上传", filterable=True ) with gr.Row(): with gr.Column(): with gr.Group(elem_classes="image-label-container"): seg_input_img = gr.Image( show_label=False, interactive=False, width=300, height=300 ) gr.HTML("
输入图片
") with gr.Column(): with gr.Group(elem_classes="image-label-container"): seg_output_img = gr.Image( show_label=False, interactive=False, width=300, height=300 ) gr.HTML("
分割结果图片
") with gr.Row(elem_classes="button-row"): seg_reset_btn = gr.Button("清空", elem_classes="gray-btn") seg_btn = gr.Button("点击执行分割", elem_classes="orange-btn") seg_select.change(fn=show_seg_input, inputs=seg_select, outputs=seg_input_img) seg_btn.click(fn=segment_demo, inputs=seg_select, outputs=seg_output_img) seg_reset_btn.click(fn=reset_seg, inputs=None, outputs=[seg_select, seg_input_img, seg_output_img]) # ============ 第二行:疾病诊断 ============ with gr.Row(): with gr.Group(elem_classes="blue-dash-border"): with gr.Group(elem_classes="big-group"): gr.HTML("
疾病分类模块
") with gr.Row(): # ---------- 左列:输入图片 + 按钮 ---------- with gr.Column(): diag_select = gr.Dropdown( choices=DIAG_CHOICES, value=DIAG_DEFAULT, label="请选择样例图片或者上传", filterable=True ) with gr.Column(): with gr.Group(elem_classes="image-label-container"): diag_input_img = gr.Image( show_label=False, interactive=False, width=300, height=300 ) gr.HTML("
输入图片
") with gr.Row(elem_classes="button-row"): # === 这里用新class名 === diag_reset_btn = gr.Button("清空", elem_classes="gray-btn-diag") diag_btn = gr.Button("点击执行诊断", elem_classes="orange-btn-diag") diag_select.change(fn=show_diag_input, inputs=diag_select, outputs=diag_input_img) # ---------- 中列:结果表格(新增label) ---------- with gr.Column(): diag_table = gr.Dataframe( headers=["诊断类别", "模型预测概率"] ) # ---------- 右列:诊断结果 & 建议 ---------- with gr.Column(): diag_result = gr.Textbox(label="诊断结果") diag_suggestion = gr.Textbox(label="建议的治疗方案") diag_btn.click( fn=diagnose_demo, inputs=diag_select, outputs=[diag_table, diag_result, diag_suggestion] ) diag_reset_btn.click( fn=reset_diag, inputs=None, outputs=[diag_select, diag_input_img, diag_table, diag_result, diag_suggestion] ) # ====== 页面加载时自动显示默认结果 ====== demo.load(fn=show_enhance_input, inputs=gr.State(ENHANCE_DEFAULT), outputs=enhance_input_img) demo.load(fn=enhance_demo, inputs=gr.State(ENHANCE_DEFAULT), outputs=enhance_output_img) demo.load(fn=show_seg_input, inputs=gr.State(SEG_DEFAULT), outputs=seg_input_img) demo.load(fn=segment_demo, inputs=gr.State(SEG_DEFAULT), outputs=seg_output_img) demo.load(fn=show_diag_input, inputs=gr.State(DIAG_DEFAULT), outputs=diag_input_img) demo.load(fn=diagnose_demo, inputs=gr.State(DIAG_DEFAULT), outputs=[diag_table, diag_result, diag_suggestion]) demo.launch()