总共分三步:压缩,灰度化,均值化,求哈希值。

1.压缩

void secondMethod(char* filename, char* savename)
{
//const char* filename2 = filename.c_str();
//const char* savename2 = savename.c_str();
//第一幅图像的参数
IplImage* img = NULL; //OpenCV图像数据结构指针
int width, height; //图像的宽和高
//char* filename = "E:\\Pictures\\Me\\portrait.png"; //要打开图像的路径
img = cvLoadImage(filename, 1); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
width = img->width; //图像的宽
height = img->height; //图像的高 IplImage* img2; //均值后的图像
//char* savename = "E:\\Pictures\\Me\\portrait4.png"; //要存储图像的路径
img2 = cvCreateImage(cvSize(8, 8), img->depth, img->nChannels); //新建8X8的图像 //图像压缩,将任意图像压缩成8x8的图像,保存到img2中 中间变量
int img2data[3][8][8];//8x8列的数组 //其实应该是[8][8][3]还是[3][8][8] //不能设为uchar类型
int widthTime, heightTime; //平均每个像素需要合并的次数
widthTime = width/8;
heightTime = height/8; std::cout<<"widthTime:"<<widthTime<<","<<"heightTime:"<<heightTime<<std::endl;
uchar* data2 = (uchar*)(img2->imageData); //声明指针指向第二幅图像的数据区 //保存各个区域的颜色值总量,以求平均值,先归零
for(int row=0; row<img->height; row++)
for(int cols=0; cols<img->width; cols++)
{
if(row/heightTime<8 && cols/widthTime<8)
{
img2data[0][row/heightTime][cols/widthTime] = 0; //第一幅图颜色的和保存在数组,先归零
img2data[1][row/heightTime][cols/widthTime] = 0;
img2data[2][row/heightTime][cols/widthTime] = 0; data2[row/heightTime*img2->widthStep/sizeof(uchar)+cols/widthTime*img2->nChannels + 0] = 0; //第二幅图的颜色值归零,一定要是img2->widthStep img2->nChannels
std::cout<<"row:"<<row/heightTime<<",cols:"<<cols/widthTime<<std::endl;
data2[row/heightTime*img2->widthStep/sizeof(uchar)+cols/widthTime*img2->nChannels + 1] = 0;
data2[row/heightTime*img2->widthStep/sizeof(uchar)+cols/widthTime*img2->nChannels + 2] = 0;
}
}
//求和,保存在数组
for(int row=0; row<img->height; row++) //操作数据区,要注意OpenCV的RGB的存储顺序为GBR
for(int cols=0; cols<img->width; cols++)
{
if(row/heightTime<8 && cols/widthTime<8)
{
img2data[0][row/heightTime][cols/widthTime] += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
img2data[1][row/heightTime][cols/widthTime] += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 1];
img2data[2][row/heightTime][cols/widthTime] += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 2];
} } //求平均值后,保存到第二幅图的数据区
for(int row=0; row<8; row++) //操作数据区,要注意OpenCV的RGB的存储顺序为GBR
for(int cols=0; cols<8; cols++)
{
if(row/heightTime<8 && cols/widthTime<8)
{
data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = img2data[0][row][cols]/heightTime/widthTime; //G /100.0 /heightTime/widthTime
std::cout<<"0:"<<img2data[0][row][cols]<<std::endl;
data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 1] = img2data[1][row][cols]/heightTime/widthTime; //B /100.0 /heightTime/widthTime
data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 2] = img2data[2][row][cols]/heightTime/widthTime; //R /100.0 /heightTime/widthTime }
}
cvSaveImage(savename, img2); //存储图像
cvNamedWindow("show", 1); //创建窗口对象用于显示
cvShowImage("show", img2); //将图像显示在窗口上
cvWaitKey(0);
cvReleaseImage(&img); //释放图像数据结构指针对象所指内容
cvReleaseImage(&img2);
}

2. 灰值化

