文档章节

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

Pulsar-V
 Pulsar-V
发布于 2017/07/24 15:16
字数 1252
阅读 633
收藏 18
点赞 1
评论 1

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;
}

© 著作权归作者所有

共有 人打赏支持
Pulsar-V
粉丝 43
博文 74
码字总数 58982
作品 1
成都
后端工程师
加载中

评论(1)

Stronger飞
Stronger飞
创造性
OpenCV中几何形状识别与测量

经常看到有学习OpenCV不久的人提问,如何识别一些简单的几何形状与它们的颜色,其实通过OpenCV的轮廓发现与几何分析相关的函数,只需不到100行的代码就可以很好的实现这些简单几何形状识别与...

gloomyfish ⋅ 04/16 ⋅ 0

【OpenCV系列】【四】操作像素的三种方式

在opencv中,操作像素的方法有三种,每种的速度不同,可以实际使用时测试(测试方法见【OpenCV系列】【三】计算程序运行时间),各有各的好处。 具体代码如下: 可以看出,后面两种方式,需要...

muqiusangyang ⋅ 04/15 ⋅ 0

图片人脸检测(OpenCV版)

图片人脸检测 人脸检测使用到的技术是OpenCV,上一节已经介绍了OpenCV的环境安装,点击查看. 功能展示 识别一种图上的所有人的脸,并且标出人脸的位置,画出人眼以及嘴的位置,展示效果图如下...

vipstone ⋅ 05/21 ⋅ 0

28局部与分割-图像修补inpaint

28局部与分割-图像修补 inpaint算法的核心在于:提取带修补区域的边界,分别从最外层的边界到最里层的边界,然后依次进行修补。算法的思想如下: 看到这里,就会有疑惑了,怎么确定像素与边缘...

z827997640 ⋅ 04/21 ⋅ 0

视频分析(一):Meanshift均值漂移和Camshift算法来查找和跟踪视频中的对象

目标 在这一章当中, 我们将学习Meanshift和Camshift算法来查找和跟踪视频中的对象。 均值漂移 手段背后的直觉很简单。考虑你有一组点。(它可以是像直方图反投影的像素分布)。您会看到一个...

漫步当下 ⋅ 05/19 ⋅ 0

(三)OpenCV中的图像处理之图像变换及模板匹配

注释:本文翻译自OpenCV3.0.0 document->OpenCV-Python Tutorials,包括对原文档种错误代码的纠正 3.10 OpenCV中的图像变换 第一节:傅里叶变换(Fourier Transform) 1.目标 使用OpenCV查找图...

u014403318 ⋅ 05/30 ⋅ 0

世界上最好的语言PHP:我也可以用OpenCV搞计算机视觉

  选自Medium   作者:Vladimir Goncharov   机器之心编译   参与:Huiyuan Zhuo、思源、刘晓坤      作者 Vladimir Goncharov 平常主要关注与研究两个主题:PHP 和 Server Adm...

机器之心 ⋅ 今天 ⋅ 0

特征检测(二):OpenCV中的SIFT尺度不变特征变化特征检测技术

目标 在这一章当中, 我们将学习SIFT算法的概念 我们将学习如何找到SIFT关键点和描述符。 理论 在最后几章中,我们看到了一些角落探测器,如哈里斯等。它们是旋转不变的,这意味着,即使图像...

漫步当下 ⋅ 05/19 ⋅ 0

tensorflow实现人脸检测及识别(简单版)

本教程主要是对人脸检测及识别python实现系列 及碉堡了!程序员用深度学习写了个老板探测器(付源码) 的实现。主要实现的功能是用网络摄像头自动识别在工位通道走过的人脸,如果确认是老板的...

gavinmiaoc ⋅ 05/28 ⋅ 0

视频分析(二):光流(Optical Flow)

目标 在这一章当中, 我们将使用Lucas-Kanade方法理解光流的概念及其估计。 我们将使用像cv2.calcOpticalFlowPyrLK()这样的函数来跟踪视频中的特征点。 光学流程 光流是由物体或相机的运动...

漫步当下 ⋅ 05/19 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

从方法论到零售客户实践 解码阿里巴巴数据中台——2018上海云栖大会

摘要: 一、数据中台之道 6月8日,上海云栖大会进入了第二天的议程,数据中台专场论坛座无虚席,数据中台总架构师邓中华女士向在场的观众介绍了数据中台的衍生发展之道。 基于OneID、OneData...

阿里云云栖社区 ⋅ 25分钟前 ⋅ 0

Ubuntu部署django问题汇总

使用Anaconda3的Python3.6的pip安装UWSGI报错 原因是gcc版本不兼容,安装4.7并修改gccsudo apt-get install gcc-4.7sudo mv /usr/bin/gcc /usr/bin/gcc.baksudo ln -s /usr/bin/gcc-4.......

wuyaSama ⋅ 28分钟前 ⋅ 0

从方法论到零售客户实践 解码阿里巴巴数据中台——2018上海云栖大会

摘要: 一、数据中台之道 6月8日,上海云栖大会进入了第二天的议程,数据中台专场论坛座无虚席,数据中台总架构师邓中华女士向在场的观众介绍了数据中台的衍生发展之道。 基于OneID、OneData...

猫耳m ⋅ 28分钟前 ⋅ 0

Docker减肥小记

如果经常使用 docker,你会发现 docker 占用的资源膨胀很快,其中最明显也最容易被察 如何快速的清理 docker 占用的系统资源,具体点说就是删除那些无用的镜像、容器、网络和数据卷… 1、查看...

寰宇01 ⋅ 38分钟前 ⋅ 0

微信小程序中如何使用WebSocket实现长连接(含完整源码)

本文由腾讯云技术团队原创,感谢作者的分享。 1、前言 微信小程序提供了一套在微信上运行小程序的解决方案,有比较完整的框架、组件以及 API,在这个平台上面的想象空间很大。腾讯云研究了一...

JackJiang- ⋅ 46分钟前 ⋅ 0

定制库到Maven本地资源库

1.如果只有定制库的JAR文件 下载链接如下:pdf.jar 2.使用命令转换成Maven本地资源 mvn install:install-file -Dfile=/Users/manager/Downloads/clj-pdf-2.2.33.jar -DgroupId=clj-pdf -Dar......

年少爱追梦 ⋅ 51分钟前 ⋅ 0

高仿springmvc之xuchen-mvc

package org.mvc.framework.servlet; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.......

徐志 ⋅ 53分钟前 ⋅ 0

关于自定义URLStreamHandler的一次踩坑

关于自定义URLStreamHandler的一次踩坑 20180625 lambo init 说明 一般自定义实现url的协议解析.方案为实现URLStreamHandler.实现其 openConnection 就可以了, 如果我们执行 new URL("xx://...

林小宝 ⋅ 54分钟前 ⋅ 0

【SM2证书】利用BC的X509v3CertificateBuilder组装X509国密证书

演示证书文件 链接: https://pan.baidu.com/s/1ijHNnMQJj7jzW-jXEVd6Gg 密码: vfva 所需jar包 <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependenc......

小帅帅丶 ⋅ 55分钟前 ⋅ 0

用Calendar 实现 计算 一段时间的毫秒值

Calendar c=Calendar.getInstance();c.add(Calendar.MONTH, -1);int lastMonthMaxDay=c.getActualMaximum(Calendar.DAY_OF_MONTH);c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH)......

岸芷汀兰 ⋅ 58分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部