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;
}