[OpenCV学习日记-java]-15-图像直方图

图像直方图

图像直方图是图像的统计学特征


直方图的计算与显示

对图像进行统计,并且绘制他们各个灰度等级对应的直方图就可以的得到图像的直方图

计算直方图的api如下

calcHist(List<Mat> images, MatOfInt channels, Mat mask, Mat hist, MatOfInt histSize, MatOfFloat ranges)
  • images:输入图像,类型必须相同
  • channels:通道索引列表
  • mask:遮罩层
  • hist:计算得到直方图数据,
  • histSize:直方图的大小
  • ranges:直方图的取值范围

实现代码如下

Mat m = Imgcodecs.imread("C:\\test\\ecy.jpg");
HighGui.imshow("原图",m);

//灰度
Mat m1 = new Mat();
Imgproc.cvtColor(m,m1,Imgproc.COLOR_BGR2GRAY);
HighGui.imshow("灰度",m1);

//添加图像
List<Mat> images = new ArrayList<>();
images.add(m1);


//计算直方图
Mat hist = new Mat();
Imgproc.calcHist(images,new MatOfInt(0),new Mat(),hist,new MatOfInt(256),new MatOfFloat(0,255));

//数值归一化
Core.normalize(hist,hist,0,255,Core.NORM_MINMAX);
int h = hist.rows();

Mat m2 = new Mat(new Size(300,300),m.type(),new Scalar(200,200,200));
float[] histdata = new float[256];

//获取数据
hist.get(0,0,histdata);

//绘制直方图
int x = 20;
int y = 280;//图像区域位置
Imgproc.line(m2,new Point(x,0),new Point(x,y),new Scalar(255,0,0));
Imgproc.line(m2,new Point(x,y),new Point(400,y),new Scalar(255,0,0));

for (int i = 0; i < h - 1; i++) {
    int y1 = (int) histdata[i];
    Rect rect = new Rect();
    rect.x = x+i;
    rect.y = y-y1;
    rect.width= 1;
    rect.height = y1;
    Imgproc.rectangle(m2,rect.tl(),rect.br(),new Scalar(15,15,15));

}

HighGui.imshow("直方图",m2);

[OpenCV学习日记-java]-15-图像直方图


在此之后 我封装了一个Api函数
方便后面直接调用

    /**
     * @param name 显示直方图的窗口名
     * @param gray 灰度图像
     * @return 返回计算后的直方图 hist
     */
    public static Mat showHist(String name,Mat...gray){

    //添加图像
    List<Mat> images = new ArrayList<>(Arrays.asList(gray));  
    
    //计算直方图
    Mat hist = new Mat();
    Imgproc.calcHist(images,new MatOfInt(0),new Mat(),hist,new MatOfInt(256),new MatOfFloat(0,255));

    //数值归一化
    Core.normalize(hist,hist,0,255,Core.NORM_MINMAX);
    int h = hist.rows();

    //创建背景
    Mat histImg = new Mat(new Size(300,300),CvType.CV_8UC3,new Scalar(200,200,200));
    float[] histdata = new float[256];

    //获取直方图数据
    hist.get(0,0,histdata);
    int x = 20;
    int y = 280;
    

    //绘制直方图
    Imgproc.line(histImg,new Point(x,0),new Point(x,y),new Scalar(255,0,0));
    Imgproc.line(histImg,new Point(x,y),new Point(400,y),new Scalar(255,0,0));

    for (int i = 0; i < h - 1; i++) {
        int y1 = (int) histdata[i];
        Rect rect = new Rect();
        rect.x = x+i;
        rect.y = y-y1;
        rect.width= 1;
        rect.height = y1;
        Imgproc.rectangle(histImg,rect.tl(),rect.br(),new Scalar(15,15,15));

    }

    HighGui.imshow(name,histImg);
    return hist;
}

直方图均衡化

