diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/LAB.iml b/.idea/LAB.iml new file mode 100644 index 0000000..c69f1c9 --- /dev/null +++ b/.idea/LAB.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..782eb56 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1f83f51 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/1.py b/1.py index e69de29..0aa4715 100644 --- a/1.py +++ b/1.py @@ -0,0 +1,3 @@ +git add . + + diff --git a/git_commannd b/git_commannd new file mode 100644 index 0000000..1df4812 --- /dev/null +++ b/git_commannd @@ -0,0 +1,3 @@ +git add . +git commit -m "commit message" +git push origin master \ No newline at end of file diff --git a/r1.py b/r1.py new file mode 100644 index 0000000..24a6b58 --- /dev/null +++ b/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