当前位置: 首页 > news >正文

OpenCV图像哈希计算及汉明距离的计算

OpenCV均值哈希与感知哈希计算,比对图像相似度,当计算出来的汉明距离越大,图像的相似度越小,汉明距离越小,图像的相似度越大,这种没有基于特征点的图像比对用在快速搜索引擎当中可以有效的进行图像搜索.

离散傅里叶变换的推导 具体代码和OpenCV代码请移步到博客

输入图片说明

下面附上Mathmetica代码

设X (n) 是一个长度为M的有限长序列,则定义X (n) 的N点离散傅里叶变换为

X (k) = DFT[x (n)] = 
\!\(\*UnderscriptBox[
OverscriptBox[\(\[Sum]\), \(N - 1\)], \(K = 0\)]\) 
   x (n) Subscript[W, N]^kn , k = 0, 1, ..., N - 1
X (k) 的傅里叶逆变换为
x (n) = IDFT[X (k)] = 
\!\(\*UnderscriptBox[
OverscriptBox[\(\[Sum]\), \(N - 1\)], \(k = 0\)]\)X (k) Subscript[
    W^-kn, N], k = 0, 1, 2, 3, 4, ...., N - 1
式中, Subscript[W, N] = 
 e^(-j*2 \[Pi]/N) N称为DFT变换区间长度,N \[GreaterSlantEqual] 
 M通常称 (1) 式和 (2) 式为离散傅里叶变换对。
下面来证明IDFT[X (k)] 的唯一性
把 (1) 代入 (2) 有
IDFT[X (k)] = (1/N) 
\!\(\*UnderscriptBox[
OverscriptBox[\(\[Sum]\), \(N - 1\)], \(k = 0\)]\)[
\!\(\*UnderscriptBox[
OverscriptBox[\(\[Sum]\), \(N - 1\)], \(m = 0\)]\) 
       x (m) Subscript[W^mk, N]] Subscript[W^-kn, N] =
  
\!\(\*UnderscriptBox[
OverscriptBox[\(\[Sum]\), \(N - 1\)], \(m = 0\)]\)x (m) (1/N) 
\!\(\*UnderscriptBox[
OverscriptBox[\(\[Sum]\), \(N - 1\)], \(k = 0\)]\)Subscript[W^(
     k (m - n)), N]
