图片相似性 d-hash算法 C#实践

参考:

https://github.com/maccman/dhash

http://blog.iconfinder.com/detecting-duplicate-images-using-python/ 讲的很详细

http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html 各种图片相似性算法比较

namespace PictureSimilarity
{
    public class ImageDHash
    {
        /// <summary>
        /// 获取图片的D-hash值
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public static ulong GetHash(Image image)
        {
            int hashSize = 8;
            //图片缩小到9*8的尺寸
            var thumbImage = Resize(image, hashSize + 1, hashSize);
            //获取灰度图片,灰度图片即把rgb转换成0~255的值
            var grayImage = GetGrayScaleVersion(thumbImage);

            ulong hash = 0;

            //遍历9*8像素点,记录相邻像素之间的对边关系,产生8*8=64个对比关系,对应ulong的64位
            for (int x = 0; x < hashSize; x++)
            {
                for (int y = 0; y < hashSize; y++)
                {
                    //比较当前像素点与下一个像素点的对比关系,如果当前像素点值较大则为1,否则为0
                    var largerThanNext = Math.Abs(grayImage.GetPixel(y, x).R) > Math.Abs(grayImage.GetPixel(y + 1, x).R);
                    if (largerThanNext)
                    {
                        var currentIndex = x * hashSize + y;
                        hash |= (1UL << currentIndex);
                    }

                }
            }

            return hash;
        }

        /// <summary>
        /// 计算两个hash值之间的汉明距离
        /// </summary>
        /// <param name="hash1"></param>
        /// <param name="hash2"></param>
        /// <returns></returns>
        public static double GetSimilarity(ulong hash1, ulong hash2)
        {
            return (64 - BitCount(hash1 ^ hash2)) / 64.0;
        }

        /// <summary>
        /// Bitcounts array used for BitCount method (used in Similarity comparisons).
        /// Don‘t try to read this or understand it, I certainly don‘t. Credit goes to
        /// David Oftedal of the University of Oslo, Norway for this.
        /// http://folk.uio.no/davidjo/computing.php
        /// </summary>
        private static byte[] bitCounts = {
            0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,
            2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
            2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,
            4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
            2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,
            3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
            4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
        };
        /// <summary>
        /// 计算ulong中位值为1的个数
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        private static uint BitCount(ulong num)
        {
            uint count = 0;
            for (; num > 0; num >>= 8)
                count += bitCounts[(num & 0xff)];
            return count;
        }

        /// <summary>
        /// 修改图片尺寸
        /// </summary>
        /// <param name="originalImage"></param>
        /// <param name="newWidth"></param>
        /// <param name="newHeight"></param>
        /// <returns></returns>
        public static Image Resize(Image originalImage, int newWidth, int newHeight)
        {
            Image smallVersion = new Bitmap(newWidth, newHeight);
            using (Graphics g = Graphics.FromImage(smallVersion))
            {
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                g.DrawImage(originalImage, 0, 0, newWidth, newHeight);
            }

            return smallVersion;
        }

        private static ColorMatrix ColorMatrix = new ColorMatrix(
          new float[][]
          {
             new float[] {.3f, .3f, .3f, 0, 0},
             new float[] {.59f, .59f, .59f, 0, 0},
             new float[] {.11f, .11f, .11f, 0, 0},
             new float[] {0, 0, 0, 1, 0},
             new float[] {0, 0, 0, 0, 1}
          });

        /// <summary>
        /// 获取灰度图片
        /// </summary>
        /// <param name="original"></param>
        /// <returns></returns>
        public static Bitmap GetGrayScaleVersion(Image original)
        {
            //http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale
            //create a blank bitmap the same size as original
            Bitmap newBitmap = new Bitmap(original.Width, original.Height);

            //get a graphics object from the new image
            using (Graphics g = Graphics.FromImage(newBitmap))
            {
                //create some image attributes
                ImageAttributes attributes = new ImageAttributes();

                //set the color matrix attribute
                attributes.SetColorMatrix(ColorMatrix);

                //draw the original image on the new image
                //using the grayscale color matrix
                g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
                   0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
            }
            return newBitmap;
        }
    }
}
时间: 2024-10-12 16:30:40

图片相似性 d-hash算法 C#实践的相关文章

图片相似度——hash算法简介

一.均值hash 均值hash方法是对每幅图片生成一个"指纹"字符串,然后通过比较不同图片的指纹来确定图片的相似性,比较结果越接近,则说明图片越相似. 计算均值hash的步骤. 1.缩小尺寸 去除高频和细节的最快方法是缩小图片,将图片缩小到8x8的尺寸,总共64个像素.不要保持纵横比,只需将其变成8*8的正方形.这样就可以比较任意大小的图片,摒弃不同尺寸.比例带来的图片差异. 2.简化色彩 将8*8的小图片转换成灰度图像,将64个像素的颜色(red,green,blue)转换成一种颜色

PHP核心技术与最佳实践之Hash算法

