import gradio as gr import cv2 import numpy as np from PIL import Image import requests from io import BytesIO import base64 def download_image(url): """从URL下载图像""" response = requests.get(url) response.raise_for_status() return Image.open(BytesIO(response.content)).convert("RGB") def downsample_image(image, target_size=(1024, 576), sharpen=True): """ 将高分辨率图像降采样至目标大小 参数: image: PIL图像对象 target_size: 目标分辨率元组 (宽度, 高度) sharpen: 是否应用锐化 返回: 降采样后的PIL图像对象 """ # 将PIL图像转换为cv2格式 cv2_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) # 获取原始图像尺寸 original_height, original_width = cv2_image.shape[:2] print(f"原始图像尺寸: {original_width}x{original_height}") # 计算目标宽高比 target_width, target_height = target_size target_ratio = target_width / target_height # 计算原始图像尺寸,保持宽高比 original_ratio = original_width / original_height if original_ratio > target_ratio: # 原始图像更宽,按宽度缩放 new_width = target_width new_height = int(new_width / original_ratio) else: # 原始图像更高,按高度缩放 new_height = target_height new_width = int(new_height * original_ratio) print(f"调整后尺寸: {new_width}x{new_height}") # 应用高斯模糊减少锯齿 blurred = cv2.GaussianBlur(cv2_image, (3, 3), 0) # 使用双三次插值降采样 downsampled = cv2.resize(blurred, (new_width, new_height), interpolation=cv2.INTER_CUBIC) # 如果需要,应用锐化增强 if sharpen: kernel = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]]) downsampled = cv2.filter2D(downsampled, -1, kernel) # 将cv2图像转换回PIL格式 result_image = Image.fromarray(cv2.cvtColor(downsampled, cv2.COLOR_BGR2RGB)) return result_image def process_image(image, sharpen=True): """处理上传的图像,返回降采样结果""" if image is None: return None, None, "请提供图像" try: # 获取原始图像信息 original_width, original_height = image.size original_size = f"{original_width}x{original_height}" # 降采样图像 downsampled_image = downsample_image(image, sharpen=sharpen) # 获取降采样后图像信息 downsampled_width, downsampled_height = downsampled_image.size downsampled_size = f"{downsampled_width}x{downsampled_height}" # 计算压缩率 original_pixels = original_width * original_height downsampled_pixels = downsampled_width * downsampled_height compression_ratio = original_pixels / downsampled_pixels status = f"原始尺寸: {original_size} → 降采样后: {downsampled_size} (压缩率: {compression_ratio:.1f}x)" return image, downsampled_image, status except Exception as e: return None, None, f"处理失败: {str(e)}" def process_image_url(url, sharpen=True): """处理图像URL""" if not url: return None, None, "请提供图像URL" try: # 下载图像 image = download_image(url) # 调用处理函数 return process_image(image, sharpen=sharpen) except Exception as e: return None, None, f"处理失败: {str(e)}" def create_comparison_image(original, downsampled): """创建对比图像,并排显示原始图像和降采样图像""" if original is None or downsampled is None: return None # 获取图像尺寸 original_width, original_height = original.size downsampled_width, downsampled_height = downsampled.size # 计算目标高度,取较小值 target_height = min(original_height, downsampled_height) # 按比例缩放图像 original_scaled = original.resize((int(original_width * target_height / original_height), target_height)) downsampled_scaled = downsampled.resize((int(downsampled_width * target_height / downsampled_height), target_height)) # 创建新图像,并排显示 comparison_width = original_scaled.width + downsampled_scaled.width comparison_height = target_height comparison = Image.new('RGB', (comparison_width, comparison_height)) comparison.paste(original_scaled, (0, 0)) comparison.paste(downsampled_scaled, (original_scaled.width, 0)) return comparison def main(): # 示例图像URL example_images = [ "https://p26-doubao-search-sign.byteimg.com/labis/37b5a464e50688032736bf0c132848ce~tplv-be4g95zd3a-image.jpeg?rk3s=542c0f93&x-expires=1764660945&x-signature=e6oLB%2F8eHQeohzwBZRZSsTtJw8Y%3D", "https://p11-doubao-search-sign.byteimg.com/tos-cn-i-qvj2lq49k0/d0aa7a30b66a4c55a783d440e15cdb52~tplv-be4g95zd3a-image.jpeg?rk3s=542c0f93&x-expires=1764660945&x-signature=EB1%2F4QQ1nJr1U1CwV7Qw%2FoJDzwY%3D", "https://p11-doubao-search-sign.byteimg.com/labis/4ff8314a923313d6f18fbf0355993f21~tplv-be4g95zd3a-image.jpeg?rk3s=542c0f93&x-expires=1764660945&x-signature=a%2FihmjuTBzmmRTMsBZLaTQfhvtA%3D", "https://p26-doubao-search-sign.byteimg.com/labis/4279cfae8ecb40a269dccce03ae30c48~tplv-be4g95zd3a-image.jpeg?rk3s=542c0f93&x-expires=1764660945&x-signature=kVB4Wif5J7a3eMW8VyQn7dV4arE%3D" ] # 创建Gradio应用 with gr.Blocks(title="Resample Pro - 高质量图像降采样", theme=gr.themes.Soft( primary_hue="green", secondary_hue="blue", neutral_hue="slate", font=["Inter", "system-ui", "sans-serif"], spacing_size="md", radius_size="md" )) as demo: # 自定义CSS gr.Markdown(""" """) # 标题和说明 with gr.Row(): with gr.Column(scale=1): gr.Image("https://p3-flow-imagex-sign.byteimg.com/tos-cn-i-a9rns2rl98/rc/pc/super_tool/60c651b800994851bbdc482bc7745d82~tplv-a9rns2rl98-image.image?rcl=2025100315350927166B93AC1D320B5E7B&rk3s=8e244e95&rrcfp=f06b921b&x-expires=1762068959&x-signature=3nOCcuHdW5SKib3%2FE00MV7voRdc%3D", width=100, height=100, show_label=False) with gr.Column(scale=3): gr.Markdown("

