前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2020-10-22在线识图搜索引擎

2020-10-22在线识图搜索引擎

作者头像
爱笑的架构师
发布2020-10-28 14:50:31
9410
发布2020-10-28 14:50:31
举报
文章被收录于专栏:爱笑的架构师爱笑的架构师

前言

最近在逛淘宝时发现了淘宝的图片搜索功能,可能是我太Low了这个技术点已经实现很长时间了。想想自己能不能实现这个功能,起初我是这么想的,对两张图片从左上角的第一个像素点一直比较到右下角的最后一个像素点,并在比较时记录它们的相似度,可能是我太天真了(主要还是知识限制了想象),这样做有很多问题,比如说两张图片大小不一致、核心要素点的位置不同等...最终只得借助网络了,找到了一种叫做均值哈希的算法(Average hash algorithm),接下来具体阐述它的基本思路以及适用场景。

均值哈希的基本思路

1、缩小尺寸:

去除图片的高频和细节的最快方法是缩小图片,将图片缩小到8x8的尺寸,总共64个像素。不要保持纵横比,只需将其变成8乘8的正方形。这样就可以比较任意大小的图片,摒弃不同尺寸、比例带来的图片差异。

2、简化色彩:

将8乘8的小图片转换成灰度图像。

3、计算平均值:

计算所有64个像素的灰度平均值。

4、比较像素的灰度:

将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

5、计算hash值:

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

如果图片放大或缩小,或改变纵横比,结果值也不会改变。增加或减少亮度或对比度,或改变颜色,对hash值都不会太大的影响。最大的优点:计算速度快!

那么完成了以上步骤,一张图片就相当于有了自己的"指纹"了,然后就是计算不同位的个数,也就是汉明距离(例如1010001与1011101的汉明举例就是2,也就是不同的个数)。

如果汉明距离小于5,则表示有些不同,但比较相近,如果汉明距离大于10则表明完全不同的图片。

以上就是均值哈希的基本实现思路,总体来说是比较简单的。

C#实现

代码语言:javascript
复制
public class ImageHashHelper

{

/// <summary>

/// 获取缩略图

/// </summary>

/// <returns></returns>

private static Bitmap GetThumbImage(Image image, int w, int h)

{

Bitmap bitmap = new Bitmap(w, h);

Graphics g = Graphics.FromImage(bitmap);

g.DrawImage(image,

new Rectangle(0, 0, bitmap.Width, bitmap.Height),

new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);

return bitmap;

}


/// <summary>

/// 将图片转换为灰度图像

/// </summary>

/// <returns></returns>

private static Bitmap ToGray(Bitmap bmp)

{

for (int i = 0; i < bmp.Width; i++)

{

for (int j = 0; j < bmp.Height; j++)

{

//获取该点的像素的RGB的颜色

Color color = bmp.GetPixel(i, j);

//利用公式计算灰度值

int gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);//计算方式1

//int gray1 = (int)((color.R + color.G + color.B) / 3.0M);//计算方式2

Color newColor = Color.FromArgb(gray, gray, gray);

bmp.SetPixel(i, j, newColor);

}

}

return bmp;

}


/// <summary>

/// 获取图片的均值哈希

/// </summary>

/// <returns></returns>

public static int[] GetAvgHash(Bitmap bitmap)

{

Bitmap newBitmap = ToGray(GetThumbImage(bitmap, 8, 8));

int[] code = new int[64];

//计算所有64个像素的灰度平均值。

List<int> allGray = new List<int>();

for (int row = 0; row < bitmap.Width; row++)

{

for (int col = 0; col < bitmap.Height; col++)

{

allGray.Add(newBitmap.GetPixel(row, col).R);

}

}

double avg = allGray.Average(a => a);//拿到平均值

//比较像素的灰度

for (int i = 0; i < allGray.Count; i++)

{

code[i] = allGray[i] >= avg ? 1 : 0;//将比较结果进行组合

}

//返回结果

return code;

}


/// <summary>

/// 对两个AvgHash进行比较

/// </summary>

/// <returns></returns>

public static int Compare(int[] code1, int[] code2)

{

int v = 0;

for (int i = 0; i < 64; i++)

{

if (code1[i] == code2[i])

{

v++;

}

}

return v;

}

}

这里我们在GetAvgHash函数中获取64个像素的灰度值时直接通过了R来获取,因为RGB都是一样的,所以哪一个都可以。

灰度值换算:baike.baidu.com/item/灰度值/10…

效果演示:

1、原图查找

2、完全马赛克查找

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-10-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 均值哈希的基本思路
  • C#实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档