diff --git a/2502/.gitignore b/2502/.gitignore new file mode 100644 index 0000000..36deac7 --- /dev/null +++ b/2502/.gitignore @@ -0,0 +1,22 @@ +# Python 缓存 +__pycache__/ +*.pyc + +# 虚拟环境 + #venv/ + +# IDE 设置(例如 PyCharm) +.idea/ + + # for ss2025 数据 +*.csv +*.xlsx +*.jpg +*.png +*.dcm +*.raw +*.mhd +*.nii +*.nii.gz +*.npz +*.attrs diff --git a/R1/r1.py b/R1/r1.py new file mode 100644 index 0000000..24a6b58 --- /dev/null +++ b/R1/r1.py @@ -0,0 +1,327 @@ +import argparse +import numpy as np +from PIL import Image +import os +import sys + + +def load_image(image_path): + """ + 加载图像文件并转换为numpy数组 + + Args: + image_path (str): 输入图像路径 + + Returns: + numpy.ndarray: 图像数据 (H, W, C) + + Raises: + FileNotFoundError: 当图像文件不存在时 + ValueError: 当图像格式不支持时 + """ + try: + # 检查文件是否存在 + if not os.path.exists(image_path): + raise FileNotFoundError(f"图像文件不存在: {image_path}") + + image = Image.open(image_path) + image_array = np.array(image) + print(f"✅ 成功加载图像: {image_path}") + print(f"📐 原始图像尺寸: {image_array.shape} (高度, 宽度, 通道数)") + return image_array + except FileNotFoundError as e: + raise e + except Exception as e: + raise ValueError(f"❌ 无法加载图像 '{image_path}': {e}") + + +def save_image(image_array, output_path): + """ + 将numpy数组保存为图像文件 + + Args: + image_array (numpy.ndarray): 图像数据 + output_path (str): 输出图像路径 + """ + try: + # 确保输出目录存在 + os.makedirs(os.path.dirname(output_path) if os.path.dirname(output_path) else '.', exist_ok=True) + + image = Image.fromarray(image_array.astype(np.uint8)) + image.save(output_path) + print(f"✅ 成功保存图像: {output_path}") + print(f"📐 输出图像尺寸: {image_array.shape}") + except Exception as e: + raise ValueError(f"❌ 无法保存图像 '{output_path}': {e}") + + +def process_image(input_array, output_size, anchor_point): + """ + 核心处理函数:根据输出尺寸和基准点进行裁剪或填充 + + Args: + input_array (numpy.ndarray): 输入图像数组 (H, W, C) + output_size (int): 输出图像尺寸(正方形) + anchor_point (int): 基准点 (0-8) + + Returns: + numpy.ndarray: 处理后的图像数组 + + Raises: + ValueError: 当参数无效时 + """ + # 输入验证 + if len(input_array.shape) != 3 or input_array.shape[2] not in [3, 4]: + raise ValueError("❌ 输入必须是3通道(RGB)或4通道(RGBA)彩色图像") + + if output_size <= 0: + raise ValueError("❌ 输出尺寸必须为正整数") + + if anchor_point not in range(0, 9): + raise ValueError("❌ 基准点必须在0-8范围内") + + input_height, input_width, channels = input_array.shape + print(f"📥 输入尺寸: {input_width}x{input_height}, 通道数: {channels}") + print(f"🎯 目标尺寸: {output_size}x{output_size}, 基准点: {anchor_point}") + + # 创建输出数组(初始为黑色) + output_array = np.zeros((output_size, output_size, channels), dtype=input_array.dtype) + + # 计算裁剪或填充的区域 + crop_height = min(input_height, output_size) + crop_width = min(input_width, output_size) + + print(f"✂️ 实际复制区域: {crop_width}x{crop_height}") + + # 根据基准点计算源和目标坐标 + src_x, src_y, dst_x, dst_y = calculate_coordinates( + input_width, input_height, output_size, crop_width, crop_height, anchor_point + ) + + # 执行裁剪或填充操作 + output_array[dst_y:dst_y + crop_height, dst_x:dst_x + crop_width] = \ + input_array[src_y:src_y + crop_height, src_x:src_x + crop_width] + + # 判断是裁剪还是填充 + if output_size > input_width or output_size > input_height: + operation = "填充(Padding)" + elif output_size < input_width or output_size < input_height: + operation = "裁剪(Cropping)" + else: + operation = "尺寸不变" + + print(f"🔄 操作类型: {operation}") + + return output_array + + +def calculate_coordinates(input_width, input_height, output_size, crop_width, crop_height, anchor_point): + """ + 根据基准点计算源图像和目标图像的坐标 + + Args: + input_width (int): 输入图像宽度 + input_height (int): 输入图像高度 + output_size (int): 输出图像尺寸 + crop_width (int): 裁剪宽度 + crop_height (int): 裁剪高度 + anchor_point (int): 基准点 + + Returns: + tuple: (src_x, src_y, dst_x, dst_y) + """ + # 基准点映射说明: + anchor_names = { + 0: "左上(Top-Left)", 1: "中上(Top-Center)", 2: "右上(Top-Right)", + 3: "左中(Middle-Left)", 4: "中心(Center)", 5: "右中(Middle-Right)", + 6: "左下(Bottom-Left)", 7: "中下(Bottom-Center)", 8: "右下(Bottom-Right)" + } + + print(f"📍 基准点: {anchor_point} - {anchor_names[anchor_point]}") + + # 源图像起始坐标(从输入图像中裁剪的部分) + if anchor_point in [0, 3, 6]: # 左对齐 + src_x = 0 + elif anchor_point in [1, 4, 7]: # 水平居中 + src_x = (input_width - crop_width) // 2 + else: # 右对齐 [2, 5, 8] + src_x = input_width - crop_width + + if anchor_point in [0, 1, 2]: # 上对齐 + src_y = 0 + elif anchor_point in [3, 4, 5]: # 垂直居中 + src_y = (input_height - crop_height) // 2 + else: # 下对齐 [6, 7, 8] + src_y = input_height - crop_height + + # 目标图像起始坐标(在输出图像中放置的位置) + if anchor_point in [0, 3, 6]: # 左对齐 + dst_x = 0 + elif anchor_point in [1, 4, 7]: # 水平居中 + dst_x = (output_size - crop_width) // 2 + else: # 右对齐 [2, 5, 8] + dst_x = output_size - crop_width + + if anchor_point in [0, 1, 2]: # 上对齐 + dst_y = 0 + elif anchor_point in [3, 4, 5]: # 垂直居中 + dst_y = (output_size - crop_height) // 2 + else: # 下对齐 [6, 7, 8] + dst_y = output_size - crop_height + + print(f"🎯 源坐标: ({src_x}, {src_y}), 目标坐标: ({dst_x}, {dst_y})") + + return src_x, src_y, dst_x, dst_y + + +def setup_argument_parser(): + """ + 设置命令行参数解析器 + + Returns: + argparse.ArgumentParser: 配置好的参数解析器 + """ + parser = argparse.ArgumentParser( + description="🎨 彩色图像裁剪与填充处理器", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +📋 基准点选项 (0-8): + 0: 左上(Top-Left) 1: 中上(Top-Center) 2: 右上(Top-Right) + 3: 左中(Middle-Left) 4: 中心(Center) 5: 右中(Middle-Right) + 6: 左下(Bottom-Left) 7: 中下(Bottom-Center) 8: 右下(Bottom-Right) + +💡 使用示例: + python image_processor.py input.jpg output.jpg 512 4 + python image_processor.py photo.png result.png 256 0 + +🚀 完整演示: + python image_processor.py "/Users/liulaolao/SkillSemi2025/pepper.png" "output_512_center.jpg" 512 4 + """ + ) + + parser.add_argument( + "input_image", + help="📥 输入图像文件路径" + ) + + parser.add_argument( + "output_image", + help="📤 输出图像文件路径" + ) + + parser.add_argument( + "output_size", + type=int, + help="📐 输出图像尺寸(正方形边长)" + ) + + parser.add_argument( + "anchor_point", + type=int, + choices=range(0, 9), # 0-8 + help="📍 裁剪/填充基准点 (0-8)" + ) + + return parser + + +def demo_with_fixed_path(): + """ + 使用固定路径进行演示的函数 + """ + print("🚀 开始使用固定路径演示图像处理...") + + # 固定参数设置 + input_path = "/Users/liulaolao/SkillSemi2025/pepper.png" + output_sizes = [300, 512, 800] # 测试不同尺寸 + anchor_points = [0, 4, 8] # 测试不同基准点:左上、中心、右下 + + try: + # 加载图像 + original_image = load_image(input_path) + original_height, original_width, _ = original_image.shape + + print(f"\n📊 原始图像信息:") + print(f" 宽度: {original_width}px") + print(f" 高度: {original_height}px") + + for size in output_sizes: + for anchor in anchor_points: + print(f"\n{'=' * 60}") + print(f"🔄 处理中: 尺寸={size}, 基准点={anchor}") + print(f"{'=' * 60}") + + # 处理图像 + processed_image = process_image(original_image, size, anchor) + + # 生成输出文件名 + output_filename = f"pepper_{size}px_anchor{anchor}.jpg" + output_path = os.path.join("/Users/liulaolao/SkillSemi2025/", output_filename) + + # 保存结果 + save_image(processed_image, output_path) + + print(f"\n🎉 所有演示完成!生成的图像已保存到 SkillSemi2025 目录") + + except Exception as e: + print(f"❌ 演示过程中发生错误: {e}") + return False + + return True + + +def main(): + """主函数""" + try: + # 设置参数解析器 + parser = setup_argument_parser() + + # 检查是否有命令行参数 + if len(sys.argv) == 1: + # 没有参数时,运行固定路径演示 + print("🎮 未提供命令行参数,运行固定路径演示模式...") + demo_with_fixed_path() + else: + # 有参数时,正常解析并运行 + args = parser.parse_args() + + print("=" * 60) + print("🎨 彩色图像裁剪与填充处理器") + print("=" * 60) + + # 显示参数信息 + print(f"📥 输入文件: {args.input_image}") + print(f"📤 输出文件: {args.output_image}") + print(f"📐 输出尺寸: {args.output_size}") + print(f"📍 基准点: {args.anchor_point}") + print("-" * 60) + + # 加载图像 + input_array = load_image(args.input_image) + + # 处理图像 + output_array = process_image(input_array, args.output_size, args.anchor_point) + + # 保存结果 + save_image(output_array, args.output_image) + + print("-" * 60) + print("✅ 处理完成!") + print("=" * 60) + + except FileNotFoundError as e: + print(f"❌ 文件错误: {e}") + sys.exit(1) + except ValueError as e: + print(f"❌ 参数错误: {e}") + sys.exit(1) + except KeyboardInterrupt: + print("\n⏹️ 程序被用户中断") + sys.exit(1) + except Exception as e: + print(f"❌ 未知错误: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/r1.py b/r1.py deleted file mode 100644 index 24a6b58..0000000 --- a/r1.py +++ /dev/null @@ -1,327 +0,0 @@ -import argparse -import numpy as np -from PIL import Image -import os -import sys - - -def load_image(image_path): - """ - 加载图像文件并转换为numpy数组 - - Args: - image_path (str): 输入图像路径 - - Returns: - numpy.ndarray: 图像数据 (H, W, C) - - Raises: - FileNotFoundError: 当图像文件不存在时 - ValueError: 当图像格式不支持时 - """ - try: - # 检查文件是否存在 - if not os.path.exists(image_path): - raise FileNotFoundError(f"图像文件不存在: {image_path}") - - image = Image.open(image_path) - image_array = np.array(image) - print(f"✅ 成功加载图像: {image_path}") - print(f"📐 原始图像尺寸: {image_array.shape} (高度, 宽度, 通道数)") - return image_array - except FileNotFoundError as e: - raise e - except Exception as e: - raise ValueError(f"❌ 无法加载图像 '{image_path}': {e}") - - -def save_image(image_array, output_path): - """ - 将numpy数组保存为图像文件 - - Args: - image_array (numpy.ndarray): 图像数据 - output_path (str): 输出图像路径 - """ - try: - # 确保输出目录存在 - os.makedirs(os.path.dirname(output_path) if os.path.dirname(output_path) else '.', exist_ok=True) - - image = Image.fromarray(image_array.astype(np.uint8)) - image.save(output_path) - print(f"✅ 成功保存图像: {output_path}") - print(f"📐 输出图像尺寸: {image_array.shape}") - except Exception as e: - raise ValueError(f"❌ 无法保存图像 '{output_path}': {e}") - - -def process_image(input_array, output_size, anchor_point): - """ - 核心处理函数:根据输出尺寸和基准点进行裁剪或填充 - - Args: - input_array (numpy.ndarray): 输入图像数组 (H, W, C) - output_size (int): 输出图像尺寸(正方形) - anchor_point (int): 基准点 (0-8) - - Returns: - numpy.ndarray: 处理后的图像数组 - - Raises: - ValueError: 当参数无效时 - """ - # 输入验证 - if len(input_array.shape) != 3 or input_array.shape[2] not in [3, 4]: - raise ValueError("❌ 输入必须是3通道(RGB)或4通道(RGBA)彩色图像") - - if output_size <= 0: - raise ValueError("❌ 输出尺寸必须为正整数") - - if anchor_point not in range(0, 9): - raise ValueError("❌ 基准点必须在0-8范围内") - - input_height, input_width, channels = input_array.shape - print(f"📥 输入尺寸: {input_width}x{input_height}, 通道数: {channels}") - print(f"🎯 目标尺寸: {output_size}x{output_size}, 基准点: {anchor_point}") - - # 创建输出数组(初始为黑色) - output_array = np.zeros((output_size, output_size, channels), dtype=input_array.dtype) - - # 计算裁剪或填充的区域 - crop_height = min(input_height, output_size) - crop_width = min(input_width, output_size) - - print(f"✂️ 实际复制区域: {crop_width}x{crop_height}") - - # 根据基准点计算源和目标坐标 - src_x, src_y, dst_x, dst_y = calculate_coordinates( - input_width, input_height, output_size, crop_width, crop_height, anchor_point - ) - - # 执行裁剪或填充操作 - output_array[dst_y:dst_y + crop_height, dst_x:dst_x + crop_width] = \ - input_array[src_y:src_y + crop_height, src_x:src_x + crop_width] - - # 判断是裁剪还是填充 - if output_size > input_width or output_size > input_height: - operation = "填充(Padding)" - elif output_size < input_width or output_size < input_height: - operation = "裁剪(Cropping)" - else: - operation = "尺寸不变" - - print(f"🔄 操作类型: {operation}") - - return output_array - - -def calculate_coordinates(input_width, input_height, output_size, crop_width, crop_height, anchor_point): - """ - 根据基准点计算源图像和目标图像的坐标 - - Args: - input_width (int): 输入图像宽度 - input_height (int): 输入图像高度 - output_size (int): 输出图像尺寸 - crop_width (int): 裁剪宽度 - crop_height (int): 裁剪高度 - anchor_point (int): 基准点 - - Returns: - tuple: (src_x, src_y, dst_x, dst_y) - """ - # 基准点映射说明: - anchor_names = { - 0: "左上(Top-Left)", 1: "中上(Top-Center)", 2: "右上(Top-Right)", - 3: "左中(Middle-Left)", 4: "中心(Center)", 5: "右中(Middle-Right)", - 6: "左下(Bottom-Left)", 7: "中下(Bottom-Center)", 8: "右下(Bottom-Right)" - } - - print(f"📍 基准点: {anchor_point} - {anchor_names[anchor_point]}") - - # 源图像起始坐标(从输入图像中裁剪的部分) - if anchor_point in [0, 3, 6]: # 左对齐 - src_x = 0 - elif anchor_point in [1, 4, 7]: # 水平居中 - src_x = (input_width - crop_width) // 2 - else: # 右对齐 [2, 5, 8] - src_x = input_width - crop_width - - if anchor_point in [0, 1, 2]: # 上对齐 - src_y = 0 - elif anchor_point in [3, 4, 5]: # 垂直居中 - src_y = (input_height - crop_height) // 2 - else: # 下对齐 [6, 7, 8] - src_y = input_height - crop_height - - # 目标图像起始坐标(在输出图像中放置的位置) - if anchor_point in [0, 3, 6]: # 左对齐 - dst_x = 0 - elif anchor_point in [1, 4, 7]: # 水平居中 - dst_x = (output_size - crop_width) // 2 - else: # 右对齐 [2, 5, 8] - dst_x = output_size - crop_width - - if anchor_point in [0, 1, 2]: # 上对齐 - dst_y = 0 - elif anchor_point in [3, 4, 5]: # 垂直居中 - dst_y = (output_size - crop_height) // 2 - else: # 下对齐 [6, 7, 8] - dst_y = output_size - crop_height - - print(f"🎯 源坐标: ({src_x}, {src_y}), 目标坐标: ({dst_x}, {dst_y})") - - return src_x, src_y, dst_x, dst_y - - -def setup_argument_parser(): - """ - 设置命令行参数解析器 - - Returns: - argparse.ArgumentParser: 配置好的参数解析器 - """ - parser = argparse.ArgumentParser( - description="🎨 彩色图像裁剪与填充处理器", - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=""" -📋 基准点选项 (0-8): - 0: 左上(Top-Left) 1: 中上(Top-Center) 2: 右上(Top-Right) - 3: 左中(Middle-Left) 4: 中心(Center) 5: 右中(Middle-Right) - 6: 左下(Bottom-Left) 7: 中下(Bottom-Center) 8: 右下(Bottom-Right) - -💡 使用示例: - python image_processor.py input.jpg output.jpg 512 4 - python image_processor.py photo.png result.png 256 0 - -🚀 完整演示: - python image_processor.py "/Users/liulaolao/SkillSemi2025/pepper.png" "output_512_center.jpg" 512 4 - """ - ) - - parser.add_argument( - "input_image", - help="📥 输入图像文件路径" - ) - - parser.add_argument( - "output_image", - help="📤 输出图像文件路径" - ) - - parser.add_argument( - "output_size", - type=int, - help="📐 输出图像尺寸(正方形边长)" - ) - - parser.add_argument( - "anchor_point", - type=int, - choices=range(0, 9), # 0-8 - help="📍 裁剪/填充基准点 (0-8)" - ) - - return parser - - -def demo_with_fixed_path(): - """ - 使用固定路径进行演示的函数 - """ - print("🚀 开始使用固定路径演示图像处理...") - - # 固定参数设置 - input_path = "/Users/liulaolao/SkillSemi2025/pepper.png" - output_sizes = [300, 512, 800] # 测试不同尺寸 - anchor_points = [0, 4, 8] # 测试不同基准点:左上、中心、右下 - - try: - # 加载图像 - original_image = load_image(input_path) - original_height, original_width, _ = original_image.shape - - print(f"\n📊 原始图像信息:") - print(f" 宽度: {original_width}px") - print(f" 高度: {original_height}px") - - for size in output_sizes: - for anchor in anchor_points: - print(f"\n{'=' * 60}") - print(f"🔄 处理中: 尺寸={size}, 基准点={anchor}") - print(f"{'=' * 60}") - - # 处理图像 - processed_image = process_image(original_image, size, anchor) - - # 生成输出文件名 - output_filename = f"pepper_{size}px_anchor{anchor}.jpg" - output_path = os.path.join("/Users/liulaolao/SkillSemi2025/", output_filename) - - # 保存结果 - save_image(processed_image, output_path) - - print(f"\n🎉 所有演示完成!生成的图像已保存到 SkillSemi2025 目录") - - except Exception as e: - print(f"❌ 演示过程中发生错误: {e}") - return False - - return True - - -def main(): - """主函数""" - try: - # 设置参数解析器 - parser = setup_argument_parser() - - # 检查是否有命令行参数 - if len(sys.argv) == 1: - # 没有参数时,运行固定路径演示 - print("🎮 未提供命令行参数,运行固定路径演示模式...") - demo_with_fixed_path() - else: - # 有参数时,正常解析并运行 - args = parser.parse_args() - - print("=" * 60) - print("🎨 彩色图像裁剪与填充处理器") - print("=" * 60) - - # 显示参数信息 - print(f"📥 输入文件: {args.input_image}") - print(f"📤 输出文件: {args.output_image}") - print(f"📐 输出尺寸: {args.output_size}") - print(f"📍 基准点: {args.anchor_point}") - print("-" * 60) - - # 加载图像 - input_array = load_image(args.input_image) - - # 处理图像 - output_array = process_image(input_array, args.output_size, args.anchor_point) - - # 保存结果 - save_image(output_array, args.output_image) - - print("-" * 60) - print("✅ 处理完成!") - print("=" * 60) - - except FileNotFoundError as e: - print(f"❌ 文件错误: {e}") - sys.exit(1) - except ValueError as e: - print(f"❌ 参数错误: {e}") - sys.exit(1) - except KeyboardInterrupt: - print("\n⏹️ 程序被用户中断") - sys.exit(1) - except Exception as e: - print(f"❌ 未知错误: {e}") - sys.exit(1) - - -if __name__ == "__main__": - main() \ No newline at end of file