C#,图像的平均哈希(Average hash),感知哈希(Perceptual hash)与差异哈希(Difference hash)算法与源代码

C#,图像的平均哈希(Average hash),感知哈希(Perceptual hash)与差异哈希(Difference hash)算法与源代码_第1张图片

 

一、均值哈希(Average hash)

均值哈希算法是各像素灰度值与灰度均值的差异获得的哈希值。

算法步骤是:(1)图像转为灰度值;(2)计算灰度平均值;(3)逐个像素计算差异获得哈希值。

/// 
/// 均值计算
/// 
/// 
/// 
public static double Mean(double[,] A)
{
    int M = A.GetLength(0);
    int N = A.GetLength(1);
    double mean = 0.0;
    for (int y = 0; y < M; y++)
    {
        for (int x = 0; x < N; x++)
        {
            mean += A[y, x];
        }
    }
    mean /= (M * N);
    return mean;
}

均值哈希常常用于缩略图的比较。

/// 
/// 图像均值哈希算法(Average Hash)
/// 
/// 
/// 
public static byte[,] aHash(double[,] A)
{
    int M = A.GetLength(0);
    int N = A.GetLength(1);

    double mean = Mean(A);

    byte[,] r = new byte[M, N];
    for (int y = 0; y < M; y++)
    {
        for (int x = 0; x < N; x++)
        {
            r[y, x] = (byte)((A[y, x] > mean) ? 1 : 0);
        }
    }
    return r;
}

C#,图像的平均哈希(Average hash),感知哈希(Perceptual hash)与差异哈希(Difference hash)算法与源代码_第2张图片

 

二、感知哈希(Perceptual hash)

感知哈希是图像经过计算离散余弦变换(Discrete Cosine Transform,DCT)之后的值计算得到的哈希值。

DCT变换

DCT变换又称离散余弦变换(DCT for Discrete Cosine Transform)是与傅里叶变换相关的一种变换,
它类似于离散傅里叶变换(DFT for Discrete Fourier Transform),但是只使用实数。
离散余弦变换相当于一个长度大概是它两倍的离散傅里叶变换,
这个离散傅里叶变换是对一个实偶函数进行的(因为一个实偶函数的傅里叶变换仍然是一个实偶函数),
在有些变形里面需要将输入或者输出的位置移动半个单位(DCT有8种标准类型,其中4种是常见的)。

DCT变换原因:DCT变换的时候,滤掉了高频的部分,一般图形高频部分的系数是比较小的,
在量化的时候可以忽略掉,因而还原的时候就是一个反傅里叶变化,就可以得到一个图形。
对于那些颜色比较绚丽的图形,在压缩的时候,高频的系数已经不能忽略了,
如果量化的时候压缩比过高,就可能导致明显的失真。

/// 
/// DCT变换
/// 
/// 
public static double[,] DCT(double[,] A)
{
    int M = A.GetLength(0);
    int N = A.GetLength(1);
    double[,] B = new double[M, N];
    for (int y = 0; y < M; y++)
    {
        for (int x = 0; x < N; x++)
        {
            double ay = (y == 0) ? Math.Sqrt(1.0 / M) : Math.Sqrt(2.0 / M);
            double ax = (x == 0) ? Math.Sqrt(1.0 / N) : Math.Sqrt(2.0 / N);
            double tmp = 0.0;
            for (int yy = 0; yy < M; yy++)
            {
                for (int xx = 0; xx < N; xx++)
                {
                    tmp += A[yy, xx] * Math.Cos((2.0 * yy + 1) * y * Math.PI / (2.0 * M)) * Math.Cos((2.0 * xx + 1) * x * Math.PI / (2.0 * N));
                }
            }
            B[y, x] = ay * ax * tmp;
        }
    }
    return B;
}

/// 
/// DCT逆变换
/// 
/// 
/// 
public static double[,] Inverse_DCT(double[,] B)
{
    int M = B.GetLength(0);
    int N = B.GetLength(1);
    double[,] C = new double[M, N];
    for (int y = 0; y < M; y++)
    {
        for (int x = 0; x < N; x++)
        {
            double tmp = 0.0;
            for (int yy = 0; yy < M; yy++)
            {
                for (int xx = 0; xx < N; xx++)
                {
                    double ay = (yy == 0) ? (1.0 / Math.Sqrt(M)) : Math.Sqrt(2.0 / M);
                    double ax = (xx == 0) ? (1.0 / Math.Sqrt(N)) : Math.Sqrt(2.0 / N);
                    tmp += ay * ax * B[yy, xx] * Math.Cos(Math.PI * (2.0 * y + 1.0) * yy / (2.0 * M)) * Math.Cos(Math.PI * (2.0 * xx + 1.0) * x / (2.0 * N));
                }
            }
            C[y, x] = (tmp);
        }
    }
    return C;
}

无论你改变图片的高宽、亮度甚至颜色,都不会改变感知哈希值。

/// 
/// 图像感知哈希算法(Perceptual Hash)
/// 
/// 
/// 
public static byte[,] pHash(double[,] A)
{
    int M = A.GetLength(0);
    int N = A.GetLength(1);

    double[,] B = DCT(A);
    double mean = Mean(B);

    byte[,] r = new byte[M, N];
    for (int y = 0; y < M; y++)
    {
        for (int x = 0; x < N; x++)
        {
            r[y, x] = (byte)((B[y, x] > mean) ? 1 : 0);
        }
    }
    return r;
}

C#,图像的平均哈希(Average hash),感知哈希(Perceptual hash)与差异哈希(Difference hash)算法与源代码_第3张图片

 

 

三、差异哈希(Difference hash)

计算差异值,获得最后哈希值(与aHash主要区别处)。比较每行左右两个像素,如果左边的像素比右边的更亮(左边像素值大于右边像素值),则记录为1,否则为0。因为每行有9个像素,左右两个依次比较可得出8个值,所以8行像素共可以得出64个值,因此此时哈希值为长度是64的0-1序列。

/// 
/// 图像差异哈希算法(Difference Hash)
/// 
/// 
/// 
public static byte[,] dHash(double[,] A)
{
    int M = A.GetLength(0);
    int N = A.GetLength(1);
    byte[,] r = new byte[M, N];
    for (int y = 0; y < M; y++)
    {
        for (int x = 0; x < (N - 1); x++)
        {
            r[y, x] = (byte)((A[y, x] > A[y, x + 1]) ? 1 : 0);
        }
        r[y, N - 1] = 0;
    }
    return r;
}

POWER BY 联高软件。

你可能感兴趣的:(C#算法演义,Algorithm,Recipes,哈希算法,算法,均值算法)