在网上找了一圈资料之后:比较两个图片相似度方法主要有2种
1.遍历图片每个像素,计算方差进行比较。这个没有去试,直接遍历Bitmap所有获取像素点,性能上不会好到哪去的。
2.也是使用方差,但是是使用两个图片的总方差进行比较(因为项目中主要是用来自动裁剪图片中相似度高的部分,经测试,比较出来的结果还是可以接受的)
variance是计算方差的方法,cutBitmapByVariance方法是具体使用,会涉及到了其它很多的业务代码,那些就不贴出来了
/// <summary>
/// 计算方差
/// datas为Bitmap中的byte
/// </summary>
private static double variance(byte[] datas)
{
double variance = 0;
int avg = datas.Sum(x => x) / datas.Length;
foreach (byte data in datas)
{
variance += (double)((double)(data - avg)) * (data - avg) / datas.Length;
}
return variance;
}
/// <summary>
/// 根据方差计算相似度
/// </summary>
public static List<JudgeInfoModel> cutBitmapByVariance(FileStream fs,List<JudgeInfoModel> lstTimes,bool isMirror=false)
{
List<JudgeInfoModel> lstTempTimes = new List<JudgeInfoModel>(lstTimes);
long totalImage = fs.Length / GlobalData.imageSize;
int forCount = (int)totalImage / GlobalData.perCount;
fs.Seek(0, SeekOrigin.Begin);
byte[] startBytes = new byte[GlobalData.perCount*GlobalData.imageSize];
fs.Read(startBytes, 0, startBytes.Length);
double startVariance = variance(startBytes);
double xx = 10;
for (int i = 1; i < forCount; i++)
{
fs.Seek(i*GlobalData.perCount*GlobalData.imageSize, SeekOrigin.Begin);
byte[] tempBytes = new byte[GlobalData.perCount * GlobalData.imageSize];
fs.Read(tempBytes, 0, tempBytes.Length);
double tempVariance = variance(tempBytes);
if (Math.Abs(startVariance - tempVariance) <= xx) //如果相似
{
int index = lstTempTimes.FindIndex(x => x.X == i * GlobalData.perCount);
int cutCount = lstTempTimes.Count - index < GlobalData.perCount ? lstTempTimes.Count - index : GlobalData.perCount;
lstTempTimes.RemoveRange(index, cutCount);
}
startVariance = tempVariance;
}
return lstTempTimes;
}
3.使用直方图比较(应用了算法计算。这个方法比较出来的结果会比较准确)
使用了OpenCv,首先需要添加依赖包OpenCvSharp4.Extensions和OpenCvSharp4.Windows
以下是主要代码
public static double compareHist(Bitmap bBitmap, Bitmap cBitmap)
{
Mat bMat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bBitmap);
Mat cMat = OpenCvSharp.Extensions.BitmapConverter.ToMat(cBitmap);
Cv2.CvtColor(bMat, bMat, ColorConversionCodes.BGR2HSV);
Cv2.CvtColor(cMat, cMat, ColorConversionCodes.BGR2HSV);
int h_bins = 50;
int s_bins = 60;
int[] histSize = { h_bins, s_bins };
Rangef h_ranges = new Rangef(0, 256);
Rangef s_ranges = new Rangef(0, 180);
Rangef[] ranges = { h_ranges, s_ranges };
int[] channels = { 0, 1 };
Mat hist_bMat = new Mat();
Mat hist_cMat = new Mat();
Cv2.CalcHist(new Mat[] { bMat }, channels, new Mat(), hist_bMat, 2, histSize, ranges, true, false);
Cv2.Normalize(hist_bMat, hist_bMat, 0, 1, NormTypes.MinMax, -1, new Mat());
Cv2.CalcHist(new Mat[] { cMat }, channels, new Mat(), hist_cMat, 2, histSize, ranges, true, false);
Cv2.Normalize(hist_cMat, hist_cMat, 0, 1, NormTypes.MinMax, -1, new Mat());
double result = Cv2.CompareHist(hist_bMat, hist_cMat, HistCompMethods.Bhattacharyya);
return result;
}