1. 程式人生 > 其它 >感知雜湊演算法——找出相似的圖片

感知雜湊演算法——找出相似的圖片

第一步 縮小圖片尺寸

將圖片縮小到16x16的尺寸, 總共256個畫素. 這一步的作用是去除各種圖片尺寸和圖片比例的差異, 只保留結構、明暗等基本資訊.

第二步 轉為灰度圖片

將縮小後的圖片, 轉為256級灰度圖片.

第三步 計算灰度平均值

計算圖片中所有畫素的灰度平均值

第四步 比較畫素的灰度

將每個畫素的灰度與平均值進行比較, 如果大於或等於平均值記為1, 小於平均值記為0.

第五步 計算雜湊值

將上一步的比較結果, 組合在一起, 就構成了一個64位的二進位制整數, 這就是這張圖片的指紋.

第六步 對比圖片指紋

得到圖片的指紋後, 就可以對比不同的圖片的指紋, 計算出64位中有多少位是不一樣的. 如果不相同的資料位數不超過5, 就說明兩張圖片很相似, 如果大於10, 說明它們是兩張不同的圖片.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace B2BPicture
{
   public  class pictureCompare
    {
        Image SourceImg;

        public pictureCompare(string filePath)
        {
            SourceImg = Image.FromFile(filePath);
        }

        public pictureCompare(Stream stream)
        {
            SourceImg = Image.FromStream(stream);
        }

        public String GetHash()
        {
            Image image = ReduceSize();
            Byte[] grayValues = ReduceColor(image);
            Byte average = CalcAverage(grayValues);
            String reslut = ComputeBits(grayValues, average);
            return reslut;
        }

        // Step 1 : Reduce size to 8*8
        private Image ReduceSize(int width = 16, int height = 16)
        {
            Image image = SourceImg.GetThumbnailImage(width, height, () => { return false; }, IntPtr.Zero);
            return image;
        }

        // Step 2 : Reduce Color
        private Byte[] ReduceColor(Image image)
        {
            Bitmap bitMap = new Bitmap(image);
            Byte[] grayValues = new Byte[image.Width * image.Height];

            for (int x = 0; x < image.Width; x++)
                for (int y = 0; y < image.Height; y++)
                {
                    Color color = bitMap.GetPixel(x, y);
                    byte grayValue = (byte)((color.R * 30 + color.G * 59 + color.B * 11) / 100);
                    grayValues[x * image.Width + y] = grayValue;
                }
            return grayValues;
        }

        // Step 3 : Average the colors
        private Byte CalcAverage(byte[] values)
        {
            int sum = 0;
            for (int i = 0; i < values.Length; i++)
                sum += (int)values[i];
            return Convert.ToByte(sum / values.Length);
        }

        // Step 4 : Compute the bits
        private String ComputeBits(byte[] values, byte averageValue)
        {
            char[] result = new char[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                if (values[i] < averageValue)
                    result[i] = '0';
                else
                    result[i] = '1';
            }
            return new String(result);
        }

        // Compare hash
        public static Int32 CalcSimilarDegree(string a, string b)
        {
            if (a.Length != b.Length)
                throw new ArgumentException();
            int count = 0;
            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] != b[i])
                    count++;
            }
            return count;
        }
    
}
}

  

呼叫生成hash碼值

pictureCompare picture = new pictureCompare(@"C:\Users\yc\Desktop\圖片\" + i+".png");
string hashvalue = picture.GetHash();

pictureCompare picture2 = new pictureCompare(@"C:\Users\yc\Desktop\圖片\" + i+".png");
string hashvalue2 = picture2.GetHash();

hash碼值對比

int count= pictureCompare.CalcSimilarDegree(hashvalue2, hashvalue);

count小於10 基本就非常相似了,這樣子就可以從相簿找到相似圖了

參考來源:https://www.cnblogs.com/technology/archive/2012/07/12/2588022.html