opencv3/C++ PHash算法图像检索详解

PHash算法即感知哈希算法/Perceptual Hash algorithm,计算基于低频的均值哈希.对每张图像生成一个指纹字符串,通过对该字符串比较可以判断图像间的相似度.

PHash算法原理

将图像转为灰度图,然后将图片大小调整为32*32像素并通过DCT变换,取左上角的8*8像素区域。然后计算这64个像素的灰度值的均值。将每个像素的灰度值与均值对比,大于均值记为1,小于均值记为0,得到64位哈希值。

PHash算法实现

将图片转为灰度值

将图片尺寸缩小为32*32

resize(src, src, Size(32, 32));

DCT变换

 Mat srcDCT;
 dct(src, srcDCT);

计算DCT左上角8*8像素区域均值,求hash值

 double sum = 0;
 for (int i = 0; i < 8; i++)
  for (int j = 0; j < 8; j++)
   sum += srcDCT.at<float>(i,j);

 double average = sum/64;
 Mat phashcode= Mat::zeros(Size(8, 8), CV_8U);
 for (int i = 0; i < 8; i++)
  for (int j = 0; j < 8; j++)
   phashcode.at<char>(i,j) = srcDCT.at<float>(i,j) > average ? 1:0;

hash值匹配

  int d = 0;
  for (int n = 0; n < srchash.size[1]; n++)
   if (srchash.at<uchar>(0,n) != dsthash.at<uchar>(0,n)) d++; 

即,计算两幅图哈希值之间的汉明距离,汉明距离越大,两图片越不相似。

OpenCV实现

如图在下图中对比各个图像与图person.jpg的汉明距离,以此衡量两图之间的额相似度。

#include <iostream>
#include <stdio.h>
#include <fstream>
#include <io.h>
#include <string>
#include <opencv2\opencv.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\core\mat.hpp>
using namespace std;
using namespace cv;
int fingerprint(Mat src, Mat* hash);

int main()
{
 Mat src = imread("E:\\image\\image\\image\\person.jpg", 0);
 if(src.empty())
 {
  cout << "the image is not exist" << endl;
  return -1;
 }
 Mat srchash, dsthash;
 fingerprint(src, &srchash);
 for(int i = 1; i <= 8; i++)
 {
  string path0 = "E:\\image\\image\\image\\person";
  string number;
  stringstream ss;
  ss << i;
  ss >> number;
  string path = "E:\\image\\image\\image\\person" + number +".jpg";
  Mat dst = imread(path, 0);
  if(dst.empty())
  {
   cout << "the image is not exist" << endl;
   return -1;
  }
  fingerprint(dst, &dsthash);
  int d = 0;
  for (int n = 0; n < srchash.size[1]; n++)
   if (srchash.at<uchar>(0,n) != dsthash.at<uchar>(0,n)) d++; 

  cout <<"person" << i <<" distance= " <<d<<"\n";
 }

 system("pause");
 return 0;
}

int fingerprint(Mat src, Mat* hash)
{
 resize(src, src, Size(32, 32));
 src.convertTo(src, CV_32F);
 Mat srcDCT;
 dct(src, srcDCT);
 srcDCT = abs(srcDCT);
 double sum = 0;
 for (int i = 0; i < 8; i++)
  for (int j = 0; j < 8; j++)
   sum += srcDCT.at<float>(i,j);

 double average = sum/64;
 Mat phashcode= Mat::zeros(Size(8, 8), CV_8U);
 for (int i = 0; i < 8; i++)
  for (int j = 0; j < 8; j++)
   phashcode.at<char>(i,j) = srcDCT.at<float>(i,j) > average ? 1:0;

 *hash = phashcode.reshape(0,1).clone();
 return 0;
}

输出汉明距离:

可以看出若将阈值设置为20则可将后三张其他图片筛选掉。

