翻拍图像检测(即拍摄屏幕的照片)功能实现思路
Claude Sonnet 4
根据搜索结果和翻拍图像的特征,我来为你提供识别翻拍照片的思路和Python代码实现。
识别思路
翻拍照片(拍摄屏幕的照片)通常具有以下可识别特征:
- 摩尔纹检测 - 相机传感器与屏幕像素栅格的干涉模式
- 频域分析 - 屏幕刷新频率在频谱中的特征
- 亮度均匀性 - 屏幕边缘通常较暗,中心较亮
- 色彩分布异常 - 屏幕显示的色彩特征
- 边缘检测 - 可能存在屏幕边框
- 噪声模式分析 - 电子噪声vs自然光学噪声
Python代码实现
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage
from sklearn.ensemble import RandomForestClassifier
from skimage import feature, filters, measure
import warnings
warnings.filterwarnings('ignore')
class RecaptureDetector:def __init__(self):"""初始化翻拍图像检测器创建随机森林分类器(100棵树,固定随机种子)"""self.classifier = RandomForestClassifier(n_estimators=100, random_state=42)def extract_moire_features(self, image):"""提取摩尔纹特征(检测周期性图案)输入:image: BGR格式的原始图像 (numpy array)输出:moire_scores: 数组,包含不同角度和频率的Gabor滤波器响应标准差(36个特征值:12个角度×3个频率)功能:1. 将图像转为灰度图2. 使用Gabor滤波器在12个角度(0°-150°,步长30°)和3个频率(0.1,0.2,0.3)上检测3. 对每个滤波器输出计算标准差作为特征4. 返回所有标准差组成的数组"""gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 使用不同尺度的Gabor滤波器检测周期性模式moire_scores = []for theta in range(0, 180, 30): # 不同角度for frequency in [0.1, 0.2, 0.3]: # 不同频率kernel = cv2.getGaborKernel((21, 21), 3, np.radians(theta), 2*np.pi*frequency, 0.5, 0, ktype=cv2.CV_32F)filtered = cv2.filter2D(gray, cv2.CV_8UC3, kernel)moire_scores.append(np.std(filtered))return np.array(moire_scores)def extract_frequency_features(self, image):"""提取频域特征(分析图像频率分布)输入:image: BGR格式的原始图像 (numpy array)输出:freq_features: 数组,包含20个频率区间内的平均能量(20个特征值:从1到20的频率区间)功能:1. 将图像转为灰度图2. 计算2D傅里叶变换并移频3. 构建径向距离矩阵4. 计算每个频率环(半径1-20)内的平均能量5. 返回能量值组成的数组"""gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# FFT变换f_transform = np.fft.fft2(gray)f_shift = np.fft.fftshift(f_transform)magnitude_spectrum = np.abs(f_shift)# 计算径向功率谱h, w = magnitude_spectrum.shapecenter = (h//2, w//2)# 创建径向距离矩阵y, x = np.ogrid[:h, :w]r = np.sqrt((x - center[1])**2 + (y - center[0])**2)# 计算不同频率的能量freq_features = []for i in range(1, 20):mask = (r >= i) & (r < i+1)if np.sum(mask) > 0:freq_features.append(np.mean(magnitude_spectrum[mask]))else:freq_features.append(0)return np.array(freq_features)def extract_brightness_uniformity(self, image):"""提取亮度均匀性特征(分析亮度分布)输入:image: BGR格式的原始图像 (numpy array)输出:brightness_features: 包含3个特征的数组[中心亮度/边缘平均亮度比, 边缘亮度方差, 中心区域平均亮度]功能:1. 将图像转为灰度图2. 分割图像为中心区域和四个边缘区域3. 计算中心区域平均亮度和边缘区域平均亮度4. 计算中心与边缘的亮度比例5. 计算边缘亮度的方差6. 返回特征数组"""gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)h, w = gray.shape# 分析不同区域的亮度center_region = gray[h//4:3*h//4, w//4:3*w//4]edge_regions = [gray[:h//4, :], # 顶部gray[3*h//4:, :], # 底部gray[:, :w//4], # 左侧gray[:, 3*w//4:] # 右侧]center_brightness = np.mean(center_region)edge_brightness = [np.mean(region) for region in edge_regions]# 计算中心与边缘的亮度差异brightness_ratio = center_brightness / (np.mean(edge_brightness) + 1e-6)brightness_variance = np.var(edge_brightness)return np.array([brightness_ratio, brightness_variance, center_brightness])def extract_color_features(self, image):"""提取色彩特征(分析颜色分布)输入:image: BGR格式的原始图像 (numpy array)输出:color_features: 包含24个特征的数组[HSV: H均值/标准差/25%分位数/75%分位数 × 3, LAB: L均值/标准差 × 3]功能:1. 将图像转为HSV和LAB色彩空间2. 对每个通道计算4个统计特征(均值、标准差、25%分位数、75%分位数)3. 对HSV的3个通道和LAB的3个通道分别提取4. 返回所有特征组成的数组"""# 转换到不同色彩空间hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)# HSV统计特征hsv_features = []for i in range(3):hsv_features.extend([np.mean(hsv[:,:,i]),np.std(hsv[:,:,i]),np.percentile(hsv[:,:,i], 25),np.percentile(hsv[:,:,i], 75)])# LAB色彩空间特征lab_features = []for i in range(3):lab_features.extend([np.mean(lab[:,:,i]),np.std(lab[:,:,i])])return np.array(hsv_features + lab_features)def extract_edge_features(self, image):"""提取边缘特征(检测屏幕边框)输入:image: BGR格式的原始图像 (numpy array)输出:edge_features: 包含5个特征的数组[检测到的直线总数, 水平线数量, 垂直线数量, 边缘密度]功能:1. 将图像转为灰度图2. 应用Canny边缘检测3. 使用霍夫变换检测直线4. 统计水平线和垂直线数量5. 计算边缘像素占总像素的比例6. 返回特征数组"""gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# Canny边缘检测edges = cv2.Canny(gray, 50, 150)# 检测直线(可能的屏幕边框)lines = cv2.HoughLines(edges, 1, np.pi/180, threshold=100)if lines is not None:# 统计水平和垂直线条horizontal_lines = 0vertical_lines = 0for rho, theta in lines[:, 0]:if abs(theta) < np.pi/6 or abs(theta - np.pi) < np.pi/6: # 水平线horizontal_lines += 1elif abs(theta - np.pi/2) < np.pi/6: # 垂直线vertical_lines += 1edge_features = [len(lines), horizontal_lines, vertical_lines]else:edge_features = [0, 0, 0]# 边缘密度edge_density = np.sum(edges) / (edges.shape[0] * edges.shape[1])edge_features.append(edge_density)return np.array(edge_features)def extract_noise_features(self, image):"""提取噪声特征(分析图像噪声模式)输入:image: BGR格式的原始图像 (numpy array)输出:noise_features: 包含8个特征的数组[噪声标准差, 噪声绝对均值, 95%分位数, 噪声方差, 局部方差均值, 局部方差标准差]功能:1. 将图像转为灰度图并转为浮点型2. 用高斯滤波估计噪声(原图-平滑图)3. 计算噪声的统计特征4. 用局部均值滤波计算局部方差5. 返回噪声特征数组"""gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY).astype(np.float32)# 使用高斯滤波器估计噪声blurred = cv2.GaussianBlur(gray, (5, 5), 1.0)noise = gray - blurred# 噪声统计特征noise_features = [np.std(noise),np.mean(np.abs(noise)),np.percentile(np.abs(noise), 95),np.var(noise)]# 局部方差分析kernel = np.ones((5, 5), np.float32) / 25local_mean = cv2.filter2D(gray, -1, kernel)local_variance = cv2.filter2D((gray - local_mean)**2, -1, kernel)noise_features.extend([np.mean(local_variance),np.std(local_variance)])return np.array(noise_features)def extract_all_features(self, image):"""提取所有特征(整合所有特征提取器)输入:image: BGR格式的原始图像 (numpy array)输出:features: 包含所有特征的数组(36+20+3+24+5+8 = 96个特征)功能:1. 缩放图像到最大边800像素以内(加速处理)2. 依次调用所有特征提取函数3. 将所有特征拼接成一个长数组4. 异常处理:特征提取失败时返回None