Unity C#使用pHash算法实现图片相似度计算

1.pHash介绍:

    pHash算法(感知Hash算法)计算图片相似,是通过DCT(离散余弦变换)变换获得图片哈希值然后进行比较,比较方法很多通常采用计算汉明距离或者余弦相似度.

开源pHash源码:http://www.phash.org/

2.pHash计算流程:

1.压缩图片:

    //压缩图片
    Texture2D ReduceSize(Texture2D tex, int size)
    {
        if (tex == null || size <= 0)
        {
            Debug.Log("图片错误");
            return null;
        }
        Texture2D newTexture = new Texture2D(size, size, TextureFormat.RGB24, false);
        float ratioX = tex.width / size;
        float ratioY = tex.height / size;
        Color color;
        for (int i = 0; i < newTexture.height; i++)
        {
            for (int j = 0; j < newTexture.width; j++)
            {
                color = tex.GetPixel(Mathf.RoundToInt(j * ratioX), Mathf.RoundToInt(i * ratioY));
                newTexture.SetPixel(j, i, color);
            }
        }
        return newTexture;

    }

 2.图片转为灰度图:

    //转灰度
    Texture2D Tex2Gray(Texture2D tex)
    {
        Color color;
        for (int i = 0; i < tex.height; i++)
        {
            for (int j = 0; j < tex.width; j++)
            {
                color = tex.GetPixel(j, i);
                float gray = (color.r * 30 + color.b * 59 + color.b * 11) / 100;
                tex.SetPixel(j, i, new Color(gray, gray, gray));
            }
        }
        return tex;
    }

3.DCT变换:

 (1)图片DCT变换公式:

(2)公式可以转化为方便代码计算形式:

(3)dct计算:

        //DCT变换
        float[,] A = creatDCTMatrix(size);
        float[,] Aa = Transpose(A);
        float[,] DCT = Multiply(Multiply(A, ima1F), Aa);

 

    //图片转矩阵
    float[,] image2F(Texture2D tex)
    {
        int size = tex.width;
        float[,] f = new float[size, size];
        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                f[i, j] = tex.GetPixel(i, j).r;
            }
        }
        return f;
    }

    //计算DCT矩阵
    float[,] creatDCTMatrix(int size)
    {
        //Debug.Log((float)Mathf.Cos(Mathf.PI));
        float[,] ret = new float[size, size];
        for (int x = 0; x < size; x++)
        {
            for (int y = 0; y < size; y++)
            {
                float angle = ((y + 0.5f) * Mathf.PI * x / size);
                ret[x, y] = cfunc(x, size) * (float)Mathf.Cos(angle);
            }
        }
        return ret;
    }
    float cfunc(int n, int size)
    {
        if (n == 0)
        {
            return Mathf.Sqrt(1f / size);
        }
        else
        {
            return Mathf.Sqrt(2f / size);
        }

    }

    //矩阵转置
    float[,] Transpose(float[,] C)
    {
        int size = C.GetLength(0);
        float[,] ret = new float[size, size];
        for (var x = 0; x < size; x++)
        {
            for (var y = 0; y < size; y++)
            {
                ret[y, x] = C[x, y];
            }
        }
        return ret;
    }

    //矩阵相乘
    float[,] Multiply(float[,] C1, float[,] C2)
    {
        int size = C1.GetLength(0);
        float[,] ret = new float[size, size];
        for (var y = 0; y < size; y++)
        {
            for (var x = 0; x < size; x++)
            {
                float sum1 = 0;
                for (int k = 0; k < size; k++)   
                {
                    sum1 += C1[x, k] * C2[k, y];
                }
                ret[x, y] = sum1;
            }
        }
        return ret;
    }

4.计算均值:

    //DCT均值
    float averageDCT(float[,] dct)
    {
        int size = dct.GetLength(0);
        float aver = 0;
        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                aver += dct[i, j];
            }
        }
        return aver / (size * size);
    }

 5.计算pHash值:

    //获取当前图片pHash值
    string getHash(float[,] dct, float aver)
    {
        string hash = string.Empty;
        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 8; j++)
            {
                hash += (dct[i, j] >= aver ? "1" : "0");
            }
        }
        return hash;
    }

 6.计算汉明距离:

    //计算两图片哈希值的汉明距离
    float computeDistance(string hash1, string hash2)
    {
        float dis = 0;
        for (int i = 0; i < hash1.Length; i++)
        {
            if (hash1[i] == hash2[i])
            {
                dis++;
            }
        }
        return dis / hash1.Length;
    }

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值