diff --git a/utils/poster_notes_creator.py b/utils/poster_notes_creator.py index b2d0423..96bda6d 100644 --- a/utils/poster_notes_creator.py +++ b/utils/poster_notes_creator.py @@ -10,6 +10,7 @@ import numpy as np from PIL import ImageEnhance, ImageFilter from .output_handler import OutputHandler import io +import math # 尝试导入 scipy,如果失败则标记 try: @@ -456,7 +457,7 @@ class PosterNotesCreator: def apply_smart_crop_resize(self, image: Image.Image, strength: str = "medium") -> Image.Image: """ - 应用智能裁剪和重缩放来抵抗哈希算法 + 应用智能裁剪和重缩放来抵抗哈希算法 (增强版) Args: image: 输入图像 @@ -469,14 +470,16 @@ class PosterNotesCreator: original_width, original_height = image.size logger.debug(f"应用智能裁剪+重缩放 (强度: {strength}), 原始尺寸: {original_width}x{original_height}") - # 根据强度决定裁剪量 (0-3 像素) + # 根据强度决定裁剪量 (增强) if strength == "low": - max_crop = 1 + max_crop = 3 # 原为 1 elif strength == "high": - max_crop = 3 + max_crop = 10 # 原为 3 else: # medium - max_crop = 2 + max_crop = 6 # 原为 2 + logger.debug(f"增强型智能裁剪: max_crop = {max_crop} 像素") + # 随机决定每边的裁剪量 crop_left = random.randint(0, max_crop) crop_top = random.randint(0, max_crop) @@ -491,9 +494,21 @@ class PosterNotesCreator: # 确保裁剪后尺寸至少为1x1 if left >= right or top >= bottom: - logger.warning("智能裁剪计算无效,跳过此步骤。") - return image - + logger.warning("智能裁剪计算无效(裁剪过多),尝试使用较小裁剪量。") + # 尝试减小裁剪量再次计算 + safe_max_crop = min(original_width // 4, original_height // 4, max_crop) # 保证不裁掉整个图 + crop_left = random.randint(0, safe_max_crop) + crop_top = random.randint(0, safe_max_crop) + crop_right = random.randint(0, safe_max_crop) + crop_bottom = random.randint(0, safe_max_crop) + left = crop_left + top = crop_top + right = original_width - crop_right + bottom = original_height - crop_bottom + if left >= right or top >= bottom: # 再次失败则跳过 + logger.error("智能裁剪再次失败,跳过此步骤。") + return image + logger.debug(f" 裁剪参数: L={crop_left}, T={crop_top}, R={crop_right}, B={crop_bottom}") logger.debug(f" 裁剪区域: ({left}, {top}, {right}, {bottom})") @@ -575,40 +590,40 @@ class PosterNotesCreator: """ logger.debug("移除图像元数据...") try: - # 从当前图像对象的像素数据创建一个新的Image对象 - # 这确保我们使用的是内存中修改后的数据 - # 保留原始格式信息,如果可用 - img_format = image.format if hasattr(image, 'format') else 'PNG' - - # 如果图像有alpha通道,需要正确处理 + # 确保图像处于适合保存的模式(例如RGB) if image.mode == 'RGBA': # 创建一个白色背景,然后粘贴带有alpha的图像 background = Image.new("RGB", image.size, (255, 255, 255)) background.paste(image, mask=image.split()[3]) # 3 is the alpha channel image_to_save = background - img_format = 'JPEG' # 通常去除alpha后存为JPEG elif image.mode == 'P': # 带调色板的图像转换为RGB image_to_save = image.convert('RGB') - img_format = 'JPEG' - else: + elif image.mode == 'L': + # 灰度图通常可以保存为JPEG或PNG image_to_save = image - - # 保存到内存缓冲区 - data = io.BytesIO() - # 确保保存时指定质量参数,避免默认压缩导致意外变化 - if img_format == 'JPEG': - image_to_save.save(data, format='JPEG', quality=95) # 使用高质量JPEG + elif image.mode == 'RGB': + image_to_save = image # 已经是RGB,直接使用 else: - # 对于PNG等无损格式,不需要质量参数 - image_to_save.save(data, format=img_format) + logger.warning(f"未知的图像模式 {image.mode},尝试转换为RGB进行元数据剥离。") + image_to_save = image.convert('RGB') + + # 保存到内存缓冲区,强制使用JPEG格式以剥离元数据 + data = io.BytesIO() + # --- FIX: 强制使用JPEG格式保存到缓冲区 --- + save_format = 'JPEG' + logger.debug(f"强制使用 {save_format} 格式保存以剥离元数据") + image_to_save.save(data, format=save_format, quality=95) # 使用高质量JPEG + # --- END FIX --- data.seek(0) # 重置缓冲区指针 reloaded_image = Image.open(data) logger.debug("元数据移除成功。") return reloaded_image + except Exception as e: logger.error(f"移除元数据时出错: {e}") + logger.error(traceback.format_exc()) # 打印详细错误 return image # 出错时返回原图 def apply_overlay_noise(self, image: Image.Image, alpha: int = 10, noise_type: str = 'uniform') -> Image.Image: @@ -664,66 +679,561 @@ class PosterNotesCreator: logger.error(traceback.format_exc()) # 打印详细错误 return image # 出错时返回原图 - def optimize_anti_hash_methods(self, image: Image.Image, strength: str = "medium") -> Image.Image: - """优化后的哈希对抗方法,策略: 裁剪缩放 + DCT噪声 + 叠加噪声""" - logger.info(f"--- 开始优化抗哈希方法 (强度: {strength}) - 叠加噪声策略 ---") - original_image_for_logging = image.copy() - - # --- 参数定义 --- - if strength == "low": - phash_intensity = 0.06 # 轻微DCT噪声 - color_hist_strength = 0.02 # 轻微颜色扰动 - apply_crop_resize = True # 应用裁剪缩放 - noise_alpha = random.randint(5, 8) # 低透明度噪声 - elif strength == "high": - phash_intensity = 0.20 # 较强DCT噪声 - color_hist_strength = 0.06 # 较强颜色扰动 - apply_crop_resize = True # 应用裁剪缩放 - noise_alpha = random.randint(12, 18) # 较高透明度噪声 - else: # medium - phash_intensity = 0.12 # 中等DCT噪声 - color_hist_strength = 0.04 # 中等颜色扰动 - apply_crop_resize = True # 应用裁剪缩放 - noise_alpha = random.randint(8, 12) # 中等透明度噪声 - - logger.debug(f"参数: pHash强度={phash_intensity:.2f}, 颜色强度={color_hist_strength:.2f}, 应用裁剪缩放={apply_crop_resize}, 噪声Alpha={noise_alpha}") - - processed_image = image # 从原图开始 - - # 1. 智能裁剪 + 重缩放 (策略C) - if apply_crop_resize: - processed_image = self.apply_smart_crop_resize(processed_image, strength) - - # 2. 强化的pHash对抗方法 (策略A) - logger.debug(f"应用 pHash 对抗 (强化DCT噪声), 强度={phash_intensity:.2f}") - processed_image = self.add_phash_noise(processed_image, intensity=phash_intensity) - - # 3. 保留轻微的颜色直方图扰动 - if color_hist_strength > 0: - logger.debug(f"应用颜色直方图扰动, 强度={color_hist_strength:.3f}") - processed_image = self.perturb_color_histogram(processed_image, strength=color_hist_strength) - - # 4. 应用低透明度噪声叠加 (新策略核心) - if noise_alpha > 0: - processed_image = self.apply_overlay_noise(processed_image, alpha=noise_alpha, noise_type='uniform') # 先用 uniform 试试 - # 内部已有日志 - - # --- 移除之前的 aHash块, dHash线, 区域变换, 高斯噪声等 --- - logger.debug("已移除 aHash/dHash特定对抗、区域变换、高斯噪声等。") - - # 对比修改前后 + def apply_ahash_specific_disruption(self, image: Image.Image, strength: str = "medium") -> Image.Image: + """ + 专门针对aHash的干扰方法:插入亮度带 (增强版) + Args: + image: 输入图像 + strength: 处理强度 ('low', 'medium', 'high') + Returns: + 处理后的图像 + """ try: - diff = ImageChops.difference(original_image_for_logging.convert('RGB'), processed_image.convert('RGB')).getbbox() # 确保模式一致 - if diff: - logger.info(f"图像已修改。差异区域: {diff}") + # 设定强度相关参数 (增强) + if strength == "low": + intensity = 0.08 # 原为 0.02 + bands = 2 + elif strength == "high": + intensity = 0.18 # 原为 0.04 + bands = 4 + else: # medium + intensity = 0.12 # 原为 0.03 + bands = 3 + + logger.debug(f"应用aHash特定干扰 (亮度带) (增强版), 强度:{strength}, 条带数:{bands}, 强度因子:{intensity:.3f}") + + # ... (其余逻辑不变) ... + result = image.copy() + width, height = result.size + pixels = result.load() + + is_horizontal = random.choice([True, False]) + band_positions = [] + if is_horizontal: + for _ in range(bands): + base_pos = random.randint(0, height - 1) + band_positions.append(base_pos) else: - logger.warning("!!!优化方法似乎未修改图像!!!") - except ValueError: - logger.warning("无法比较图像差异:模式可能不同或错误。") - except Exception as log_e: - logger.warning(f"无法比较图像差异: {log_e}") + for _ in range(bands): + base_pos = random.randint(0, width - 1) + band_positions.append(base_pos) + + for y_idx in range(height): # Renamed y to y_idx to avoid conflict + for x_idx in range(width): # Renamed x to x_idx to avoid conflict + is_on_band = False + if is_horizontal: + for pos in band_positions: + if abs(y_idx - pos) <= 1: + is_on_band = True + break + else: + for pos in band_positions: + if abs(x_idx - pos) <= 1: + is_on_band = True + break + + if is_on_band: + pixel = pixels[x_idx, y_idx] + if isinstance(pixel, int): + r_val = g_val = b_val = pixel # Renamed r,g,b to r_val, g_val, b_val + is_rgb = False + else: + if len(pixel) >= 3: + r_val, g_val, b_val = pixel[0], pixel[1], pixel[2] + is_rgb = True + else: + continue + + factor = 1.0 + intensity * (1 if random.random() > 0.5 else -1) + r_val, g_val, b_val = int(r_val * factor), int(g_val * factor), int(b_val * factor) + r_val, g_val, b_val = max(0, min(255, r_val)), max(0, min(255, g_val)), max(0, min(255, b_val)) + + if is_rgb: + if len(pixel) == 4: + pixels[x_idx, y_idx] = (r_val, g_val, b_val, pixel[3]) + else: + pixels[x_idx, y_idx] = (r_val, g_val, b_val) + else: + pixels[x_idx, y_idx] = r_val + + logger.debug(f"aHash特定干扰完成: {'水平' if is_horizontal else '垂直'}亮度带") + return result + + except Exception as e: + logger.error(f"应用aHash特定干扰时出错: {e}") + logger.error(traceback.format_exc()) + return image + + def apply_dhash_specific_disruption(self, image: Image.Image, strength: str = "medium") -> Image.Image: + """ + 专门针对dHash的干扰方法:梯度反向模式 (增强版) + Args: + image: 输入图像 + strength: 处理强度 ('low', 'medium', 'high') + Returns: + 处理后的图像 + """ + try: + # 设定强度相关参数 (增强) + if strength == "low": + gradient_strength = 0.08 # 原为 0.02 + regions = 2 + elif strength == "high": + gradient_strength = 0.18 # 原为 0.04 + regions = 4 + else: # medium + gradient_strength = 0.12 # 原为 0.03 + regions = 3 + + logger.debug(f"应用dHash特定干扰 (梯度反向) (增强版), 强度:{strength}, 区域数:{regions}, 梯度强度:{gradient_strength:.3f}") + + # ... (其余逻辑不变, 确保使用增强的 gradient_strength) ... + result = image.copy() + width, height = result.size + + for _ in range(regions): + region_w = random.randint(width//12, width//8) # Renamed region_width to region_w + region_h = random.randint(height//12, height//8) # Renamed region_height to region_h + region_x_coord = random.randint(0, width - region_w) # Renamed region_x to region_x_coord + region_y_coord = random.randint(0, height - region_h) # Renamed region_y to region_y_coord + + region = result.crop((region_x_coord, region_y_coord, region_x_coord + region_w, region_y_coord + region_h)) + region_array = np.array(region) + is_rgb = len(region_array.shape) == 3 + + if is_rgb: + gray_region = np.mean(region_array, axis=2).astype(np.uint8) + else: + gray_region = region_array + + h_gradients = np.zeros_like(gray_region, dtype=np.int16) + v_gradients = np.zeros_like(gray_region, dtype=np.int16) + + for y_idx in range(region_h): # Renamed y to y_idx + for x_idx in range(region_w-1): # Renamed x to x_idx + h_gradients[y_idx, x_idx] = int(gray_region[y_idx, x_idx+1]) - int(gray_region[y_idx, x_idx]) + + for y_idx in range(region_h-1): # Renamed y to y_idx + for x_idx in range(region_w): # Renamed x to x_idx + v_gradients[y_idx, x_idx] = int(gray_region[y_idx+1, x_idx]) - int(gray_region[y_idx, x_idx]) + + modified_region = region_array.astype(np.float32) + for y_idx in range(region_h): # Renamed y to y_idx + for x_idx in range(region_w): # Renamed x to x_idx + if x_idx < region_w-1 and abs(h_gradients[y_idx, x_idx]) > 5: + h_change = -h_gradients[y_idx, x_idx] * gradient_strength + if is_rgb: + for c_channel in range(3): # Renamed c to c_channel + modified_region[y_idx, x_idx+1, c_channel] = np.clip( + modified_region[y_idx, x_idx+1, c_channel] + h_change/2, 0, 255) + modified_region[y_idx, x_idx, c_channel] = np.clip( + modified_region[y_idx, x_idx, c_channel] - h_change/2, 0, 255) + else: + modified_region[y_idx, x_idx+1] = np.clip( + modified_region[y_idx, x_idx+1] + h_change/2, 0, 255) + modified_region[y_idx, x_idx] = np.clip( + modified_region[y_idx, x_idx] - h_change/2, 0, 255) + + if y_idx < region_h-1 and abs(v_gradients[y_idx, x_idx]) > 5: + v_change = -v_gradients[y_idx, x_idx] * gradient_strength + if is_rgb: + for c_channel in range(3): # Renamed c to c_channel + modified_region[y_idx+1, x_idx, c_channel] = np.clip( + modified_region[y_idx+1, x_idx, c_channel] + v_change/2, 0, 255) + modified_region[y_idx, x_idx, c_channel] = np.clip( + modified_region[y_idx, x_idx, c_channel] - v_change/2, 0, 255) + else: + modified_region[y_idx+1, x_idx] = np.clip( + modified_region[y_idx+1, x_idx] + v_change/2, 0, 255) + modified_region[y_idx, x_idx] = np.clip( + modified_region[y_idx, x_idx] - v_change/2, 0, 255) + + modified_region = modified_region.astype(np.uint8) + modified_region_image = Image.fromarray(modified_region) + result.paste(modified_region_image, (region_x_coord, region_y_coord)) + + logger.debug(f"dHash特定干扰完成: 在{regions}个区域应用梯度反向") + return result + + except Exception as e: + logger.error(f"应用dHash特定干扰时出错: {e}") + logger.error(traceback.format_exc()) + return image + + def apply_phash_specific_disruption(self, image: Image.Image, strength: str = "medium") -> Image.Image: + """ + 专门针对pHash的干扰方法:定向DCT系数修改 (增强版) + Args: + image: 输入图像 + strength: 处理强度 ('low', 'medium', 'high') + Returns: + 处理后的图像 + """ + if not SCIPY_AVAILABLE: + logger.warning("Scipy 未安装,无法执行pHash专用干扰。请运行 'pip install scipy'") + return image - logger.info(f"--- 完成优化抗哈希方法 (强度: {strength}) - 叠加噪声策略 ---") + try: + # 设定强度相关参数 (增强) + if strength == "low": + intensity = 0.20 # 原为 0.10 + key_positions_count = 4 + elif strength == "high": + intensity = 0.40 # 原为 0.20 + key_positions_count = 8 + else: # medium + intensity = 0.30 # 原为 0.15 + key_positions_count = 6 + + logger.debug(f"应用pHash特定干扰 (定向DCT干扰) (增强版), 强度:{strength}, 密度:{key_positions_count}, 强度因子:{intensity:.2f}") + + # ... (其余逻辑不变, 确保使用增强的 intensity) ... + gray_image = image.convert('L') + img_array_np = np.array(gray_image) # Renamed img_array to img_array_np + h_img, w_img = img_array_np.shape # Renamed h,w to h_img,w_img + + resized_array = np.array(gray_image.resize((32, 32), Image.LANCZOS)) + dct_array = dct(dct(resized_array.T, norm='ortho').T, norm='ortho') + + key_positions = [] + for i_pos in range(1, 8): # Renamed i to i_pos + for j_pos in range(1, 8): # Renamed j to j_pos + key_positions.append((i_pos, j_pos)) + + selected_positions = random.sample(key_positions, k=min(len(key_positions), key_positions_count)) + + block_h_size, block_w_size = h_img // 32, w_img // 32 # Renamed block_height, block_width + + for dct_y_coord, dct_x_coord in selected_positions: # Renamed dct_y, dct_x + orig_y_coord = dct_y_coord * block_h_size # Renamed orig_y to orig_y_coord + orig_x_coord = dct_x_coord * block_w_size # Renamed orig_x to orig_x_coord + + pattern_s = min(block_h_size, block_w_size) # Renamed pattern_size to pattern_s + for y_off in range(pattern_s): # Renamed y_offset to y_off + for x_off in range(pattern_s): # Renamed x_offset to x_off + y_val = orig_y_coord + y_off # Renamed y to y_val + x_val = orig_x_coord + x_off # Renamed x to x_val + if 0 <= y_val < h_img and 0 <= x_val < w_img: + offset_val = intensity * 20 * math.sin(2 * math.pi * (y_off / pattern_s)) * \ + math.cos(2 * math.pi * (x_off / pattern_s)) # Renamed offset to offset_val + img_array_np[y_val, x_val] = np.clip(img_array_np[y_val, x_val] + offset_val, 0, 255) + + result_img = Image.fromarray(img_array_np.astype(np.uint8)) # Renamed result to result_img + + if image.mode != 'L': + r_channel, g_channel, b_channel = image.split()[:3] # Renamed r,g,b to r_channel, g_channel, b_channel + + diff_img = ImageChops.difference(gray_image, result_img) # Renamed diff to diff_img + diff_array_np = np.array(diff_img) # Renamed diff_array to diff_array_np + + r_array_np = np.array(r_channel) # Renamed r_array to r_array_np + g_array_np = np.array(g_channel) # Renamed g_array to g_array_np + b_array_np = np.array(b_channel) # Renamed b_array to b_array_np + + transfer_factor = 0.8 + r_array_np = np.clip(r_array_np + diff_array_np * transfer_factor, 0, 255).astype(np.uint8) + g_array_np = np.clip(g_array_np + diff_array_np * transfer_factor, 0, 255).astype(np.uint8) + b_array_np = np.clip(b_array_np + diff_array_np * transfer_factor, 0, 255).astype(np.uint8) + + r_new_img = Image.fromarray(r_array_np) # Renamed r_new to r_new_img + g_new_img = Image.fromarray(g_array_np) # Renamed g_new to g_new_img + b_new_img = Image.fromarray(b_array_np) # Renamed b_new to b_new_img + + if image.mode == 'RGBA': + alpha_channel = image.split()[3] # Renamed a to alpha_channel + result_img = Image.merge('RGBA', (r_new_img, g_new_img, b_new_img, alpha_channel)) + else: + result_img = Image.merge('RGB', (r_new_img, g_new_img, b_new_img)) + + logger.debug(f"pHash特定干扰完成: 修改了{len(selected_positions)}个DCT关键位置") + return result_img + + except Exception as e: + logger.error(f"应用pHash特定干扰时出错: {e}") + logger.error(traceback.format_exc()) + return image + + def apply_block_based_perturbations(self, image: Image.Image, block_size: int = 16, strength: str = "medium") -> Image.Image: + """ + 对图像各个块应用不同的、独立的干扰策略 (增强版) + Args: + image: 输入图像 + block_size: 块大小 + strength: 处理强度 ('low', 'medium', 'high') + Returns: + 处理后的图像 + """ + try: + # 设定强度相关参数 (增强) + if strength == "low": + factor_range = 0.08 # 原为 0.03 + skip_prob = 0.5 + elif strength == "high": + factor_range = 0.18 # 原为 0.06 + skip_prob = 0.2 + else: # medium + factor_range = 0.12 # 原为 0.045 + skip_prob = 0.35 + + logger.debug(f"应用块级混合干扰 (增强版), 块大小:{block_size}, 强度:{strength}, 因子范围:{factor_range:.3f}") + + # ... (其余逻辑不变, 确保使用增强的 factor_range) ... + result = image.copy() # Renamed result_img to result + width, height = image.size + img_array = np.array(result) + is_rgb = len(img_array.shape) == 3 + + strategies = ['brightness', 'contrast', 'hue_shift', 'gradient_flip', 'micro_pattern', 'skip'] + processed_blocks = 0 + skipped_blocks = 0 + + for y_coord in range(0, height, block_size): # Renamed y to y_coord + for x_coord in range(0, width, block_size): # Renamed x to x_coord + block_w = min(block_size, width - x_coord) + block_h = min(block_size, height - y_coord) + + if block_w < 4 or block_h < 4: + continue + + current_strategy = 'skip' if random.random() < skip_prob else random.choice([s for s in strategies if s != 'skip']) # Renamed strategy to current_strategy + + if is_rgb: + current_block = img_array[y_coord:y_coord+block_h, x_coord:x_coord+block_w, :] # Renamed block to current_block + else: + current_block = img_array[y_coord:y_coord+block_h, x_coord:x_coord+block_w] + + if current_strategy == 'skip': + skipped_blocks +=1 + elif current_strategy == 'brightness': + factor = 1.0 + random.uniform(-factor_range, factor_range) + current_block = (current_block.astype(float) * factor).clip(0, 255).astype(np.uint8) + processed_blocks += 1 + elif current_strategy == 'contrast': + factor = 1.0 + random.uniform(-factor_range, factor_range) + if is_rgb: + mean_val = np.mean(current_block, axis=(0, 1), keepdims=True) + current_block = (((current_block.astype(float) - mean_val) * factor) + mean_val).clip(0, 255).astype(np.uint8) + else: + mean_val = np.mean(current_block) + current_block = (((current_block.astype(float) - mean_val) * factor) + mean_val).clip(0, 255).astype(np.uint8) + processed_blocks += 1 + elif current_strategy == 'hue_shift' and is_rgb: + r_factor = 1.0 - random.uniform(0, factor_range/2) + g_factor = 1.0 - random.uniform(0, factor_range/2) + b_factor = 1.0 - random.uniform(0, factor_range/2) + r_ch, g_ch, b_ch = current_block[:,:,0], current_block[:,:,1], current_block[:,:,2] # Renamed r,g,b to r_ch,g_ch,b_ch + current_block[:,:,0] = (r_ch * r_factor + g_ch * (1-r_factor)).clip(0, 255).astype(np.uint8) + current_block[:,:,1] = (g_ch * g_factor + b_ch * (1-g_factor)).clip(0, 255).astype(np.uint8) + current_block[:,:,2] = (b_ch * b_factor + r_ch * (1-b_factor)).clip(0, 255).astype(np.uint8) + processed_blocks += 1 + elif current_strategy == 'gradient_flip': + if block_w > 2 and block_h > 2: + mid_w, mid_h = block_w // 2, block_h // 2 + pattern_s = min(mid_w, mid_h) # Renamed pattern_size to pattern_s + for by_idx in range(1, pattern_s-1): # Renamed by to by_idx + for bx_idx in range(1, pattern_s-1): # Renamed bx to bx_idx + if is_rgb: + curr_val = np.mean(current_block[by_idx, bx_idx, :]) # Renamed curr to curr_val + right_val = np.mean(current_block[by_idx, bx_idx+1, :]) # Renamed right to right_val + below_val = np.mean(current_block[by_idx+1, bx_idx, :]) # Renamed below to below_val + if abs(curr_val - right_val) > 5: + diff_val = (curr_val - right_val) * factor_range # Renamed diff to diff_val + current_block[by_idx, bx_idx, :] = np.clip(current_block[by_idx, bx_idx, :] - diff_val/2, 0, 255).astype(np.uint8) + current_block[by_idx, bx_idx+1, :] = np.clip(current_block[by_idx, bx_idx+1, :] + diff_val/2, 0, 255).astype(np.uint8) + if abs(curr_val - below_val) > 5: + diff_val = (curr_val - below_val) * factor_range + current_block[by_idx, bx_idx, :] = np.clip(current_block[by_idx, bx_idx, :] - diff_val/2, 0, 255).astype(np.uint8) + current_block[by_idx+1, bx_idx, :] = np.clip(current_block[by_idx+1, bx_idx, :] + diff_val/2, 0, 255).astype(np.uint8) + else: + curr_val = float(current_block[by_idx, bx_idx]) + right_val = float(current_block[by_idx, bx_idx+1]) + below_val = float(current_block[by_idx+1, bx_idx]) + if abs(curr_val - right_val) > 5: + diff_val = (curr_val - right_val) * factor_range + current_block[by_idx, bx_idx] = np.clip(current_block[by_idx, bx_idx] - diff_val/2, 0, 255).astype(np.uint8) + current_block[by_idx, bx_idx+1] = np.clip(current_block[by_idx, bx_idx+1] + diff_val/2, 0, 255).astype(np.uint8) + if abs(curr_val - below_val) > 5: + diff_val = (curr_val - below_val) * factor_range + current_block[by_idx, bx_idx] = np.clip(current_block[by_idx, bx_idx] - diff_val/2, 0, 255).astype(np.uint8) + current_block[by_idx+1, bx_idx] = np.clip(current_block[by_idx+1, bx_idx] + diff_val/2, 0, 255).astype(np.uint8) + processed_blocks += 1 + elif current_strategy == 'micro_pattern': + pattern_type = random.choice(['dot', 'line', 'cross']) + center_y_coord, center_x_coord = block_h // 2, block_w // 2 # Renamed center_y, center_x + pattern_coords = [] + if pattern_type == 'dot': + pattern_coords = [(center_y_coord, center_x_coord)] + elif pattern_type == 'line': + if random.choice([True, False]): + pattern_coords = [(center_y_coord, cx_val) for cx_val in range(center_x_coord-1, center_x_coord+2)] # Renamed cx to cx_val + else: + pattern_coords = [(cy_val, center_x_coord) for cy_val in range(center_y_coord-1, center_y_coord+2)] # Renamed cy to cy_val + else: + pattern_coords.extend([(center_y_coord, cx_val) for cx_val in range(center_x_coord-1, center_x_coord+2)]) + pattern_coords.extend([(cy_val, center_x_coord) for cy_val in range(center_y_coord-1, center_y_coord+2) if (cy_val, center_x_coord) not in pattern_coords]) + + pattern_strength = random.uniform(factor_range*50, factor_range*100) + for py_coord, px_coord in pattern_coords: # Renamed py,px to py_coord,px_coord + if 0 <= py_coord < block_h and 0 <= px_coord < block_w: + if is_rgb: + target_channel = random.randint(0, 2) # Renamed channel to target_channel + if random.choice([True, False]): + current_block[py_coord, px_coord, target_channel] = np.clip(current_block[py_coord, px_coord, target_channel] + pattern_strength, 0, 255).astype(np.uint8) + else: + current_block[py_coord, px_coord, target_channel] = np.clip(current_block[py_coord, px_coord, target_channel] - pattern_strength, 0, 255).astype(np.uint8) + else: + if random.choice([True, False]): + current_block[py_coord, px_coord] = np.clip(current_block[py_coord, px_coord] + pattern_strength, 0, 255).astype(np.uint8) + else: + current_block[py_coord, px_coord] = np.clip(current_block[py_coord, px_coord] - pattern_strength, 0, 255).astype(np.uint8) + processed_blocks += 1 + + if is_rgb: + img_array[y_coord:y_coord+block_h, x_coord:x_coord+block_w, :] = current_block + else: + img_array[y_coord:y_coord+block_h, x_coord:x_coord+block_w] = current_block + + result = Image.fromarray(img_array) # Result was already defined + + logger.debug(f"块级混合干扰完成: 处理了{processed_blocks}个块, 跳过了{skipped_blocks}个块") + return result + + except Exception as e: + logger.error(f"应用块级混合干扰时出错: {e}") + logger.error(traceback.format_exc()) + return image + + def apply_strategic_hash_disruption(self, image: Image.Image, strength: str = "medium") -> Image.Image: + """ + 战略性哈希干扰:对各种哈希算法进行有针对性的干扰 + + 整合了多种针对性干扰策略,包括块级混合干扰和针对特定哈希算法的干扰。 + + Args: + image: 输入图像 + strength: 处理强度 ('low', 'medium', 'high') + + Returns: + 处理后的图像 + """ + try: + logger.info(f"开始战略性哈希干扰 (强度: {strength})") + original_image_for_logging = image.copy() + + # 设定策略应用概率 + if strength == "low": + ahash_prob = 0.7 + dhash_prob = 0.7 + phash_prob = 0.9 + block_prob = 0.6 + block_size = 24 + elif strength == "high": + ahash_prob = 0.9 + dhash_prob = 0.9 + phash_prob = 0.95 + block_prob = 0.8 + block_size = 16 + else: # medium + ahash_prob = 0.8 + dhash_prob = 0.8 + phash_prob = 0.9 + block_prob = 0.7 + block_size = 20 + + logger.debug(f"策略概率: aHash={ahash_prob:.1f}, dHash={dhash_prob:.1f}, pHash={phash_prob:.1f}, 块级={block_prob:.1f}") + + # 保存原图 + result = image.copy() + applied_strategies = [] + + # 1. 应用块级混合干扰 + if random.random() < block_prob: + result = self.apply_block_based_perturbations(result, block_size=block_size, strength=strength) + applied_strategies.append(f"BlockBased({block_size})") + + # 2. 应用针对特定哈希算法的干扰 + # 2.1 aHash特定干扰 + if random.random() < ahash_prob: + result = self.apply_ahash_specific_disruption(result, strength) + applied_strategies.append("aHash") + + # 2.2 dHash特定干扰 + if random.random() < dhash_prob: + result = self.apply_dhash_specific_disruption(result, strength) + applied_strategies.append("dHash") + + # 2.3 pHash特定干扰(最重要的一个) + if random.random() < phash_prob: + result = self.apply_phash_specific_disruption(result, strength) + applied_strategies.append("pHash") + + logger.info(f"已应用战略干扰: {', '.join(applied_strategies)}") + + # 对比修改前后 + try: + diff = ImageChops.difference(original_image_for_logging.convert('RGB'), result.convert('RGB')).getbbox() + if diff: + logger.info(f"图像已修改。差异区域: {diff}") + else: + logger.warning("!!!战略干扰似乎未修改图像!!!") + except Exception as log_e: + logger.warning(f"无法比较图像差异: {log_e}") + + logger.info(f"战略性哈希干扰完成 (强度: {strength})") + return result + + except Exception as e: + logger.error(f"应用战略性哈希干扰时出错: {e}") + logger.error(traceback.format_exc()) + return image # 出错时返回原图 + + def optimize_anti_hash_methods(self, image: Image.Image, strength: str = "medium") -> Image.Image: + """优化后的哈希对抗方法,使用新的分层增强策略""" + logger.info(f"--- 开始优化抗哈希方法 (强度: {strength}) - 分层增强策略 ---") + processed_image = image.copy() + + # 定义各阶段强度参数 + global_max_crop: int + global_overlay_alpha: int + global_color_hist_strength: float + + if strength == "low": + global_max_crop = 3 + global_overlay_alpha = random.randint(8, 12) + global_color_hist_strength = 0.03 + elif strength == "high": + global_max_crop = 10 + global_overlay_alpha = random.randint(18, 25) + global_color_hist_strength = 0.08 + else: # medium + global_max_crop = 6 + global_overlay_alpha = random.randint(12, 18) + global_color_hist_strength = 0.05 + + logger.debug(f"分层策略 - 全局扰动参数: strength_for_crop='{strength}' (内部max_crop将按新标准), overlay_alpha={global_overlay_alpha}, color_hist_strength={global_color_hist_strength:.3f}") + + # --- 层 1: 基础全局扰动 --- + logger.info("应用基础全局扰动...") + + # 1.1 智能裁剪 + 重缩放 (现在 apply_smart_crop_resize 内部已增强) + processed_image = self.apply_smart_crop_resize(processed_image, strength) + + # 1.2 低透明度噪声叠加 + processed_image = self.apply_overlay_noise(processed_image, alpha=global_overlay_alpha, noise_type='uniform') + + # 1.3 颜色直方图扰动 + if global_color_hist_strength > 0: # 确保强度大于0才应用 + processed_image = self.perturb_color_histogram(processed_image, strength=global_color_hist_strength) + + # --- 层 2: 战略性哈希干扰 (在基础扰动之上) --- + # apply_strategic_hash_disruption 内部调用的各 specific 和 block_based 方法已增强 + logger.info("应用战略性哈希干扰 (各子方法已增强)...") + processed_image = self.apply_strategic_hash_disruption(processed_image, strength) + + # --- 清除元数据 --- + processed_image = self.strip_metadata(processed_image) + + logger.info(f"--- 完成优化抗哈希方法 (强度: {strength}) - 分层增强策略 ---") return processed_image def optimized_process_image( @@ -741,28 +1251,32 @@ class PosterNotesCreator: random.seed(seed) np.random.seed(seed) - # 根据微调强度设置参数 + # 根据微调强度设置参数 (保留变化因子等) if variation_strength == "low": brightness_factor = random.uniform(0.97, 1.03) contrast_factor = random.uniform(0.97, 1.03) saturation_factor = random.uniform(0.97, 1.03) max_rotation = 0.5 border_size = random.randint(0, 1) - use_extra = random.random() < 0.3 and extra_effects + # use_extra = random.random() < 0.3 and extra_effects #<-- 旧逻辑 elif variation_strength == "high": brightness_factor = random.uniform(0.92, 1.08) contrast_factor = random.uniform(0.92, 1.08) saturation_factor = random.uniform(0.92, 1.08) max_rotation = 2.0 border_size = random.randint(0, 3) - use_extra = extra_effects + # use_extra = extra_effects #<-- 旧逻辑 (本身就是直接赋值) else: # medium brightness_factor = random.uniform(0.95, 1.05) contrast_factor = random.uniform(0.95, 1.05) saturation_factor = random.uniform(0.95, 1.05) max_rotation = 1.0 border_size = random.randint(0, 2) - use_extra = random.random() < 0.7 and extra_effects + # use_extra = random.random() < 0.7 and extra_effects #<-- 旧逻辑 + + # --- FIX: 直接使用传入的 extra_effects 控制是否启用抗哈希和额外效果 --- + use_extra = extra_effects + # --- END FIX --- # 调整图像为目标比例 width, height = image.size