感知哈希算法实现以图搜图软件

前言

百度谷歌等搜索引擎有一个用图片来搜索图片的功能,如下图所示:


网上看到一篇介绍实现它的一种方法原理的文章,依据该原理方法自己动手写了一个类似功能的软件(软件含源码)。


开发环境

Windows10+VS2013+OpenCV300+Qt560


理论与代码实现

上面那篇文章实现意图搜图功能大概有以下几个步骤(注:以下理论引用自上面那篇文章,算法自己实现,只列出主要代码):

第一步:缩小尺寸:

将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异,代码如下:

Mat PerceptualHashAlgorithm::reductionTo64Pixel(Mat image){

	cv::Mat image64Pix;
	cv::Size newsize = cv::Size(8, 8);
	if (image.channels() == 1)		image64Pix = cv::Mat(newsize, CV_8UC1);
	else if (image.channels() == 3)	image64Pix = cv::Mat(newsize, CV_8UC3);
	else if (image.channels() == 4)	image64Pix = cv::Mat(newsize, CV_8UC4);
	else							return image;
	cv::resize(image, image64Pix, newsize);

	return image64Pix; // 返回缩小到8*8的图像
}
第二步,简化色彩:

将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色,代码如下:

Mat PerceptualHashAlgorithm::cvtTo64LevelGray(Mat image){

	Mat image64PixGray;
	cvtColor(image, image64PixGray, CV_BGR2GRAY);

	for (int i = 0; i < image64PixGray.rows; i++){

		unsigned char *p = image64PixGray.ptr<unsigned char>(i);
		for (int j = 0; j < image64PixGray.cols; j++){

			p[j] = p[j] / 256. * 64.;
		}
	}
	return image64PixGray; // 返回64级灰度
}
第三步,计算平均值

计算所有64个像素的灰度平均值,代码如下:

int PerceptualHashAlgorithm::calc64LevelGrayAverage(Mat image){

	int sum = 0;
	for (int i = 0; i < image.rows; i++){

		unsigned char *p = image.ptr<unsigned char>(i);
		for (int j = 0; j < image.cols; j++){

			sum += p[j];
		}
	}
	return (sum / 64); // 返回平均值
}
第四步,比较像素的灰度

将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为255;小于平均值,记为0,代码如下:

Mat PerceptualHashAlgorithm::calcHashMask(Mat image, int ave){

	hashValue = 0;
	for (int i = 0; i < image.rows; i++){

		unsigned char *p = image.ptr<unsigned char>(i);
		for (int j = 0; j < image.cols; j++){

			if (p[j] >= ave) p[j] = 255; // 大等于均值,标记255
			else p[j] = 0; // 小于均值,标记0

			hashValue |= ((p[j] == 0) ? (0) : (1)); // 计算哈希值
			hashValue = hashValue << 1;
		}
	}
	return image;
}

第五步,计算哈希值

将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。(注:上一步代码的hashValue就是哈希值)。


图片示意

以下用一张图片演示上面步骤的全过程:


上面全过程代码封装如下:

Mat PerceptualHashAlgorithm::calcFingerprint(Mat image){

	Mat image64Pix		= reductionTo64Pixel(image);
	Mat image64PixGray	= cvtTo64LevelGray(image64Pix);
	int ave				= calc64LevelGrayAverage(image64PixGray);
	Mat mask			= calcHashMask(image64PixGray, ave);
	return mask;
}

  

软件展示

软件这边下载(传送门),含源码。

初始界面,可以选择训练图片或者搜索图片(当然前提是数据库中已经训练了一些图片供搜索),如下图:


训练图片的界面,选择图片(伟大的国旗)后,会进行训练生成对应的哈希值和哈希指纹图片,点击加入数据库,就会把图像和哈希指纹(哈希指纹图像加入数据库要以bmp格式加入,如果以jpg会导致压缩过程失真导致数据发生轻微变形,进行汉明距离计算的时候发生错误)加入数据库,如下图:



搜索图片界面,选择要搜索的图片后,就会进行将该图片与数据库进行比对,得到每一张图片的汉明距离,所有符合汉明距离要求的图像就是相似图像,会列出所有的相似图像的缩略图,点击对应的图像的缩略图可以看到对应的哈希指纹和汉明距离的值,如下图:


OK,大概功能就是这样子,(不过有时候识别有误,不过还算可以了,哈哈,做毕业设计的可以拿去参考参考,可以更换不同的特征特点生成类似这样的哈希指纹,原理都差不多,只不过实现的过程算法不一样)。


附录

软件和源码下载地址:http://download.csdn.net/download/kaychangeek/10244711



  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值