以上这篇opencv3/C++ PHash算法图像检索详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • opencv3/C++ 使用Tracker实现简单目标跟踪

    简介 MIL: TrackerMIL 以在线方式训练分类器将对象与背景分离;多实例学习避免鲁棒跟踪的漂移问题. OLB: TrackerBoosting 基于AdaBoost算法的在线实时对象跟踪.分类器在更新步骤中使用周围背景作为反例以避免漂移问题. MedianFlow: TrackerMedianFlow 跟踪器适用于非常平滑和可预测的运动,物体在整个序列中可见. TLD: TrackerTLD 将长期跟踪任务分解为跟踪,学习和检测.跟踪器在帧之间跟踪对象.探测器本地化所观察到的所有外观,

  • opencv3/Python 稠密光流calcOpticalFlowFarneback详解

    光流是由物体或相机的运动引起的图像对象在两个连续帧之间的视在运动模式.光流方法计算在t和 t+Δtt+Δt时刻拍摄的两个图像帧之间的每个像素的运动位置.这些方法被称为差分,因为它们基于图像信号的局部泰勒级数近似; 也就是说,它们使用关于空间和时间坐标的偏导数. 和稀疏光流相比,稠密光流不仅仅是选取图像中的某些特征点(一般用角点)进行计算;而是对图像进行逐点匹配,计算所有点的偏移量,得到光流场,从而进行配准.因此其计算量会显著大于稀疏光流,但效果一般优于稀疏光流. 函数: def calcOpti

  • opencv3/C++实现光流点追踪

    光流金字塔 calcOpticalFlowPyrLK()函数参数说明: void calcOpticalFlowPyrLK( InputArray prevImg, //第一个8位输入图像或者通过 buildOpticalFlowPyramid()建立的金字塔 InputArray nextImg,//第二个输入图像或者和prevImg相同尺寸和类型的金字塔 InputArray prevPts, //二维点向量存储找到的光流:点坐标必须是单精度浮点数 InputOutputArray next

  • opencv3/C++ HOG特征提取方式

    HOG特征 HOG(Histograms of Oriented Gradients)梯度方向直方图 通过利用梯度信息能反映图像目标的边缘信息并通过局部梯度的大小将图像局部的外观和形状特征化.在论文Histograms of Oriented Gradients for Human Detection中被提出. HOG特征的提取过程为: Gamma归一化: 计算梯度: 划分cell 组合成block,统计block直方图: 梯度直方图归一化: 收集HOG特征. Gamma归一化: 对图像颜色进行

  • opencv3/C++图像边缘提取方式

    canny算子实现 使用track bar 调整canny算子参数,提取到合适的图像边缘. #include<iostream> #include<opencv2/opencv.hpp> using namespace cv; void trackBar(int, void*); int s1=0,s2=0; Mat src, dst; int main() { src = imread("E:/image/image/daibola.jpg"); if(src

  • opencv3/C++ PHash算法图像检索详解

    PHash算法即感知哈希算法/Perceptual Hash algorithm,计算基于低频的均值哈希.对每张图像生成一个指纹字符串,通过对该字符串比较可以判断图像间的相似度. PHash算法原理 将图像转为灰度图,然后将图片大小调整为32*32像素并通过DCT变换,取左上角的8*8像素区域.然后计算这64个像素的灰度值的均值.将每个像素的灰度值与均值对比,大于均值记为1,小于均值记为0,得到64位哈希值. PHash算法实现 将图片转为灰度值 将图片尺寸缩小为32*32 resize(src

  • java 中模式匹配算法-KMP算法实例详解

    java 中模式匹配算法-KMP算法实例详解 朴素模式匹配算法的最大问题就是太低效了.于是三位前辈发表了一种KMP算法,其中三个字母分别是这三个人名的首字母大写. 简单的说,KMP算法的对于主串的当前位置不回溯.也就是说,如果主串某次比较时,当前下标为i,i之前的字符和子串对应的字符匹配,那么不要再像朴素算法那样将主串的下标回溯,比如主串为"abcababcabcabcabcabc",子串为"abcabx".第一次匹配的时候,主串1,2,3,4,5字符都和子串相应的

  • JavaScript算法系列之快速排序(Quicksort)算法实例详解

    "快速排序"的思想很简单,整个排序过程只需要三步: (1)在数据集之中,选择一个元素作为"基准"(pivot). (2)所有小于"基准"的元素,都移到"基准"的左边:所有大于"基准"的元素,都移到"基准"的右边. (3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止. 举例来说,现在有一个数据集{85, 24, 63, 45,

  • Java 选择排序、插入排序、希尔算法实例详解

    1.基本思想: 在要排序的一组数中,选出最小的一个数与第一个位置的数交换:然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止. 2.实例 3.算法实现 /** * 选择排序算法 * 在未排序序列中找到最小元素,存放到排序序列的起始位置 * 再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾. * 以此类推,直到所有元素均排序完毕. * @param numbers */ public static void selectSort(int[] nu

  • Java 归并排序算法、堆排序算法实例详解

    基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并排序示例: 合并方法: 设r[i-n]由两个有序子表r[i-m]和r[m+1-n]组成,两个子表长度分别为n-i +1.n-m. j=m+1:k=i:i=i; //置两个子表的起始下标及辅助数组的起始下标 若i>m 或j>n,转⑷ //其中一个子表已合并完,比较选取结束 //选取r[i]和r[j]较小的存入辅助数组

  • KMP 算法实例详解

    KMP 算法实例详解 KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法. 分析:KMP模板题.KMP的关键是求出next的值.先预处理出next的值.然后一遍扫过.复杂度O(m+n) 实例代码: #include<stdio.h> #include<string.h> #define N 1000005 int s[N]; int p[N]; int n

  • Python编程实现粒子群算法(PSO)详解

    1 原理 粒子群算法是群智能一种,是基于对鸟群觅食行为的研究和模拟而来的.假设在鸟群觅食范围,只在一个地方有食物,所有鸟儿看不到食物(不知道食物的具体位置),但是能闻到食物的味道(能知道食物距离自己位置).最好的策略就是结合自己的经验在距离鸟群中距离食物最近的区域搜索. 利用粒子群算法解决实际问题本质上就是利用粒子群算法求解函数的最值.因此需要事先把实际问题抽象为一个数学函数,称之为适应度函数.在粒子群算法中,每只鸟都可以看成是问题的一个解,这里我们通常把鸟称之为粒子,每个粒子都拥有: 位置,可

  • Java版超大整数阶乘算法代码详解-10,0000级

    当计算超过20以上的阶乘时,阶乘的结果值往往会很大.一个很小的数字的阶乘结果就可能超过目前个人计算机的整数范围.如果需求很大的阶乘,比如1000以上完全无法用简单的递归方式去解决.在网上我看到很多用C.C++和C#写的一些关于大整数阶乘的算法,其中不乏经典但也有很多粗糙的文章.数组越界,一眼就可以看出程序本身无法运行.转载他人文章的时候,代码倒是仔细看看啊.唉,粗糙.过年了,在家闲来蛋疼,仔细分析分析,用Java实现了一个程序计算超大整数阶乘.思想取自网上,由我个人优化和改进. 这个方法采用"数

  • 基于python实现雪花算法过程详解

    这篇文章主要介绍了基于python实现雪花算法过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Snowflake是Twitter提出来的一个算法,其目的是生成一个64bit的整数: 1bit:一般是符号位,不做处理 41bit:用来记录时间戳,这里可以记录69年,如果设置好起始时间比如今年是2018年,那么可以用到2089年,到时候怎么办?要是这个系统能用69年,我相信这个系统早都重构了好多次了. 10bit:10bit用来记录机器ID

随机推荐