PHP核心技术与最佳实践之Hash算法 Hash表又称散列表,通过把关键字Key映射到数组中的一个位置来访问记录,以加快查找速度.这个映射函数称为Hash函数,存放记录的数组称为Hash表. 1.     Hash函数 作用是把任意长度的输入,通过Hash算法变换成固定长度的输出,该输出就是Hash值.这种转换是一种压缩映射,也就是Hash值得空间通常远小于输入的空间,不输入可能会散列成相同的输出,而不可能从Hash值来唯一的确定输入值. 一个好的hash函数应该满足以下条件:每个关键字都可以均

【数据结构与算法】一致性Hash算法及Java实践

追求极致才能突破极限 一.案例背景 1.1 系统简介 首先看一下系统架构,方便解释: 页面给用户展示的功能就是,可以查看任何一台机器的某些属性(以下简称系统信息). 消息流程是,页面发起请求查看指定机器的系统信息到后台,后台可以查询到有哪些server在提供服务,根据负载均衡算法(简单的轮询)指定由哪个server进行查询,并将消息发送到Kafka,然后所有的server消费Kafka的信息,当发现消费的信息要求自己进行查询时,就连接指定的machine进行查询,并将结果返回回去. Server

一致性hash算法 - consistent hashing

1.背景 我们都知道memcached服务器是不提供分布式功能的,memcached的分布式完全是由客户端来实现的.在部署memcached服务器集群时,我们需要把缓存请求尽可能分散到不同的缓存服务器中,这样可以使得所有的缓存空间都得到利用,而且可以降低单独一台缓存服务器的压力.     最简单的一种实现是,缓存请求时通过计算key的哈希值,取模后映射到不同的memcahed服务器.这种简单的实现在不考虑集群机器动态变化的情况下也是比较有效的一种方案,但是,在分布式集群系统中,简单取模的哈希算法

数据挖掘系列(9)——BP神经网络算法与实践

神经网络曾经很火,有过一段低迷期,现在因为深度学习的原因继续火起来了.神经网络有很多种:前向传输网络.反向传输网络.递归神经网络.卷积神经网络等.本文介绍基本的反向传输神经网络(Backpropagation 简称BP),主要讲述算法的基本流程和自己在训练BP神经网络的一些经验. BP神经网络的结构 神经网络就是模拟人的大脑的神经单元的工作方式,但进行了很大的简化,神经网络由很多神经网络层构成,而每一层又由许多单元组成,第一层叫输入层,最后一层叫输出层,中间的各层叫隐藏层,在BP神经网络中,只有

分布式缓存一致性hash算法理解

今天阅读了一下大型网络技术架构这本苏中的分布式缓存一致性hash算法这一节,针对大型分布式系统来说,缓存在该系统中必不可少,分布式集群环境中,会出现添加缓存节点的需求,这样需要保障缓存服务器中对缓存的命中率,就有很大的要求了: 采用普通方法,将key值进行取hash后对分布式缓存机器数目进行取余,以集群3台分布式缓存为例子: 对于数据进行取hash值然后对3其进行取余,余数为0则进入node 0,余数位1则进入node1,余数位2则进入node2. 如果增加一个节点则对4进行取余,则会将node

集群扩容的常规解决:一致性hash算法

写这篇博客是因为之前面试的一个问题: 如果memcached集群需要增加机器或者减少机器,那么其他机器上的数据怎么办? 最后了解到使用一致性hash算法可以解决,下面一起来学习下吧. 声明与致谢: 本文转载于朱双印博主的个人日志<白话解析:一致性哈希算法 consistent hashing>一文. 一. 引子 在了解一致性哈希算法之前,最好先了解一下缓存中的一个应用场景,了解了这个应用场景之后,再来理解一致性哈希算法,就容易多了,也更能体现出一致性哈希算法的优点,那么,我们先来描述一下这个经

用大白话讲一致性Hash算法在Redis分布式中的使用

在了解一致性哈希算法之前,最好先了解一下缓存中的一个应用场景,了解了这个应用场景之后,再来理解一致性哈希算法,就容易多了,也更能体现出一致性哈希算法的优点,那么,我们先来描述一下这个经典的分布式缓存的应用场景. 1 .场景描述 假设,我们有三台缓存服务器,用于缓存图片,我们为这三台缓存服务器编号为0号.1号.2号,现在,有3万张图片需要缓存,我们希望这些图片被均匀的缓存到这3台服务器上,以便它们能够分摊缓存的压力.也就是说,我们希望每台服务器能够缓存1万张左右的图片,那么,我们应该怎样做呢?如果

好程序员带你五分钟了解一致性hash算法

好程序员带你五分钟了解一致性hash算法,一致性哈希算法的设计目标是为了解决因特网中的热点问题,现在也被广泛应用在分布式系统中. 比如针对负载均衡问题,对hash值取模的算法扩展性差,当增加或者减少服务器时,映射关系可能会出现问题,采用一致性hash算法,就能较好的解决该问题. Hash值取模算法存在的问题 比如,我们有海量的图片存储在服务器上,假如,现在有4台服务器,我们可以根据图片名称,采用hash算法,决定图片存储在哪台服务器 如果现在需要增加服务器,那么存取图片的服务器的算法就会发生改变