void gray(char* savename, char* graysavename)//第一个参数为压缩后的保存地址,第二个参数为灰度后的保存地址
{
//第一幅图像的参数
IplImage* img = NULL; //OpenCV图像数据结构指针
int width, height; //图像的宽和高
img = cvLoadImage(savename, 1); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
width = img->width; //图像的宽
height = img->height; //图像的高 IplImage* img2; //灰度化的图像
//char* savename = "E:\\Pictures\\Me\\portrait4.png"; //要存储图像的路径
img2 = cvCreateImage(cvSize(8, 8), img->depth, 1); //新建灰度的图像 //中间变量
int img2data[1][8][8];//8x8列的数组 //其实应该是[8][8][3]还是[3][8][8] //不能设为uchar类型
int img2dataB[1][8][8], img2dataG[1][8][8], img2dataR[1][8][8];
uchar* data2 = (uchar*)(img2->imageData); //声明指针指向第二幅图像的数据区 //灰度化:公式:I = 0.3B + 0.59G + 0.11R
//先将值保存到img2dataB[1][8][8], img2dataG[1][8][8], img2dataR[1][8][8]
for(int row=0; row<height; row++)
for(int cols=0; cols<width; cols++)
{
//G
img2dataG[0][row][cols] = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0]; //第一幅图颜色的和保存在数组,先归零
//B
img2dataB[0][row][cols] = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 1];
//R
img2dataR[0][row][cols] = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 2]; img2data[0][row][cols] = 0.1140*img2dataB[0][row][cols] + 0.5870*img2dataG[0][row][cols] + 0.2989*img2dataR[0][row][cols]; data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = img2data[0][row][cols]; //第二幅图的颜色值归零,一定要是img2->widthStep img2->nChannels
/*std::cout<<"row:"<<row/heightTime<<",cols:"<<cols/widthTime<<std::endl;
data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 1] = 0;
data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 2] = 0;*/
} cvSaveImage(graysavename, img2); //存储图像
cvNamedWindow("show", 1); //创建窗口对象用于显示
cvShowImage("show", img2); //将图像显示在窗口上
cvWaitKey(0);
cvReleaseImage(&img); //释放图像数据结构指针对象所指内容
cvReleaseImage(&img2);
}

3. 均值化

void average(char* graysavename)
{
//第一幅图像的参数
IplImage* img = NULL; //OpenCV图像数据结构指针
int width, height; //图像的宽和高
img = cvLoadImage(graysavename, 1); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
width = img->width; //图像的宽
height = img->height; //图像的高 //第二幅图像的参数:二值化
IplImage* img2 = NULL;
img2 = cvCreateImage(cvSize(8, 8), img->depth, 1);
uchar* data2 = (uchar*)(img2->imageData); //计算均值
double average = 0.0;
for(int row=0; row<height; row++) //操作数据区,要注意OpenCV的RGB的存储顺序为GBR
for(int cols=0; cols<width; cols++)
{
average += data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
}
average /= (height*width); //得到均值
std::cout<<"average:"<<average<<std::endl; //二值化
for(int row=0; row<height; row++)
for(int cols=0; cols<width; cols++)
{
//对比该像素点的灰度值与平均值
uchar pixeldata = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + 0];
if(pixeldata>=average)
{
data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = 255;
}
else
{
data2[row*img2->widthStep/sizeof(uchar)+cols*img2->nChannels + 0] = 0;
}
} cvSaveImage("E:\\Pictures\\Me\\portrait6.png", img2); //存储图像
cvNamedWindow("show", 1); //创建窗口对象用于显示
cvShowImage("show", img2); //将图像显示在窗口上
cvWaitKey(0);
cvReleaseImage(&img); //释放图像数据结构指针对象所指内容
cvReleaseImage(&img2);
}

4. 求哈希值

