• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

图像比对-感知哈希算法

武飞扬头像
飞天的大鹅
帮助1

感知哈希算法是一类哈希算法的总称,其作用在于生成每张图像的“指纹”(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变换:

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;
}
学新通
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;
}
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgahffg
系列文章
更多 icon
同类精品
更多 icon
继续加载