美文网首页
C#实现哈希均值算法处理图片

C#实现哈希均值算法处理图片

作者: 流量地球 | 来源:发表于2020-07-07 18:12 被阅读0次

    using System;

    using System.Collections.Generic;

    using System.Drawing;

    using System.Text;

    using System.Linq; //list集合的扩展

    namespace W

    {

            // private static Bitmap ZoomImage(Bitmap bitmap, int destHeight, int destWidth)

            //        {

            //            try

            //            {

            //                System.Drawing.Image sourImage = bitmap;

            //                int width = 0, height = 0;

            //                //按比例缩放           

            //                int sourWidth = sourImage.Width;

            //                int sourHeight = sourImage.Height;

            //                if (sourHeight > destHeight || sourWidth > destWidth)

            //                {

            //                    if ((sourWidth * destHeight) > (sourHeight * destWidth))

            //                    {

            //                        width = destWidth;

            //                        height = (destWidth * sourHeight) / sourWidth;

            //                    }

            //                    else

            //                    {

            //                        height = destHeight;

            //                        width = (sourWidth * destHeight) / sourHeight;

            //                    }

            //                }

            //                else

            //                {

            //                    width = sourWidth;

            //                    height = sourHeight;

            //                }

            //                Bitmap destBitmap = new Bitmap(destWidth, destHeight);

            //                Graphics g = Graphics.FromImage(destBitmap);

            //                g.Clear(Color.Transparent);

            //                //设置画布的描绘质量         

            //                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

            //                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            //                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            //                g.DrawImage(sourImage, new Rectangle((destWidth - width) / 2, (destHeight - height) / 2, width, height), 0, 0, sourImage.Width, sourImage.Height, GraphicsUnit.Pixel);

            //                g.Dispose();

            //                //设置压缩质量     

            //                System.Drawing.Imaging.EncoderParameters encoderParams = new System.Drawing.Imaging.EncoderParameters();

            //                long[] quality = new long[1];

            //                quality[0] = 100;

            //                System.Drawing.Imaging.EncoderParameter encoderParam = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);

            //                encoderParams.Param[0] = encoderParam;

            //                sourImage.Dispose();

            //                return destBitmap;

            //            }

            //            catch

            //            {

            //                return bitmap;

            //            }

            //        }

            ////转换为灰度图:

            //        public static Bitmap ToGray(Bitmap bmp, out int avgGray)

            //        {

            //            int sum = 0;

            //            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);

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

            //                    sum += gray;

            //                    bmp.SetPixel(i, j, newColor);

            //                }

            //            }

            //            avgGray = sum / (bmp.Width * bmp.Height);

            //            return bmp;

            //        }

            ////灰度指纹:(64位其实可以换成更高位数,比如用16x16,和8x8相比就要用4个64位进行表示)

            //            Bitmap bmp1 = ZoomImage((Bitmap)img1, 8, 8);

            //            Bitmap bmp2 = ZoomImage((Bitmap)img2, 8, 8);

            //            int avgGray1, avgGray2;

            //            bmp1 = ToGray(bmp1, out avgGray1);

            //            bmp2 = ToGray(bmp2, out avgGray2);

            //            UInt64 Hashdis1 = 0;

            //            UInt64 Hashdis2 = 0;

            //            UInt64 mask = 1;

            //            for (int x = 0; x < 8; x++)

            //            {

            //                for (int y = 0; y < 8; y++)

            //                {

            //                    int m = y * 8 + x;

            //                    Color c1 = bmp1.GetPixel(x, y);

            //                    if (c1.R >= avgGray1)

            //                    {

            //                        Hashdis1 |= mask << m;

            //                    }

            //                    Color c2 = bmp1.GetPixel(x, y);

            //                    if (c2.R >= avgGray2)

            //                    {

            //                        Hashdis2 |= mask << m;

            //                    }

            //                }

            //            }

            ////得到汉明距离:

            //            UInt64 hash= Hashdis1 ^ Hashdis2;

            //            int Hammingdis = 0;

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

            //            {

            //                if ((hash & (mask << i)) != 0)

            //                    Hammingdis++;

            //            }

            //            return Hammingdis;

            ////两个指纹进行异或运算,求不为0的位数(相异为1)

          #region ahash算法

            /*

                    均值哈希的基本思路

            1、缩小尺寸:

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

            2、简化色彩:

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

            3、计算平均值:

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

            4、比较像素的灰度:

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

            5、计算hash值:

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

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

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

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

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

            ————————————————

            版权声明:本文为CSDN博主「床长」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

            原文链接:https://blog.csdn.net/jiangjunshow/article/details/100657183

            */

            static public class ImageHashHelper

            {

                static public List<int> mathXList = new List<int>();

                static public List<int> mathYList = new List<int>();

                /// <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)

                {

                    try

                    {

                        Log.write("ImageHashHelper", "GetAvgHash", "bmp.Width;" + bmp.Width + ";bmp.Height:" + bmp.Height);

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

                        {

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

                            {

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

                                Color color = bmp.GetPixel(x, y);

                                //利用公式计算灰度值

                                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(x, y, newColor);

                            }

                        }

                    }

                    catch (Exception ex)

                    {

                        Log.write("ImageHashHelper", "ToGray", "" + ex.ToString());

                    }

                    return bmp;

                }

                /// <summary>

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

                /// </summary>

                /// <returns></returns>

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

                public static int bitmapl = 32;

                public static int bitmapw = 32;

                static int bitmaps = bitmapl * bitmapw;

                public static int[] GetAvgHash(Bitmap bitmap)

                {

                    int[] code = new int[bitmaps];

                    try

                    {

                        //Log.write("ImageHashHelper", "GetAvgHash", "bitmaps;" + bitmaps + ";bitmapl:" + bitmapl + ";bitmapw:" + bitmapw);

                        Bitmap newBitmap = ToGray(GetThumbImage(bitmap, bitmapl, bitmapw));

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

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

                      //Log.write("ImageHashHelper", "GetAvgHash", "bitmap.Width;" + newBitmap.Width + ";bitmap.Height:" + newBitmap.Height);

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

                        {

                            for (int col = 0; col < newBitmap.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;//将比较结果进行组合

                        }

                    }

                    catch (Exception ex)

                    {

                        Log.write("ImageHashHelper", "GetAvgHash", "" + ex.ToString());

                    }

                    //返回结果

                    return code;

                }

                /// <summary>

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

                /// </summary>

                /// <returns></returns>

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

                public static int[] GetAvgHash(Bitmap bitmap,List<int> lx,List<int> ly)

                {

                    if (lx.Count < 4 || ly.Count < 4) throw new Exception("List<int> lx,ly 必须为四边形的四个点的有效坐标");

                    int[] code = new int[bitmaps];

                    try

                    {

                        Log.write("ImageHashHelper", "GetAvgHash", "bitmaps;" + bitmaps + ";bitmapl:" + bitmapl + ";bitmapw:" + bitmapw);

                        Bitmap newBitmap = ToGray(GetThumbImage(bitmap, bitmapl, bitmapw));

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

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

                        Log.write("ImageHashHelper", "GetAvgHash", "bitmap.Width;" + newBitmap.Width + ";bitmap.Height:" + newBitmap.Height);

                        int codeMack = 0;

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

                        {

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

                            {

                                if (isInTriangle2(lx[0], ly[0], lx[1], ly[1], lx[2], ly[2], row, col) && isInTriangle2(lx[0], ly[0], lx[3], ly[3], lx[2], ly[2], row, col))

                                {

                                    //标记无效

                                    code[codeMack++] = -1;

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

                                    continue;

                                }

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

                            }

                        }

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

                        //比较像素的灰度

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

                        {

                            if( code[codeMack] == -1)continue;

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

                        }

                    }

                    catch (Exception ex)

                    {

                        Log.write("ImageHashHelper", "GetAvgHash", "" + ex.ToString());

                    }

                    //返回结果

                    return code;

                }

                /// <summary>

                /// 对两个AvgHash进行比较

                /// </summary>

                /// <returns></returns>

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

                {

                    int v = 0;

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

                    {

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

                        {

                            v++;

                        }

                    }

                    return v;

                }

                /// <summary>

                /// 对两个AvgHash进行比较

                /// </summary>

                /// <returns></returns>

                /// 移除了去取均值的功能

                public static int getAvg(int[] code)

                {

                    int sum = 0;

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

                    {

                        if (code[i] == -1) continue;

                        sum += code[i];

                    }

                    return sum;

                }

                public static int getAvg4User(Bitmap bitmap)

                {

                    return getAvg(GetAvgHash(bitmap));

                }

                public static int getAvg4UserInArea(Bitmap bitmap)

                {

                    return getAvg(GetAvgHash(bitmap, mathXList, mathXList));

                }

                #endregion

                #region 判断点是否在四边形内  (判断是否为凸四边形)

                static double Xproduct(double ax, double ay, double bx, double by, double cx, double cy)

                {

                    return (bx - ax) * (cy - ay) - (cx - ax) * (by - ay);

                }

                public static bool isInTriangle2(double ax, double ay, double bx, double by, double cx, double cy, double dx, double dy)

                {

                    return (Xproduct(ax, ay, bx, by, dx, dy) >= 0 && Xproduct(bx, by, cx, cy, dx, dy) >= 0 && Xproduct(cx, cy, ax, ay, dx, dy) >= 0) ||

                          (Xproduct(ax, ay, bx, by, dx, dy) <= 0 && Xproduct(bx, by, cx, cy, dx, dy) <= 0 && Xproduct(cx, cy, ax, ay, dx, dy) <= 0);

                }

                #endregion

                public static void getMathPoint(List<int> pointXList, List<int> pointYList)

                {

                    if (pointYList.Count >= 4 && pointXList.Count >= 4)

                    {

                        mathXList = new List<int>();

                        mathYList = new List<int>();

                        int maxY = pointYList[0];

                        int maxX = pointXList[0];

                        int minX = pointXList[0];

                        int minY = pointYList[0];

                        foreach (int i in pointXList)

                        {

                            if (i > maxX)

                            {

                                maxX = i;

                            }

                            if (i < minX)

                            {

                                minX = i;

                            }

                        }

                        foreach (int j in pointYList)

                        {

                            if (j > maxY)

                            {

                                maxY = j;

                            }

                            if (j < minY)

                            {

                                minY = j;

                            }

                        }

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

                        {

                            pointXList[i] -= minX;

                        }

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

                        {

                            pointYList[i] -= minY;

                        }

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

                        {

                            if (pointXList[i] == 0)

                            {

                                mathXList.Add(0);

                            }

                            else

                            {

                                mathXList.Add(ImageHashHelper.bitmapw * ImageHashHelper.bitmapw / pointXList[i]);

                            }

                        }

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

                        {

                            if (pointYList[i] == 0)

                            {

                                mathYList.Add(0);

                            }

                            else

                            {

                                mathYList.Add(ImageHashHelper.bitmapl * ImageHashHelper.bitmapl / pointYList[i]);

                            }

                        }

                    }

                    else

                    {

                        return;

                    }

                }

            }

    }

    相关文章

      网友评论

          本文标题:C#实现哈希均值算法处理图片

          本文链接:https://www.haomeiwen.com/subject/zwszqktx.html