void getHash(char* twovaluefilename)
{
//第一幅图像的参数
IplImage* img = NULL; //OpenCV图像数据结构指针
int width, height; //图像的宽和高
img = cvLoadImage(twovaluefilename, ); //打开图像,这个过去其实也完成了图像的解码,图像的信息存在IplImage指针所指的数据结构中
uchar* data = (uchar*)(img->imageData); //声明指针指向图像的数据区
width = img->width; //图像的宽
height = img->height; //图像的高 long int value1 = 0x00000000; //保存位的值,由于C++不允许以二进制保存,所以用的0x十六进制保存的,总共4*8=32位
long int value2 = 0x00000000; //value1为前32位,value2为后32位
std::cout<<"保存值之前:"<<std::bitset<>(value1)<<std::bitset<>(value2)<<std::endl; //计算图像的哈希值
for(int row=; row<height/; row++) //前半部分
for(int cols=; cols<width; cols++)
{
//对比该像素点的灰度值与平均值
uchar pixeldata = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + ];
if(pixeldata>=) //白色
{
value1 |= (<<( - (row*+cols) -));
}
else
{
//无
}
}
for(int row=height/; row<height; row++) //后半部分
for(int cols=; cols<width; cols++)
{
//对比该像素点的灰度值与平均值
uchar pixeldata = data[row*img->widthStep/sizeof(uchar)+cols*img->nChannels + ];
if(pixeldata>=) //白色
{
value2 |= (<<( - (row*+cols) -));
}
else
{
//无
}
}
std::cout<<"保存值之后:"<<std::bitset<>(value1)<<std::bitset<>(value2)<<std::endl;//以二进制的形式输出
std::cout<<"十六进制结果值:"<<std::hex<<value1<<value2<<std::endl; //以十六进制的形式输出:比如abcdef
//将十六进制数保存到char类型里
char char1[];
hextochar(value1, value2, char1); //十六进制数转char
std::string str1 = char1; //将char数组char1保存到string变量str1中,用于文件名
std::cout<<"字符串数组:"<<str1<<std::endl; //输出哈希值
}

结果:

原图:

压缩:

灰值化:

均值化:

哈希值:

这时候,比较两个图片的相似性,就是先计算这两张图片的hash指纹,也就是64位0或1值,然后计算不同位的个数(汉明距离)。如果这个值为0,则表示这两张图片非常相似,如果汉明距离小于5,则表示有些不同,但比较相近,如果汉明距离大于10则表明完全不同的图片。(该段转自:原文。)

