在图像处理中,巴氏系数可用于进行相似图像匹配。
巴氏系数公式:BC(p,q) = ∑√p(x)q(x)
BC为巴氏系数计算结果,p、q分别为两张图像在直方图上同一位置的概率分布,巴氏系数结果范围为(0~1),0为完全不相同,1为完全相同。
原理:先分别求出两张图像在直方图上的概率分布,对相同位置的概率相乘(如果某一图像在该处分布概率为0,则乘积结果也为0,表示在该处完全不相同),然后进行开方,再对开方后结果进行累加。如果两张图像在某一处分布概率完全一样,那么该处计算结果与任意一张图像在该处分布概率相同,如果两张图像完全相同,那么计算结果就是与任意一张图像在直方图上分布概率完全相同,累加结果必定为1。
实现步骤:
1、分别计算两张图像在直方图上概率分布,如果是灰度图,可以直接计算在0~255上分布概率。彩色图像稍微复杂一些,由于彩色图像由RGB三个通道组成,也就是说彩色图像有256*256*256=16777216个灰度级别,显然要对每一个灰度级别进行计算,计算量会非常大,而且计算结果也会因为过度细分而产生较大差异。如果将彩色图像直接转为灰度图,虽然降低了计算量,但会损失掉彩色信息。一般可以将每个通道除以16,从256个灰度级别降低到16个,再将三个通道合并为单一值,将16777216个灰度级别降低到4096个。
转换代码:
int value = (R / 16) * 16 * 15 + (G / 16) * 15 + (B / 16)
当然也可以采用位运算提速:
int value = (R / 16) << 8 | (G / 16) << 4 | (B / 16)
2、计算图像在每个灰度级别上概率分布,统计每个灰度级别包含多少像素,将像素数量除以图像总像素。
P = number / width * height
3、根据巴氏系数计算公式计算匹配结果。
result = Math.sqrt(srcMap.get(i) * destMap.get(i))
实现代码:
public class BhattacharyyaCoefficient {
//singleton
private static BhattacharyyaCoefficient instance = new BhattacharyyaCoefficient();
private BhattacharyyaCoefficient() {}
public static BhattacharyyaCoefficient getInstance() {
return instance;
}
//巴氏系数计算
public double getBhattacharyyaCoefficient (BufferedImage srcImage, BufferedImage destImage) {
Map<Integer, Double> srcMap = tranverseImage(srcImage);
Map<Integer, Double> destMap = tranverseImage(destImage);
double result = getMatchResult(srcMap,destMap);
return result;
}
//计算匹配结果
private double getMatchResult(Map<Integer, Double> srcMap, Map<Integer, Double> destMap) {
double result = 0.0;
for(int i = 0; i < 4096; i++) {
result += Math.sqrt(srcMap.get(i) * destMap.get(i));
}
return result;
}
/**
* 图像RGB值转换,把255压缩到16,返回map
* R = (R / 16) << 8,G = (G / 16) << 4,B = (B / 16)
* @param image
* @return
*/
private Map<Integer, Double> tranverseImage(BufferedImage image){
int width = image.getWidth();
int height = image.getHeight();
Map<Integer, Double> map = new HashMap<>();
for(int i = 0; i < 4096; i++) {
map.put(i, 0.0);
}
for(int i = 0; i < width; i++) {
for(int j = 0; j < height; j++) {
int rgb = image.getRGB(i, j);
int R = (rgb >> 16) & 0xff;
int G = (rgb >> 8) & 0xff;
int B = rgb & 0xff;
int rgbs = tranverseRGBToInt(R, G, B);
map.put(rgbs, map.get(rgbs) + 1);
}
}
int totalPix = height * width;
for(int i = 0; i < 4096; i++) {
double value = map.get(i) / totalPix;
map.put(i, value);
}
return map;
}
/**
* 将rgb值转为压缩后int
* result = (R / 16) << 8 | (G / 16) << 4 | (B / 16)
* @param R
* @param G
* @param B
* @return
*/
private int tranverseRGBToInt(int R,int G,int B) {
int value = (R / 16) << 8 | (G / 16) << 4 | (B / 16);
return value;
}
}
测试:
public class BhattacharyyaTest {
public static void main(String[] args) throws Exception{
File srcFile = new File("E:\\桌面\\test\\原图\\1.JPG");
File destFile = new File("E:\\桌面\\test\\原图\\2.JPG");
BufferedImage srcImage = ImageIO.read(srcFile);
BufferedImage destImage = ImageIO.read(destFile);
double result = BhattacharyyaCoefficient.getInstance().getBhattacharyyaCoefficient(srcImage, destImage);
System.out.println(result);
}
}
测试图像:
运行结果:0.9899107889267019