前言
近期,某院士在清华大学回复关于图片重复问题时,指出实验室数据管理很重要,要引起重视。
恰巧的是,近期一学者同时发表于
Nature
的两篇文章均被指出出现图片重复。
这进一步突显了在学术研究和出版过程中,数据管理的重要性,以及采取必要的措施来避免这种低级错误的发生。
因此这边就尝试搞了一套流程来检测使用图片是否有重复的问题。
这里不探究图片重复的原因(如相同组别、粗心大意、数据管理不善、造假、论文工厂等有可能),而是专注于解决“如何低成本检测预发表文献中可能存在的图片重复问题”。
检测原理
以下代码的原理是通过计算
结构相似性指数(SSIM, Structural Similarity Index)
来评估两张图片的相似度,从而检测它们是否重复或相似。
SSIM 是一种衡量两张图片相似度的指标。与传统的像素差异(例如,均方误差 MSE)相比,SSIM 更加关注图像的结构、亮度、对比度等特征,因此它能够更有效地模拟人眼对图像的感知方式。
-
亮度
:衡量两幅图像的亮度差异(即图像整体亮度)。
-
对比度
:衡量图像中像素值的变化程度,反映图像的局部对比度。
-
结构
:反映两幅图像的结构信息是否一致,比如图像中的物体形状、纹理等。
基本要求
-
会运行 python 代码/脚本;
-
-
图片格式符合以下 ".png", ".jpg", ".jpeg", ".bmp", ".tiff"。
大致流程
-
-
-
代码实现
import cv2
import os
from skimage.metrics import structural_similarity as ssim
def calculate_similarity(image_path1, image_path2):
"""
使用 SSIM 计算两张图片的相似度。
参数:
image_path1 (str): 第一张图片的路径。
image_path2 (str): 第二张图片的路径。
返回:
float: 两张图片的 SSIM 相似度指数(范围 -1 到 1)。
"""
# 检查文件是否存在
if not os.path.exists(image_path1):
raise ValueError(f"未找到文件:{image_path1}")
if not os.path.exists(image_path2):
raise ValueError(f"未找到文件:{image_path2}")
# 读取图片
img1 = cv2.imread(image_path1, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(image_path2, cv2.IMREAD_GRAYSCALE)
# 检查图片是否加载成功
if img1 is None or img2 is None:
raise ValueError("其中一张或两张图片路径无效,或图片无法加载。")
# 如果图片尺寸不同,则调整大小
if img1.shape != img2.shape:
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))
# 计算 SSIM
score, _ = ssim(img1, img2, full=True)
return score
def get_images_from_folder(folder_path):
"""
获取指定文件夹中的所有图片文件路径。
参数:
folder_path (str): 文件夹的路径。
返回:
list: 图片文件路径的列表。
"""
valid_extensions = (".png", ".jpg", ".jpeg", ".bmp", ".tiff") # 支持的图片格式
return [
os.path.join(folder_path, file)
for file in os.listdir(folder_path)
if file.lower().endswith(valid_extensions)
]
if __name__ == "__main__":
# 输入文件夹路径
folder_path = input("请输入图片所在文件夹路径:").strip()
# 检查文件夹是否存在
if not os.path.exists(folder_path):
print(f"文件夹不存在:{folder_path}")
exit(1)
# 获取文件夹中的所有图片
image_paths = get_images_from_folder(folder_path)
# 检查是否有足够的图片
if len(image_paths) 2:
print("文件夹中没有足够的图片进行比较(至少需要两张图片)。")
exit(1)
# 开始计算相似度
print(f"检测到 {len(image_paths)} 张图片,开始相似度检测...\n")
pair_index = 1
results = []
for i in range(len(image_paths)):
for j in range(i + 1, len(image_paths)): # 确保每张图片只与其后面的图片比较
try:
print(f"第 {pair_index} 对:")
print(f" 图片 1: {image_paths[i]}")
print(f" 图片 2: {image_paths[j]}")
# 计算相似度
similarity = calculate_similarity(image_paths[i], image_paths[j])
print(f" SSIM 相似度: {similarity:.4f}\n")
# 保存结果
results.append({
"pair": pair_index,
"image1": image_paths[i],
"image2": image_paths[j],
"similarity": similarity
})
pair_index += 1
except Exception as e:
print(f" 处理该对时出错:{e}\n")
continue
print("相似度检测完成。\n")
# 打印总结
print("结果汇总:")
for result in results:
print(f"第 {result['pair']} 对:")
print(f" 图片 1: {result['image1']}")
print(f" 图片 2: {result['image2']}")
print(f" SSIM 相似度: {result['similarity']:.4f}\n")
测试结果
这是其中一篇文章里面的重复图片。其中在补充图片的图 3 左下角和图 7 右下角出现了图片重复(以下用代号 A 和 C 来表示,其中 B 作为非重复的对照,A_rep 作为 A 的复制)。
-
A 和 A_rep 相似度会非常高,因为是纯粹的复制,他们一模一样;
-
A 和 C,A_rep 和 C,有较高相似度,毕竟我是截图,没有最原始的图片,所以无法做到一模一样;
-
A 和 B,C 和 B,A_rep 和 B,来自不一样的视野,所以他们的相似度应该较低。