Resample Pro

") gr.Markdown("

高质量图像降采样工具 - 将4K图像高效转换为1K,同时保留细节和质量

") gr.Markdown("---") # 输入区域 with gr.Row(): with gr.Column(scale=1): gr.Markdown("

上传图像

") image_input = gr.Image(type="pil", label="拖放或点击上传", height=300) gr.Markdown("

或输入图像URL

") url_input = gr.Textbox(label="图像URL") with gr.Row(): sharpen_toggle = gr.Checkbox(label="启用智能锐化", value=True) process_button = gr.Button("处理图像", variant="primary") with gr.Column(scale=1): gr.Markdown("

示例图像

") example_gallery = gr.Gallery( value=example_images, label="点击使用示例图像", columns=2, rows=2, height=300, object_fit="cover" ) gr.Markdown("---") # 结果区域 with gr.Row(): with gr.Column(scale=1): gr.Markdown("

原始图像

") original_output = gr.Image(label="原始图像", height=300, interactive=False) with gr.Column(scale=1): gr.Markdown("

降采样结果

") result_output = gr.Image(label="降采样后图像", height=300, interactive=False) # 状态和下载 with gr.Row(): status_output = gr.Textbox(label="处理状态", interactive=False) download_button = gr.Button("下载结果", variant="secondary") # 细节对比 gr.Markdown("

细节对比

") comparison_output = gr.Image(label="对比视图", height=400, interactive=False) # 事件处理 def handle_example_click(image_url): return image_url, "", None, None, "准备处理示例图像..." example_gallery.select( fn=handle_example_click, inputs=[example_gallery], outputs=[url_input, image_input, original_output, result_output, status_output] ) def handle_process(image, url, sharpen): if image is not None: return process_image(image, sharpen) elif url: return process_image_url(url, sharpen) else: return None, None, "请上传图像或提供URL" process_button.click( fn=handle_process, inputs=[image_input, url_input, sharpen_toggle], outputs=[original_output, result_output, status_output] ).then( fn=create_comparison_image, inputs=[original_output, result_output], outputs=[comparison_output] ) def handle_download(result_image): if result_image is None: return None, "没有可下载的图像" # 将图像转换为BytesIO buffered = BytesIO() result_image.save(buffered, format="PNG") buffered.seek(0) # 返回图像数据和文件名 return buffered, "图像已准备好下载" download_button.click( fn=handle_download, inputs=[result_output], outputs=[gr.File(label="下载图像", type="binary"), status_output] ) # 页面加载时的欢迎信息 gr.Markdown("

欢迎使用Resample Pro!上传一张高分辨率图像或使用示例图像开始体验。

") # 启动应用 demo.launch(share=True, server_name="0.0.0.0") if __name__ == "__main__": main()