吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2041|回复: 4
收起左侧

[C&C++ 转载] 图像比对-感知哈希算法

  [复制链接]
DayBreak 发表于 2021-11-24 11:08
本帖最后由 DayBreak 于 2021-11-24 11:15 编辑

感知哈希算法是一类哈希算法的总称,其作用在于生成每张图像的“指纹”(fingerprint)字符串,比较不同图像的指纹信息来判断图像的相似性。结果越接近图像越相似。感知哈希算法包括均值哈希(aHash)、感知哈希(pHash)和dHash(差异值哈希)。

aHash速度较快,但精确度较低;pHash则反其道而行之,精确度较高但速度较慢;dHash兼顾二者,精确度较高且速度较快。

在得到64位hash值后,使用汉明距离量化两张图像的相似性。汉明距离越大,图像的相似度越小,汉明距离越小,图像的相似度越大。
汉明距离是使用在数据传输差错控制编码里面的,汉明距离是一个概念,它表示两个(相同长度)字对应位不同的数量,我们以d(x,y)表示两个字x,y之间的汉明距离。对两个字符串进行异或运算,并统计结果为1的个数,那么这个数就是汉明距离。例如:
1011101与1001001之间的汉明距离是2。
2143896与2233796之间的汉明距离是3。
"toned"与"roses"之间的汉明距离是3。
aHash
a)  缩放图片:为了保留图像的结构,降低图像的信息量,需要去掉细节、大小和横纵比的差异,建议把图片统一缩放到8*8,共64个像素的图片;
b)  转化为灰度图:把缩放后的图片转化为256阶的灰度图;

灰度图相关算法(R = red, G = green, B = blue)
对于彩色转灰度,其基础的心理学公式为: Gray = R0.299 + G0.587 + B0.114,部分变种也很流行:
i. 浮点算法:Gray=R0.3+G0.59+B0.11
ii. 整数方法:Gray=(R30+G59+B11)/100
iii. 移位方法:Gray =(R76+G151+B28)>>8;
iv. 平均值法:Gray=(R+G+B)/3;
v. 仅取绿色:Gray=G;



c)  计算平均值: 计算进行灰度处理后图片的所有像素点的平均值;
d)  比较像素灰度值:遍历灰度图片每一个像素,如果大于平均值记录为1,否则为0;
e)  构造hash值:组合64个bit位生成hash值,顺序随意但前后保持一致性即可;
f)  对比指纹:计算两幅图片的指纹,计算汉明距离。

pHash感知哈希算法可以获得更精确的结果,它采用的是DCT(离散余弦变换)来降低频率。
a)  缩小尺寸
为了简化了DCT的计算,pHash以小图片开始(建议图片大于8x8,32x32)。
b)  简化色彩
与aHash相同,需要将图片转化成灰度图像,进一步简化计算量(具体算法见aHash算法步骤)。
c)  计算DCT
DCT是把图片分解频率聚集和梯状形。这里以32x32的图片为例。DCT变换的全称是离散余弦变换(Discrete Cosine Transform),主要用于将数据或图像的压缩,能够将空域的信号转换到频域上,具有良好的去相关性的性能。DCT变换本身是无损的,但是在图像编码等领域给接下来的量化、哈弗曼编码等创造了很好的条件,同时,由于DCT变换时对称的,所以,我们可以在量化编码后利用DCT反变换,在接收端恢复原始的图像信息。对原始图像进行离散余弦变换,变换后DCT系数能量主要集中在左上角,其余大部分系数接近于零,DCT具有适用于图像压缩的特性。将变换后的DCT系数进行门限操作,将小于一定值得系数归零,这就是图像压缩中的量化过程,然后进行逆DCT运算,可以得到压缩后的图像。
离散余弦变换的原理:
一维DCT变换:


1234.png
[Asm] 纯文本查看 复制代码
int pHash(Mat matSrc1, Mat matSrc2)
{
        Mat matDst1, matDst2;
        cv::resize(matSrc1, matDst1, cv::Size(32, 32), 0, 0, cv::INTER_CUBIC);
        cv::resize(matSrc2, matDst2, cv::Size(32, 32), 0, 0, cv::INTER_CUBIC);

        cv::cvtColor(matDst1, matDst1, CV_BGR2GRAY);
        cv::cvtColor(matDst2, matDst2, CV_BGR2GRAY);

        matDst1.convertTo(matDst1, CV_32F);
        matDst2.convertTo(matDst2, CV_32F);
        dct(matDst1, matDst1);
        dct(matDst2, matDst2);

        int iAvg1 = 0, iAvg2 = 0;
        int arr1[64], arr2[64];

        for (int i = 0; i < 8; i++)
        {
                uchar* data1 = matDst1.ptr<uchar>(i);
                uchar* data2 = matDst2.ptr<uchar>(i);

                int tmp = i * 8;

                for (int j = 0; j < 8; j++)
                {
                        int tmp1 = tmp + j;

                        arr1[tmp1] = data1[j];
                        arr2[tmp1] = data2[j];

                        iAvg1 += arr1[tmp1];
                        iAvg2 += arr2[tmp1];
                }
        }

        iAvg1 /= 64;
        iAvg2 /= 64;

        for (int i = 0; i < 64; i++)
        {
                arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
                arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
        }

        int iDiffNum = 0;

        for (int i = 0; i < 64; i++)
                if (arr1[i] != arr2[i])
                        ++iDiffNum;

        return iDiffNum;
}

[Asm] 纯文本查看 复制代码
int aHash(Mat matSrc1, Mat matSrc2)
{
        Mat matDst1, matDst2;
        cv::resize(matSrc1, matDst1, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);
        cv::resize(matSrc2, matDst2, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);

        cv::cvtColor(matDst1, matDst1, CV_BGR2GRAY);
        cv::cvtColor(matDst2, matDst2, CV_BGR2GRAY);

        int iAvg1 = 0, iAvg2 = 0;
        int arr1[64], arr2[64];

        for (int i = 0; i < 8; i++)
        {
                uchar* data1 = matDst1.ptr<uchar>(i);
                uchar* data2 = matDst2.ptr<uchar>(i);

                int tmp = i * 8;

                for (int j = 0; j < 8; j++)
                {
                        int tmp1 = tmp + j;

                        arr1[tmp1] = data1[j] / 4 * 4;
                        arr2[tmp1] = data2[j] / 4 * 4;

                        iAvg1 += arr1[tmp1];
                        iAvg2 += arr2[tmp1];
                }
        }

        iAvg1 /= 64;
        iAvg2 /= 64;

        for (int i = 0; i < 64; i++)
        {
                arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
                arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
        }

        int iDiffNum = 0;

        for (int i = 0; i < 64; i++)
                if (arr1[i] != arr2[i])
                        ++iDiffNum;

        return iDiffNum;
}



给点免费的爱心,谢谢大家

免费评分

参与人数 2热心值 +2 收起 理由
guyinqian + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
fanghui + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Charlie2018 发表于 2021-11-24 11:35
有没有大佬打包成软件
头像被屏蔽
细水流长 发表于 2021-11-24 11:21
似水流年小小 发表于 2021-11-24 13:03
细水流长 发表于 2021-11-24 11:21
https://www.jianshu.com/p/ad7131f7999b
https://www.cnblogs.com/P3nguin/p/7860355.html

666  大神怎么找到这俩帖子的
小小孟 发表于 2021-11-24 15:23
禁止求评分、诱导评分、互刷评分、互刷悬赏值,违规者封号处理。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 11:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表