diff --git a/utils/poster_notes_creator.py b/utils/poster_notes_creator.py index 6f82c00..f3df534 100644 --- a/utils/poster_notes_creator.py +++ b/utils/poster_notes_creator.py @@ -11,6 +11,7 @@ from PIL import ImageEnhance, ImageFilter from .output_handler import OutputHandler import io import math +from core.simple_collage import process_directory as process_collage # 尝试导入 scipy,如果失败则标记 try: @@ -193,10 +194,10 @@ class PosterNotesCreator: output_filename_template: 输出文件名模板 variation_strength: 变化强度,可以是 'low', 'medium', 'high' extra_effects: 是否应用额外效果 - collage_style: 拼图风格,可以是 'grid', 'mosaic', 'polaroid', 'slice', 'random' 或 None(不使用拼图) + collage_style: 拼图风格,可以是 'grid', 'mosaic', 'polaroid', 'slice', 'random' Returns: - List[str]: 保存的笔记图像路径列表 + List[str]: 保存的图像路径列表 """ logger.info(f"开始为主题 {topic_index} 变体 {variant_index} 选择额外配图") @@ -333,56 +334,80 @@ class PosterNotesCreator: seed, variation_strength, extra_effects, - collage_style=None + collage_style="slice" ): """处理单张图像 - 此方法可在独立进程中运行""" try: - # 加载图像 - image = Image.open(image_path) + # 使用core.simple_collage模块处理图像 + style = collage_style if collage_style else "slice" - # 处理图像,优先使用拼图处理而不是数字指纹模块 - if collage_style: - # 如果指定了拼图风格,则使用拼图处理 - processed_image = self.create_collage_image( - image, - (3, 4), - style=collage_style, - seed=seed + # 创建临时目录来存放图像,以便传递给process_collage函数 + import tempfile + import shutil + + with tempfile.TemporaryDirectory() as temp_dir: + # 复制图像到临时目录 + temp_image_path = os.path.join(temp_dir, image_filename) + shutil.copy2(image_path, temp_image_path) + + # 设置随机种子以确保结果一致性 + if seed is not None: + random.seed(seed) + np.random.seed(seed) + + # 调用core.simple_collage模块处理图像 + target_size = (900, 1200) # 3:4比例 + collage_images, used_image_filenames = process_collage( + temp_dir, + style=style, + target_size=target_size, + output_count=1 ) - else: - # 调整为目标比例但不使用数字指纹模块 - processed_image = self.optimized_process_image( - image, - (3, 4), - add_variation=True, - seed=seed, - variation_strength=variation_strength, - extra_effects=False # 不使用高强度数字指纹模块 + + # 重置随机种子 + if seed is not None: + random.seed() + np.random.seed() + + if not collage_images or len(collage_images) == 0: + logger.error(f"拼图模块没有生成有效的图像: {image_filename}") + return None + + processed_image = collage_images[0] + + # 确保图像是RGB模式,解决"cannot write mode RGBA as JPEG"错误 + if processed_image.mode == 'RGBA': + logger.debug(f"将RGBA图像转换为RGB模式: {image_filename}") + # 创建白色背景并粘贴RGBA图像 + background = Image.new('RGB', processed_image.size, (255, 255, 255)) + background.paste(processed_image, mask=processed_image.split()[3]) # 使用alpha通道作为mask + processed_image = background + elif processed_image.mode != 'RGB': + logger.debug(f"将{processed_image.mode}图像转换为RGB模式: {image_filename}") + processed_image = processed_image.convert('RGB') + + # 创建元数据 + additional_metadata = { + "original_image": image_filename, + "additional_index": index + 1, + "source_dir": source_dir, + "is_additional_image": True, + "processed": True, + "aspect_ratio": "3:4", + "collage_style": style + } + + # 使用输出处理器保存图像 + return self.output_handler.handle_generated_image( + run_id, + topic_index, + variant_index, + 'additional', # 图像类型为additional + processed_image, + output_filename, + additional_metadata ) - - # 创建元数据 - additional_metadata = { - "original_image": image_filename, - "additional_index": index + 1, - "source_dir": source_dir, - "is_additional_image": True, - "processed": True, - "aspect_ratio": "3:4", - "variation_applied": True, - "variation_strength": variation_strength, - "collage_style": collage_style if collage_style else "none" - } - - # 使用输出处理器保存图像 - return self.output_handler.handle_generated_image( - run_id, - topic_index, - variant_index, - 'additional', # 图像类型为additional - processed_image, - output_filename, - additional_metadata - ) + except Exception as e: logger.error(f"处理图像时出错 '{image_filename}': {e}") logger.error(traceback.format_exc()) @@ -609,63 +634,30 @@ class PosterNotesCreator: elif style == "slice": # 切片风格: 水平或垂直切片并错开 - direction = random.choice(["horizontal", "vertical"]) + # 固定使用水平切片 collage = Image.new('RGB', (base_width, base_height), (255, 255, 255)) - if direction == "horizontal": - # 水平切片 - num_slices = random.randint(4, 8) - slice_height = base_height // num_slices + # 水平切片 + num_slices = 6 # 固定切片数量 + slice_height = base_height // num_slices + + for i in range(num_slices): + # 切出原图片片 + top = i * slice_height + bottom = min(top + slice_height, base_height) + slice_img = image_base.crop((0, top, base_width, bottom)) - for i in range(num_slices): - # 切出原图片片 - top = i * slice_height - bottom = min(top + slice_height, base_height) - slice_img = image_base.crop((0, top, base_width, bottom)) - - # 确定偏移量 - offset = random.randint(-30, 30) if i % 2 == 1 else 0 - # 确保偏移后不超出边界 - offset = max(-base_width // 4, min(base_width // 4, offset)) - - # 粘贴到拼图,带偏移 - paste_left = offset - if paste_left < 0: - # 如果左侧偏移超出边界,需要裁剪 - slice_img = slice_img.crop((-paste_left, 0, slice_img.width, slice_img.height)) - paste_left = 0 - elif paste_left + slice_img.width > base_width: - # 如果右侧偏移超出边界,需要裁剪 + # 只在奇数行应用固定偏移,让效果更整齐 + offset = 20 if i % 2 == 1 else 0 # 固定偏移量,更可控 + + # 粘贴到拼图,带偏移 + paste_left = offset + if paste_left > 0: + # 如果右侧偏移超出边界,需要裁剪 + if paste_left + slice_img.width > base_width: slice_img = slice_img.crop((0, 0, base_width - paste_left, slice_img.height)) - - collage.paste(slice_img, (paste_left, top)) - else: - # 垂直切片 - num_slices = random.randint(4, 8) - slice_width = base_width // num_slices - for i in range(num_slices): - # 切出原图片片 - left = i * slice_width - right = min(left + slice_width, base_width) - slice_img = image_base.crop((left, 0, right, base_height)) - - # 确定偏移量 - offset = random.randint(-30, 30) if i % 2 == 1 else 0 - # 确保偏移后不超出边界 - offset = max(-base_height // 4, min(base_height // 4, offset)) - - # 粘贴到拼图,带偏移 - paste_top = offset - if paste_top < 0: - # 如果上侧偏移超出边界,需要裁剪 - slice_img = slice_img.crop((0, -paste_top, slice_img.width, slice_img.height)) - paste_top = 0 - elif paste_top + slice_img.height > base_height: - # 如果下侧偏移超出边界,需要裁剪 - slice_img = slice_img.crop((0, 0, slice_img.width, base_height - paste_top)) - - collage.paste(slice_img, (left, paste_top)) + collage.paste(slice_img, (paste_left, top)) else: # 默认情况,直接返回调整后的图像 @@ -682,7 +674,7 @@ class PosterNotesCreator: logger.info(f"拼图图像创建完成,风格: {style}") return result - + def add_dct_noise(self, image: Image.Image, intensity: float = 0.1, block_size: int = 8) -> Image.Image: """ 在DCT域添加噪声以对抗pHash (需要Scipy) - 强化版 @@ -1799,10 +1791,10 @@ def select_additional_images( output_filename_template: 输出文件名模板 variation_strength: 变化强度 extra_effects: 是否应用额外效果 - collage_style: 拼图风格,可以是 'grid', 'mosaic', 'polaroid', 'slice', 'random' 或 None(不使用拼图) + collage_style: 拼图风格,可以是 'grid', 'mosaic', 'polaroid', 'slice', 'random' Returns: - List[str]: 保存的笔记图像路径列表 + List[str]: 保存的图像路径列表 """ logger.info(f"开始为主题 {topic_index} 变体 {variant_index} 选择额外配图") @@ -1814,7 +1806,7 @@ def select_additional_images( # 创建处理器实例 creator = PosterNotesCreator(output_handler) - # 使用修改后的方法处理图像 + # 使用拼图处理图像 return creator.create_additional_images( run_id, topic_index, @@ -1826,4 +1818,4 @@ def select_additional_images( variation_strength, extra_effects, collage_style - ) \ No newline at end of file + ) \ No newline at end of file