直方图均衡化的本质是改变图像的灰度分布,或者说改变图像直方图灰度分布,通过累计灰度级别与相关的数学变换公式,来改变原有的图像直方图灰度分布,然后用改变之后的灰度值重建图像,从而达到调整亮度和对比度的目的。

直方图均衡化Api如下

equalizeHist(Mat src, Mat dst)
  • src:输入 8位灰度图像
  • dst:输出 8位灰度图像

[OpenCV学习日记-java]-15-图像直方图
实现代码如下
showHist 函数是上面整合出来的

Mat m = Imgcodecs.imread("C:\\test\\ecy.jpg");

//灰度
Mat m1 = new Mat();
Imgproc.cvtColor(m,m1,Imgproc.COLOR_BGR2GRAY);

HighGui.imshow("原图灰度",m1);
showHist("原图直方图",m1);

Mat m2 = new Mat();
Imgproc.equalizeHist(m1,m2);//均衡化

HighGui.imshow("均衡化后灰度",m2);
showHist("均衡化后直方图",m2);

直方图比较

直方图的比较可以叫做计算直方图的距离

下面是比较的Api

public static double compareHist(Mat H1, Mat H2, int method){}
  • H1:第一个输入直方图的数据
  • H2:第二个输出直方图的数据
  • method:方法
  • @return 返回比较结果

直方图的比较方法有下面几种

  • HISTCMP_CORREL = 0 相关性
  • HISTCMP_CHISQR = 1 卡方
  • HISTCMP_INTERSECT = 2 相交
  • HISTCMP_BHATTACHARYYA = 3 巴氏距离
  • HISTCMP_HELLINGER = HISTCMP_BHATTACHARYYA 海灵格距离(和巴氏一样)
  • HISTCMP_CHISQR_ALT = 4 可选卡方
  • HISTCMP_KL_DIV = 5 K-L散度

下面通过代码演示
结果图示和上一个一样

Mat m = Imgcodecs.imread("C:\\test\\ecy.jpg");

//灰度
Mat m1 = new Mat();
Imgproc.cvtColor(m,m1,Imgproc.COLOR_BGR2GRAY);
HighGui.imshow("原图灰度",m1);

Mat hist1 = showHist("原图直方图",m1);

Mat m2 = new Mat();
Imgproc.equalizeHist(m1,m2);

HighGui.imshow("均衡化后灰度",m2);

Mat hist2 = showHist("均衡化后直方图",m2);

//开始计算距离
double d;
d = Imgproc.compareHist(hist1,hist2,Imgproc.HISTCMP_CORREL);
System.out.println("相关性:"+d);
d = Imgproc.compareHist(hist1,hist2,Imgproc.HISTCMP_CHISQR);
System.out.println("卡方:"+d);
d = Imgproc.compareHist(hist1,hist2,Imgproc.HISTCMP_INTERSECT);
System.out.println("巴氏距离:"+d);
d = Imgproc.compareHist(hist1,hist2,Imgproc.HISTCMP_HELLINGER);
System.out.println("海灵格距离:"+d);
d = Imgproc.compareHist(hist1,hist2,Imgproc.HISTCMP_CHISQR_ALT);
System.out.println("可选卡方:"+d);
d = Imgproc.compareHist(hist1,hist2,Imgproc.HISTCMP_KL_DIV);
System.out.println("K-L散度:"+d);

输出结果

相关性:0.01892496480027808
卡方:171801.74023263433
巴氏距离:9967.928175032139
海灵格距离:0.4559564084806153
可选卡方:14483.22276347663
K-L散度:120281.57980569218

上一篇[OpenCV学习日记-java]-14-轮廓分析

[OpenCV学习日记-java]-15-图像直方图[OpenCV学习日记-java]-15-图像直方图 Timeless小帅 发布了40 篇原创文章 · 获赞 38 · 访问量 2万+ 私信 关注
上一篇:blur()低通滤波


下一篇:open-cv 教程