121 lines
5.1 KiB
Python
121 lines
5.1 KiB
Python
import cv2
|
||
import numpy as np
|
||
import json
|
||
from datetime import datetime
|
||
|
||
|
||
class WatermarkAnalyzer:
|
||
def __init__(self, config_path="config/default_config.json"):
|
||
self.watermark_regions = []
|
||
self.selected_regions = []
|
||
self.config_path = config_path
|
||
self.load_config()
|
||
self._check_opencv_version()
|
||
|
||
def _check_opencv_version(self):
|
||
"""检查OpenCV版本,确定是否支持显著性检测"""
|
||
self.has_saliency = hasattr(cv2, 'saliency')
|
||
if not self.has_saliency:
|
||
print("警告: 当前OpenCV版本不支持显著性检测,将使用替代方法")
|
||
|
||
def load_config(self):
|
||
try:
|
||
with open(self.config_path, 'r') as f:
|
||
config = json.load(f)
|
||
self.inpaint_radius = config.get("inpaint_radius", 5)
|
||
self.inpaint_algorithm = config.get("inpaint_algorithm", cv2.INPAINT_TELEA)
|
||
self.dilate_size = config.get("dilate_size", 3)
|
||
self.use_adaptive_mask = config.get("use_adaptive_mask", True)
|
||
self.text_threshold = config.get("text_threshold", 180)
|
||
self.min_text_area = config.get("min_text_area", 100)
|
||
self.text_color_range = tuple(
|
||
tuple(c) for c in config.get("text_color_range", ((50, 50, 50), (180, 180, 180))))
|
||
self.stamp_color_range = tuple(
|
||
tuple(c) for c in config.get("stamp_color_range", ((0, 0, 100), (100, 100, 255))))
|
||
self.saliency_threshold = config.get("saliency_threshold", 0.5)
|
||
self.edge_threshold = config.get("edge_threshold", 100)
|
||
self.use_mser = config.get("use_mser", True)
|
||
self.use_color_filter = config.get("use_color_filter", True)
|
||
self.use_texture_analysis = config.get("use_texture_analysis", True)
|
||
except Exception as e:
|
||
print(f"加载配置失败: {e}")
|
||
self.reset_to_defaults()
|
||
|
||
# ... 其他方法保持不变 ...
|
||
|
||
def _detect_by_saliency(self, img):
|
||
"""基于显著性检测水印 - 兼容旧版OpenCV"""
|
||
if self.has_saliency:
|
||
# 使用标准显著性检测(如果支持)
|
||
try:
|
||
saliency = cv2.saliency.StaticSaliencySpectralResidual_create()
|
||
_, saliency_map = saliency.computeSaliency(img)
|
||
|
||
# 阈值处理
|
||
_, saliency_mask = cv2.threshold(saliency_map * 255, self.saliency_threshold * 255, 255,
|
||
cv2.THRESH_BINARY)
|
||
saliency_mask = saliency_mask.astype(np.uint8)
|
||
|
||
# 形态学操作
|
||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
|
||
closed = cv2.morphologyEx(saliency_mask, cv2.MORPH_CLOSE, kernel)
|
||
|
||
# 查找轮廓
|
||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||
|
||
regions = []
|
||
for contour in contours:
|
||
x, y, w, h = cv2.boundingRect(contour)
|
||
area = w * h
|
||
if area > self.min_text_area * 2 and area < img.shape[0] * img.shape[1] * 0.1:
|
||
regions.append({
|
||
'type': 'saliency',
|
||
'position': (x, y, w, h),
|
||
'confidence': 0.7,
|
||
'contour': contour
|
||
})
|
||
|
||
return regions
|
||
except Exception as e:
|
||
print(f"显著性检测失败: {e}")
|
||
self.has_saliency = False # 标记为不支持,下次使用替代方法
|
||
|
||
# 替代方法:使用亮度变化检测
|
||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||
|
||
# 高斯模糊减少噪声
|
||
blurred = cv2.GaussianBlur(gray, (15, 15), 0)
|
||
|
||
# 计算拉普拉斯算子检测边缘
|
||
laplacian = cv2.Laplacian(blurred, cv2.CV2.CV_64F)
|
||
laplacian = np.uint8(np.absolute(laplacian))
|
||
|
||
# 阈值处理
|
||
_, threshold = cv2.threshold(laplacian, 30, 255, cv2.THRESH_BINARY)
|
||
|
||
# 形态学操作
|
||
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
|
||
closed = cv2.morphologyEx(threshold, cv2.MORPH_CLOSE, kernel)
|
||
|
||
# 查找轮廓
|
||
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||
|
||
regions = []
|
||
for contour in contours:
|
||
x, y, w, h = cv2.boundingRect(contour)
|
||
area = w * h
|
||
if area > self.min_text_area * 2 and area < img.shape[0] * img.shape[1] * 0.1:
|
||
# 计算轮廓的紧致度
|
||
perimeter = cv2.arcLength(contour, True)
|
||
compactness = 4 * np.pi * area / (perimeter * perimeter) if perimeter > 0 else 0
|
||
|
||
# 水印通常具有中等紧致度
|
||
if 0.1 < compactness < 0.9:
|
||
regions.append({
|
||
'type': 'contrast',
|
||
'position': (x, y, w, h),
|
||
'confidence': 0.6,
|
||
'contour': contour
|
||
})
|
||
|
||
return regions |