ImageMagick 图像相似度调研报告

文档声称该改进的算法对于轻度的图像攻击(缩放,旋转[黑色背景],平移[黑色背景]亮度变换,对比度变换,伽马变换,高斯模糊,JPEG压缩,噪声,镜像或转置,水印,弧形畸变,桶形畸变,枕形失真,切向畸变)具有一定的鲁棒性

 

一、ImageMagick中的pHash算法

根据ImageMagick 官方文档的说明,它的相似图像对比算法是来自于《Perceptual Hashing for Color Images Using Invariant Moments》(基于不变矩的彩色图像感知哈希算法),但是是它的改进版本。

主要的不同点在于:

1.如果是彩色图像,原论文使用的彩色空间是 HSI YCbCr,而ImageMagick 使用的是sRGBHCLp(然后每个通道计算Hu矩);如果是灰度图像,只使用一个通道。

2.最后计算相似度距离采用的公式不同,论文采用两幅图像哈希值差的平方和的开方,而ImageMagick采用的是均方根误差(RMSE)。

特点:

1.由于引入了 Hu矩,该算法对缩放、旋转(黑色背景)、平移、翻转具有一定的鲁棒性,由于采用了HCLp彩色空间,加强了对缩放、旋转(黑色背景)、平移、翻转的不敏感性,但增加了对光照、对比度、Gamma变化的敏感性。

2.由于相似度计算使用了均方根误差,所以对于镜像变换具有一定的鲁棒性。

3.由于彩色图像是根据6个通道计算的7维的Hu矩,所有产生的哈希码为6x7=42位,但灰度图像由于只计算一个通道,只有7位的哈希码,所以彩色图像与灰度图像不能直接用哈希码进行计算。

 

二、什么是Hu

Hu 矩是由Hu1962年提出的,归一化的中心矩对于图像的平移、缩放、旋转具有不变性(直接使用普通矩或中心矩不具有不变性)。

p+q阶普通矩的公式为

其中f(x, y)为图像的灰度分布。

p+q阶中心矩的公式为



其中x0 = M10/M00y0=M01/M00

归一化的中心矩的公式为

                                                                                                       

其中 r=(p+q+2)/2,  (p+q = 2, 3, ...)

Hu不变矩是利用二阶和三阶的中心矩构造了七个不变矩,它们在相似图像的条件下可以保持平移、缩放、旋转不变。

定义如下:

 

其中npq(p, q = 0, 1, 2, ...)是归一化的中心矩。

三、测试实验

在相同尺度下实验

A 样本:“有大范围平移+大范围裁剪+大范围水印,没有翻转+旋转”

B 样本:“在没有大范围平移+大范围裁剪+大范围水印,有翻转+旋转”


ImageMaigck

A 样本运行结果

 

B 样本运行结果



我优化的算法

A 样本运行结果


B 样本运行结果



预处理:读取图片 第一步,缩小尺寸。 将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。 第二步,简化色彩。 将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。 第三步,计算平均值。 计算所有64个像素的灰度平均值。 第四步,比较像素的灰度。 将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。 第五步,计算哈希值。 将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。 得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。 你可以将几张图片放在一起,也计算出他们的汉明距离对比,就可以看看两张图片是否相似。 这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。 实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。 以上内容大部分直接从阮一峰的网站上复制过来,想看原著的童鞋可以去在最上面的链接点击进去看。
### 关于C++中实现图像相似度计算 在C++中实现图像相似度计算可以通过多种方法完成,具体取决于需求的复杂程度以及所需的精度。以下是几种常见的方法及其对应的代码示例。 #### 方法一:基于像素匹配的简单算法 这种方法通过逐一对比两幅图像对应位置上的像素值来判断其相似度。此方法适用于简单的二值图(如黑白图像)或者灰度图。 ```cpp #include <iostream> using namespace std; int main() { int m, n; cin >> m >> n; // 输入图像尺寸 int img1[m][n], img2[m][n]; // 输入第一张图像数据 for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { cin >> img1[i][j]; } } // 输入第二张图像数据并同时计算相同像素点数量 int samePixels = 0; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { cin >> img2[i][j]; if (img1[i][j] == img2[i][j]) { samePixels++; } } } double similarity = static_cast<double>(samePixels) / (m * n) * 100.0; cout << fixed << setprecision(2) << similarity << endl; // 输出相似度百分比 return 0; } ``` 这种算法的时间复杂度为 \(O(m \times n)\),其中 \(m\) 和 \(n\) 是图像的高度和宽度[^1]。 --- #### 方法二:基于直方图的相似度计算 对于彩色图像或更复杂的场景,可以利用颜色直方图来进行相似度评估。该方法的核心是比较两张图像的颜色分布差异。 ```cpp #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> #include <cmath> double histogramSimilarity(const cv::Mat& hist1, const cv::Mat& hist2) { double sum = 0.0; for (int i = 0; i < hist1.rows; ++i) { double diff = fabs(hist1.at<float>(i) - hist2.at<float>(i)); sum += diff; } return 1.0 - sum / (hist1.total()); } int main() { cv::Mat image1 = cv::imread("image1.jpg", cv::IMREAD_GRAYSCALE); cv::Mat image2 = cv::imread("image2.jpg", cv::IMREAD_GRAYSCALE); cv::Mat hist1, hist2; int histSize = 256; float range[] = {0, 256}; const float* histRange = {range}; cv::calcHist(&image1, 1, cv::Mat(), hist1, 1, &histSize, &histRange); cv::calcHist(&image2, 1, cv::Mat(), hist2, 1, &histSize, &histRange); double similarity = histogramSimilarity(hist1, hist2); cout << "Histogram Similarity: " << similarity * 100 << "%" << endl; return 0; } ``` 这里使用了 OpenCV 库中的 `cv::calcHist` 函数来提取图像的直方图,并通过比较两者之间的差值得出相似度[^2]。 --- #### 方法三:基于感知哈希(pHash) 感知哈希是一种高级技术,用于生成能够反映图像视觉特征的独特指纹。它通常应用于大规模图像检索系统中。 ```cpp // 假设已有一个函数 generatePhash 计算 pHash 值 unsigned long long phash1 = generatePhash(image1); unsigned long long phash2 = generatePhash(image2); int hammingDistance(unsigned long long hash1, unsigned long long hash2) { unsigned long long xorResult = hash1 ^ hash2; int dist = 0; while (xorResult) { dist += xorResult & 1; xorResult >>= 1; } return dist; } int distance = hammingDistance(phash1, phash2); cout << "Hamming Distance: " << distance << endl; if (distance <= 5) { cout << "Images are similar." << endl; } else { cout << "Images are different." << endl; } ``` 感知哈希的优点在于即使图像经过轻微变换(如旋转、缩放),仍能保持较高的相似性检测能力[^3]。 --- #### 使用第三方库 除了手动编写代码外,还可以借助成熟的开源库简化开发过程: - **OpenCV**: 提供丰富的图像处理功能,支持直方图计算、模板匹配等功能。 - **ImageMagick**: 支持多种图像操作,可通过命令行调用或绑定至 C++ 中。 - **Dlib**: 主要面向计算机视觉领域,提供了一些预训练模型可用于特征提取。 例如,在 OpenCV 中可以直接加载图像并执行各种运算[^4]。 --- ### 总结 以上介绍了三种不同层次的图像相似度计算方法:基础像素级对比适合简单应用场景;直方图分析更适合色彩敏感的任务;而感知哈希则针对鲁棒性和效率进行了优化。开发者应根据实际需求选择合适的方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShaderJoy

您的打赏是我继续写博客的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值