Bootstrap

通过直方图比较两个图像相似度原理及OpenCV实现(C#)

原理

H 1 H_1 H1 H 2 H_2 H2为两幅图像计算出的直方图数组, H ˉ \bar{H} Hˉ 为数组均值

相关性比较
在这里插入图片描述
由公式可知相关性比较计算结果越接近1,两个图像越相似

直方图相交法
在这里插入图片描述
取数组相同位置最小值求和,该方法不会将计算结果归一化
如模板图像为A、比较图像为B,C;B、C计算结果越大,则其和A越相似

卡方计算
在这里插入图片描述
由公式可知,卡方计算结果越接近0,两个图像越相似

巴氏距离计算
在这里插入图片描述
由公式知,计算结果越接近0,两个图像越相似

API
public static double CompareHist(InputArray h1, InputArray h2, HistCompMethods method);

参数:
InputArray h1:图像1直方图
InputArray h2:图像2直方图
HistCompMethods method:直方图比较方法
返回值:计算结果

案例演示

在这里插入图片描述

Mat mat_A = Cv2.ImRead(@"C:\Users\Aron\Desktop\01\A.jpg", ImreadModes.AnyColor);
Mat mat_B = Cv2.ImRead(@"C:\Users\Aron\Desktop\01\B.jpg", ImreadModes.AnyColor);

Mat[] mat_As;
Mat[] mat_Bs;
Cv2.Split(mat_A, out mat_As);//拆分通道              
Cv2.Split(mat_B, out mat_Bs);//拆分通道

int[] histSize = { 256 };//直方图数组大小
Rangef[] histRange = { new Rangef(0, 256) }; //直方图的像素范围    

//直方图输出数组
Mat hist_A = new Mat();
Mat hist_B = new Mat();

bool uniform = true, accumulate = false;
Cv2.CalcHist(mat_As, new int[] { 0,1,2 }, null, hist_A, 1, histSize, histRange, uniform, accumulate);
Cv2.CalcHist(mat_Bs, new int[] { 0,1,2 }, null, hist_B, 1, histSize, histRange, uniform, accumulate);

//归一化,排除图像分辨率不一致的影响
Cv2.Normalize(hist_A, hist_A, 0, 1, NormTypes.MinMax, -1, null);
Cv2.Normalize(hist_B, hist_B, 0, 1, NormTypes.MinMax, -1, null);

var result = Cv2.CompareHist(hist_A, hist_B, HistCompMethods.Correl);//相关性比较

//绘制文字
Point p1 = new Point(50, 80);
Scalar scalar = new Scalar(0, 0, 255);
Cv2.PutText(mat_B, "correlation:" + Math.Round(result,6).ToString(), p1, HersheyFonts.HersheyDuplex, 2, scalar, 4);

picBox_Display.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat_A);
picBox_After.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat_B);

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上图测试结果,使用相关性比较方法,相似的图像计算值接近1,不相似的图像计算值接近0

需要注意的是直方图比较图像的相似度时,在计算上未考虑像素的空间位置,如下图,当图像旋转时,计算结果仍然不变;同理在某些极端情况下,有可能两个图像直方图完全一致,但是两个图像完全不相似的情况,因此直方图比较图像相似度仅适合环境和特征物体种类固定的图像比对。

在这里插入图片描述

补充说明:
本案例在.NET使用的OpenCV库为OpenCvSharp4

.NET 环境的OpenCv库

;