文档章节

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

Pulsar-V
 Pulsar-V
发布于 2017/07/24 15:16
字数 1252
阅读 674
收藏 18

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

Pulsar-V

粉丝 49
博文 93
码字总数 75455
作品 1
成都
后端工程师
加载中

评论(1)

Stronger飞
Stronger飞
创造性
图像检索的三种python实现(直方图/OpenCV/哈希法)

简介: 本文介绍了图像检索的三种实现方式,均用python完成,其中前两种基于直方图比较,哈希法基于像素分布。 检索方式是:提前导入图片库作为检索范围,给出待检索的图片,将其与图片库中的...

漫步当下
07/09
0
0
OpenCV中几何形状识别与测量

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

gloomyfish
04/16
0
0
【OpenCV入门指南】第七篇 线段检测与圆检测

【OpenCV入门指南】第七篇 线段检测与圆检测 在《【OpenCV入门指南】第五篇轮廓检测上》与《【OpenCV入门指南】第六篇轮廓检测下》讲解了OpenCV的轮廓检测。本篇将讲解在OpenCV中使用线段检测...

andyhe91
2014/12/17
0
0
【OpenCV系列】【四】操作像素的三种方式

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

muqiusangyang
04/15
0
0
基于OpenCV的iOS图像处理

关于图片处理 随着科技的发展,AI、机器学习、AR、VR等已经逐渐走进生活,模式识别、图像捕捉、图片拼接等已经成为其中的重要环节。因此,图像处理技术在未来会被移动端广泛使用。其中,有很...

无忌不悔
2017/09/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

20180920 rzsz传输文件、用户和用户组相关配置文件与管理

利用rz、sz实现Linux与Windows互传文件 [root@centos01 ~]# yum install -y lrzsz # 安装工具sz test.txt # 弹出对话框,传递到选择的路径下rz # 回车后,会从对话框中选择对应的文件传递...

野雪球
今天
2
0
OSChina 周四乱弹 —— 毒蛇当辣条

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 达尔文:分享花澤香菜/前野智昭/小野大輔/井上喜久子的单曲《ミッション! 健?康?第?イチ》 《ミッション! 健?康?第?イチ》- 花澤香菜/前野智...

小小编辑
今天
7
3
java -jar运行内存设置

java -Xms64m #JVM启动时的初始堆大小 -Xmx128m #最大堆大小 -Xmn64m #年轻代的大小,其余的空间是老年代 -XX:MaxMetaspaceSize=128m # -XX:CompressedClassSpaceSize=6...

李玉长
今天
4
0
Spring | 手把手教你SSM最优雅的整合方式

HEY 本节主要内容为:基于Spring从0到1搭建一个web工程,适合初学者,Java初级开发者。欢迎与我交流。 MODULE 新建一个Maven工程。 不论你是什么工具,选这个就可以了,然后next,直至finis...

冯文议
今天
2
0
RxJS的另外四种实现方式(四)——性能最高的库(续)

接上一篇RxJS的另外四种实现方式(三)——性能最高的库 上一篇文章我展示了这个最高性能库的实现方法。下面我介绍一下这个性能提升的秘密。 首先,为了弄清楚Most库究竟为何如此快,我必须借...

一个灰
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部