zoukankan      html  css  js  c++  java
  • 感知哈希算法

    感知哈希算法(以下简称PHA)是哈希算法的一类,主要用来做相似图片的搜索工作。图片所包含的特征被用来生成一组指纹(不过它不是唯一的),而这些指纹是可以进行比较的。

    【原理】

    下面是简单的步骤,来说明对图像进行PHA的运算过程  :

    第一步,缩小尺寸。

        ​最快速的去除高频和细节,只保留结构明暗的方法就是缩小尺寸。将图片缩小到8x8的尺寸,总共64个像素。摒弃不同尺寸、比例带来的图片差异。

    第二步,简化色彩。

        ​将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

    第三步,计算DCT(离散余弦变换)。

        ​DCT是把图片分解频率聚集和梯状形,虽然JPEG使用8*8的DCT变换,在这里使用32*32的DCT变换。

    第四步,缩小DCT。

        ​虽然DCT的结果是32*32大小的矩阵,但我们只要保留左上角的8*8的矩阵,这部分呈现了图片中的最低频率。

    第五步,计算平均值。

        ​计算所有64个值的平均值。

    第六步,进一步减小DCT。

        ​这是最主要的一步,根据8*8的DCT矩阵,设置0或1的64位的hash值,大于等于DCT均值的设为”1”,小于DCT均值的设为“0”。结果并不能告诉我们真实性的低频率,只能粗略地告诉我们相对于平均值频率的相对比例。只要图片的整体结构保持不变,hash结果值就不变。能够避免伽马校正或颜色直方图被调整带来的影响。

    第七步,计算哈希值。

        ​将64bit设置成64位的长整型,组合的次序并不重要,只要保证所有图片都采用同样次序就行了。将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了(例如,自左到右、自顶向下、big-endian)。

        ​得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算“汉明距离”(Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

    ​【c++代码实现】

    #include "stdafx.h"
    #include <opencv2/opencv.hpp>
    #include <iostream>
    
    using namespace std;
    using namespace cv;
    //根据图片生成64位hash码
    int CalcImagePerceptualHashKey(InputArray input)
    {
        Mat _input = input.getMat();
        Mat pTheImage88=Mat::zeros(Size(8, 8), _input.channels());
        Mat pGrayscaleImage = Mat::zeros(Size(8, 8), 1);
        //将原图处理成8*8的图片
        resize(_input, pTheImage88, Size(8, 8));
        //cvtColor(pTheImage8x8, pGrayscaleImage);
        cvtColor(pTheImage88, pGrayscaleImage, COLOR_RGB2GRAY);
        pTheImage88.release();
    
        //计算平均值
        float ElementMean = 0;
        for (size_t y = 0; y < 8; y++)
        {
            for (size_t x = 0; x < 8; x++)
            {
                unsigned char elemet = pGrayscaleImage.at<unsigned char>(x, y);
                ElementMean += elemet;
            }
        }
        ElementMean= ElementMean / 64;
        //得到hash值
        int64 HashKey = 0;
    
        for (size_t y = 0; y < 8; y++)
        {
            for (size_t x = 0; x < 8; x++)
            {
                unsigned char elemet = pGrayscaleImage.at<unsigned char>(x, y);
                if (elemet > ElementMean)
                {
                    //向左移一位
                    HashKey <<= 1; 
                }
                else 
                {
                    //向左移一位
                    HashKey <<= 1;
                    //最后一位复制为1
                    HashKey |= 1;//相当于HashKey =HashKey | 1
                }
            }
        }
        return HashKey;
    }
    //指纹hash码比对
    float CompareImageSimilarity(int64 key1, int64 key2)
    {
        //两组hash码对比
        int64 result = key1^key2;
        int count = 0;
        int i = 64;
        while (i--)
        {
            //判断最后一位是否为1,即是否相同
            if ((result & 1) == 1)
                count++;
            //右移一位,进入下一位
            result >>= 1;
        }
        return count == 0 ? 1 : (64 - count) / (float)64;
    }
    
    int main()
    {
        Mat img1 = imread("1.jpg");
        Mat img2 = imread("2.jpg");
    
        int64 key1 = CalcImagePerceptualHashKey(img1);
        int64 key2 = CalcImagePerceptualHashKey(img2);
    
        float lv = CompareImageSimilarity(key1, key2);
    
        cout << "匹配度:" << lv << endl;
        waitKey(2000);
        system("pause");
        return 0;
    }
    View Code

    公总号:

  • 相关阅读:
    ajax工作原理
    ajax 和xmlHttpRequest区别
    ajax 基本语法
    javascript 中XMLHttpRequest 实现前台向后台的交互
    Javascript 中ajax实现前台向后台交互
    javascript 中函数eval()
    两道有趣的面试题
    linux 中的快捷键
    linux awk命令详解
    linux sed命令详解
  • 原文地址:https://www.cnblogs.com/raorao1994/p/9108345.html
Copyright © 2011-2022 走看看