OpenCV实现均值哈希的更多相关文章

  1. 使用Opencv中均值漂移meanShift跟踪移动目标

    Mean Shift均值漂移算法是无参密度估计理论的一种,无参密度估计不需要事先知道对象的任何先验知识,完全依靠训练数据进行估计,并且可以用于任意形状的密度估计,在某一连续点处的密度函数值可由该点邻域 ...

  2. OpenCV实现pHash哈希

    离散余弦变换(DCT,Discrete Cosine Transform)是与傅里叶变换相关的一种变换,它类似于离散傅里叶变换(DFT,Discrete Fourier Transform),但是只使 ...

  3. opencv-10-图像滤波-噪声添加与均值滤波-含opencv C++ 代码实现

    开始之前 再说上一篇文章中, 我们想按照噪声产生, 然后将降噪的, 但是限于篇幅, 我就放在这一篇里面了, 说起图像的噪声问题就又回到了我们上一章的内容, 把噪声当作信号处理, 实际上数字图像处理实际 ...

  4. OpenCV计算机视觉学习(4)——图像平滑处理(均值滤波,高斯滤波,中值滤波,双边滤波)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice &q ...

  5. Python OpenCV 图像相识度对比

    强大的openCV能做什么我就不啰嗦,你能想到的一切图像+视频处理. 这里,我们说说openCV的图像相似度对比, 嗯,说好听一点那叫图像识别,但严格讲, 图像识别是在一个图片中进行类聚处理,比如图片 ...

  6. 用opencv做的静态图片人脸识别

    这次给大家分享一个图像识别方面的小项目,主要功能是识别图像中的人脸并根据人脸在图片库找出同一个与它最相似的图片,也就是辨别不同的人. 环境:VS2013+opencv2.4.13 主要是算法:open ...

  7. opencv2对读书笔记——使用均值漂移算法查找物体

    一些小概念 1.反投影直方图的结果是一个概率映射,体现了已知图像内容出如今图像中特定位置的概率. 2.概率映射能够找到最初的位置,从最初的位置開始而且迭代移动,便能够找到精确的位置,这就是均值漂移算法 ...

  8. 第十五节、OpenCV学习(四)图像平滑与滤波

    图像的平滑与滤波 平滑滤波是低频增强的空间域滤波技术,是图像模糊.消除噪声. 一.2D滤波器cv2.filter2D() 对于2D图像可以进行低通或者高通滤波操作,低通滤波(LPF)有利于去噪声,模糊 ...

  9. Python下opencv使用笔记(图像的平滑与滤波)

    对于图形的平滑与滤波,但从滤波角度来讲,一般主要的目的都是为了实现对图像噪声的消除,增强图像的效果. 对于2D图像可以进行低通或者高通滤波操作 低通滤波(LPF):有利于去噪,模糊图像 高通滤波(HP ...

随机推荐

  1. [转]搭建MySQL高可用负载均衡集群

    转自:http://www.cnblogs.com/phpstudy2015-6/p/6706465.html 阅读目录 1.简介 2.基本环境 3.配置MySQL主主复制 4.中间件简述 4.1.H ...

  2. OD 实验(十四) - 内嵌补丁

    内嵌补丁(inline patch): 内嵌补丁指在程序文件中把补丁代码写入文件里面达到破解的目的 如果修改某行语句会影响后面的语句,例如某语句占用 3 个字节,修改完变为 5 个字节,会覆盖后面的语 ...

  3. thymeleaf layout

      摘自:https://tomoya92.github.io/2017/03/09/thymeleaf-layout/   thymeleaf的layout常用的有两种方式用法 第一种将页面里的每个 ...

  4. 移动app非功能测试点收集

    非功能测试 移动app测试的另一重要方面是移动app的非功能需求.移动app在推出市场或进行进一步开发前,移动测试员有许多需要测试的问题. 早期开发阶段要进行的第一个测试应该是实用性测试.通常是由al ...

  5. 初识ansible

    一 . 初识ansible 1 . 准备工作: 准备四台干净的虚拟机, 192.168.133.129(主控节点,下面三个为被控节点) 192.168.133.130 192.168.133.131 ...

  6. Android Studio 2.3.3 调用asp.net webService实战(拒绝忽悠)

    1.路径中不能包含localhost(本来想在本机调试,就是不行,没办法发布到远程服务器) 2.必须采用异步的办法(阻塞主线程的是肯定不行了) 3.以下是全部的源代码(毫不保留) package co ...

  7. 关于电机驱动扩展板 L293D 马达板Arduino

    注意端口3,4,5,6,7,8,9,10,11,12会被占用(板子上的pin口). 通过 MS_DCMotor motor(4); 中的4指的是4号电机,同理还有1-3号电机.不是pin口   舵机用 ...

  8. leetcode830

    public class Solution { public IList<IList<int>> LargeGroupPositions(string S) { //" ...

  9. 跟着太白老师学python day10 名称空间,作用域和取值顺序,变量的加载顺序

    名称空间分为3种: 1. 全局名称空间 2. 内置名称空间 3. 局部名称空间(临时) 作用域 全局作用域              1全局名称空间 2 内置名称空间 局部作用域           ...

  10. iOS学习之UINavigationController详解与使用(二)页面切换和segmentedController

    iOS学习之UINavigationController详解与使用(一)添加UIBarButtonItem是上篇,我们接着讲UINavigationController的重要作用,页面的管理和切换. ...