(1/N) 
\!\(\*UnderscriptBox[
OverscriptBox[\(\[Sum]\), \(N - 1\)], \(k = 0\)]\)Subscript[W^(
   k (m - n)), N] = { 
\!\(\*OverscriptBox[
UnderscriptBox[\(\[Placeholder]\), \(0\ \ \ \ \ \ \ \ \ \ \ \ \ \ m \
\[NotEqual] n + MN, M为整数\)], \(1\ \ \ \ \ \ \ \ \ \ \ \ \ m = n + MN, 
     M为整数\)]\)  
    所以,在变换区间上满足下式
     IDFT[X (k)] = x (n), 0 \[LessSlantEqual] n \[LessSlantEqual] N - 1
      (2) 式定义的离散傅里叶变换是唯一的。

感知哈希

string p_hashCode(Mat src) {
    //第一步,转换颜色空间,简化图像像素
    Mat img, dst;//初始化矩阵IO
    string rst(64, '\0');//初始化哈希值
    double dIdex[64];//初始化矩阵列表
    double mean = 0.0;//初始化均值
    int k = 0;//初始化矩阵行列计数
    //判断图像空间,当图像空间为3位空间的时候转换图像空间为灰度矩阵
    if (src.channels() == 3) {
        cvtColor(src, src, CV_BGR2GRAY);
        img = Mat_<double>(src);
    } else {
        img = Mat_<double>(src);
    }

    // 第二步,缩放尺寸 
    //这里将整个图像缩放到变成一个8*8的图像矩阵,汉明长度为8*8=64个字节长度
    //最快速的去除高频和细节,只保留结构明暗的方法就是缩小尺寸。
    //将图片缩小到8x8的尺寸,总共64个像素。摒弃不同尺寸、比例带来的图片差异。
    resize(img, img, Size(8, 8));

    // 第三步,离散余弦变换,DCT系数求取
    //离散余弦变换(DCT for Discrete Cosine Transform)是与傅里叶变换相关的一种变换      
    //它类似于离散傅里叶变换(DFT for Discrete Fourier Transform),但是只使用实数
    dct(img, dst);

    /* 第四步,求取DCT系数均值(左上角8*8区块的DCT系数)*/
    for (int i = 0; i < 8; ++i) {//迭代矩阵行
        for (int j = 0; j < 8; ++j) {//迭代矩阵列
            //第i行j列的图像灰度值
            dIdex[k] = dst.at<double>(i, j);
            //计算均值,此均值相对于8*8矩阵的总像素点的均值
            mean += dst.at<double>(i, j) / 64;
            k++;
        }
    }

    // 第五步,计算哈希值
    //遍历像素矩阵,当矩阵的灰度值大于均值的时候哈希为1,当矩阵的灰度值小于均值     
    //的时候哈希为2
    for (int i = 0; i < 64; ++i) {
        if (dIdex[i] >= mean) {
            rst[i] = '1';
        } else {
            rst[i] = '0';
        }
    }
    return rst;
}

均值哈希计算

string a_hashCode(Mat src) {
    string rst(64, '\0');
    Mat img;
    if (src.channels() == 3)
        cvtColor(src, img, CV_BGR2GRAY);
    else
        img = src.clone();
     //第一步,缩小尺寸。
     //将图片缩小到8x8的尺寸,总共64个像素
    resize(img, img, Size(8, 8));
    /* 第二步,简化色彩(Color Reduce)。
       将缩小后的图片,转为64级灰度。*/
    uchar *pData;
    for (int i = 0; i < img.rows; i++) {
        //取出矩阵每一行的数据
        pData = img.ptr<uchar>(i);
        for (int j = 0; j < img.cols; j++) {
            //将矩阵每一列的数据除以4
            pData[j] = pData[j] / 4;
        }
    }
    //第三步,计算平均值。
    //计算所有64个像素的灰度平均值.
    int average = mean(img).val[0];
    //第四步,比较像素的灰度。
    //将每个像素的灰度,与平均值进行比较。大于或等于平均值记为1,小于平均值记为0 
    Mat mask = (img >= (uchar) average);
    //第五步,计算哈希值
    int index = 0;
    for (int i = 0; i < mask.rows; i++) {
        pData = mask.ptr<uchar>(i);
        for (int j = 0; j < mask.cols; j++) {
            if (pData[j] == 0)
                rst[index++] = '0';
            else
                rst[index++] = '1';
        }
    }
    return rst;
}

计算汉明距离

/**
汉明距离函数取哈希字符串进行比对,两字符串长度必须相等才能计算准确的距离
*/
int HanmingDistance(string &str1, string &str2) {
    //判断当两个字符串的长度是否相等
    if ((str1.size() != 64) || (str2.size() != 64))
        return -1;
    int difference = 0;
    //遍历字符串比较两个字符串的0与1的不相同的地方,不相同一次就长度增加1从而计   
    //算总距离
    for (int i = 0; i < 64; i++) {
        if (str1[i] != str2[i])
            difference++;
    }
    return difference;
}

相关文章:

  • 【译Py】2018年8月,GitHub上的Python数据科学明星项目:自动化机器学习、自然语言处理、可视化、机器学习工作流...
  • ElasticSearch(九):springboot项目集成消息中间件activeMQ
  • BZOJ2157旅游——树链剖分+线段树
  • linux中快速清空文件内容的几种方法
  • JS中的继承
  • MyBatis拦截器原理探究
  • 关于电脑使用习惯的若干看法
  • Docker与Tomcat:去掉项目名称进行访问
  • ab压力测试工具的简单使用
  • 一个开发两年的程序员面试总结
  • sigmoid函数求导
  • rhel7 IP地址配置,DNS配置,NetworkManager查看
  • Nosql介绍
  • UESTC - 1999 也许这是唯一能阻止乐爷AK的方法( Just for Fun )(回文树)
  • 语音和面部识别技术能帮助AI在情商上超越人类吗
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • CODING 缺陷管理功能正式开始公测
  • JS题目及答案整理
  • react 代码优化(一) ——事件处理
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • 从0到1:PostCSS 插件开发最佳实践
  • 二维平面内的碰撞检测【一】
  • 仿天猫超市收藏抛物线动画工具库
  • 前端面试之闭包
  • 区块链将重新定义世界
  • 实现简单的正则表达式引擎
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 无服务器化是企业 IT 架构的未来吗?
  • Spring第一个helloWorld
  • ​低代码平台的核心价值与优势
  • # .NET Framework中使用命名管道进行进程间通信
  • # Java NIO(一)FileChannel
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (0)Nginx 功能特性
  • (Oracle)SQL优化技巧(一):分页查询
  • (ZT)出版业改革:该死的死,该生的生
  • (待修改)PyG安装步骤
  • (简单) HDU 2612 Find a way,BFS。
  • (六)激光线扫描-三维重建
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (四) 虚拟摄像头vivi体验
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (译) 函数式 JS #1:简介
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .chm格式文件如何阅读
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .net core 依赖注入的基本用发
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .Net MVC4 上传大文件,并保存表单