详解什么叫二维直方图,并利用OpenCV的函数calcHist()绘制图像的H-S二维直方图

很多书籍与技术网文在对二维直方图的介绍中,都是说函数calcHist()可以计算图像的H-S二维直方图,然后给个用函数calcHist()计算图像H-S二维直方图的代码就完事了,看完之后,大家还是不知道图像的二维直方图究竟是怎么回事。

本篇博文昊虹君为大家详细介绍究竟图像的二维直方图的概念是什么,以及二维直方图矩阵中每个数值究竟是怎样计算得到的。

图像的二维直方图的概念:图像的二维直方图是图像在两个维度上的直方图联合统计的结果。

上面这句话相信大家看了还是不明白图像的二维直方图是怎么计算得到的。

举个简单的例子来说明这个问题。

设图像A有两个通道,其两个通道的数据分别如下:

在这里插入图片描述

利用OpenCV的函数calcHist()计算上面两个通道的二维直方图的C++代码如下:

//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术

//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询

//OpenCV版本 OpenCV3.0

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;


int main()
{
	
	Mat Image1(2, 3, CV_8UC2, cv::Scalar(0, 0));

	cv::Mat A1 = (cv::Mat_<uchar>(2, 3) << 1, 1, 1,
		2, 2, 2);

	cv::Mat A2 = (cv::Mat_<uchar>(2, 3) << 3, 3, 3,
		2, 2, 2);

	std::vector<cv::Mat> A_plane;

	A_plane.push_back(A1);
	A_plane.push_back(A2);


	cv::merge(A_plane, Image1);


	int channels[] = { 0, 1 };
	int histSize[] = { 2, 3 };
	float Ranges_1[] = { 0, 4 };
	float Ranges_2[] = { 0, 6 };
	const float *ranges[] = { Ranges_1, Ranges_2 };

	Mat dstHist;

	calcHist(&Image1, 1, channels, Mat(), dstHist, 2, histSize, ranges, true, false);

	cout << dstHist << endl << endl;

	
	return 0;
}

 运行结果如下:

在这里插入图片描述

现在的问题是上面这个二维直方图矩阵dstHist的每一个元素的数据值是怎么计算得到的?
很多书籍与技术网文并未讲解这个问题。
昊虹君在这篇博文中就给大家详细讲解下。
关于这个问题详细的讲解请大家访问本博文的原文查看,
本博文的原文链接:
https://www.hhai.cc/thread-209-1-1.html

明白二维直方图是怎么回事之后,接下来我们利用OpenCV的函数calcHist()绘制图像的H-S二维直方图。

对于彩色图像,我们通常需要同时考虑图像的色调(hue)和饱和度(saturation),所以有时候我们需要计算图像的“色调-饱和度二维直方图”,即H-S直方图。

下面是利用OpenCV的函数calcHist()绘制彩色图像H-S直方图的C++示例代码。
代码中用到的图像下载链接:https://pan.baidu.com/s/1I23cagDGV08jp3F-pCizMQ?pwd=a7r7

//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术

//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询

//OpenCV版本 OpenCV3.0

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;


int main()
{
        Mat srcImage = imread("E:/material/images/2022/2022-12/view1.jpg");
        imshow("【原图】", srcImage);
 
        Mat hsvImage;
 
        //因为要计算H-S的直方图,所以需要先进行颜色空间的转换
        cvtColor(srcImage, hsvImage, CV_BGR2HSV);
 
 
        //计算H-S二维直方图的参数配置
        int channels[] = { 0, 1 };
        Mat dstHist;
        int histSize[] = { 30, 32 };
        float HRanges[] = { 0, 181 };
        float SRanges[] = { 0, 256 };
        const float *ranges[] = { HRanges, SRanges };
 
        //参数配置好后,就可以调用calcHis函数计算直方图数据了
        calcHist(&hsvImage, 1, channels, Mat(), dstHist, 2, histSize, ranges, true, false);
 
        //calcHist函数调用结束后,dstHist变量中将储存直方图数据 
 
        ///接下来绘制直方图
        //首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像  
        Mat drawImage = Mat::zeros(Size(300, 320), CV_8UC3);
 
        //因为数据矩阵中的某个值的总个数可能会超出所定义的图像的尺寸,所以要对个数进行归一化处理  
        //先用 minMaxLoc函数来得到计算直方图中的最大数据,这个函数的使用方法大家一看函数原型便知
        double g_dHistMaxValue;
        minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);
 
        //遍历直方图数据,对数据进行归一化和绘图处理 
        for (int i = 0; i < 30; i++)
        {
                for (int j = 0; j < 32; j++)
                {
                        int value = cvRound(dstHist.at<float>(i, j) * 255/ g_dHistMaxValue);
 
                        rectangle(drawImage, Point(10 * i, j * 10), Point((i + 1) * 10 - 1, (j + 1) * 10 - 1), Scalar(0,0,value), -1);
                }
        }
 
        imshow("【H-S二维联合直方图】", drawImage);
 
        waitKey(0);
 
        return 0;
}

代码中写了详细的注释,大家应该不难看懂,只是对下面两句代码补充说明一下:

int value = cvRound(dstHist.at<float>(i, j) * 255/ g_dHistMaxValue);
rectangle(drawImage, Point(10 * i, j * 10), Point((i + 1) * 10 - 1, (j + 1) * 10 - 1), Scalar(0,0,value), -1);

1 这两句代码把hist里的数据归一化到0~255。

2 这两句代码把二维直方图进行了按比例放大绘制,本来hist的大小是30×32的,但在绘制的时候我们把其放大到了300×320,这是为了便于我们观察。

3 我们是用三通道的彩色图绘制二维直方图的,这样做也是便于我们肉眼观察,每一块矩形我们都用不同程度的红色来绘制,其红色的程度值就是hist里对应点进行归一化后的值。

上面代码的运行结果如下:
在这里插入图片描述

在绘图方面,还是Python的Matplotlib方便,所以利用Python-OpenCV计算并绘制图像的H-S二维直方图的代码就很简单了。
代码如下:
代码中用到的图像下载链接:https://pan.baidu.com/s/1I23cagDGV08jp3F-pCizMQ?pwd=a7r7

# -*- coding: utf-8 -*-
# 出处:昊虹AI笔记网(hhai.cc)
# 用心记录计算机视觉和AI技术

# 博主微信/QQ 2487872782
# QQ群 271891601
# 欢迎技术交流与咨询

# OpenCV的版本为4.4.0

import cv2 as cv
from matplotlib import pyplot as plt
import sys

if __name__ == '__main__':
    # 读取图像road.jpg
    image = cv.imread('E:/material/images/2022/2022-12/view1.jpg')
    # 判断图片是否读取成功
    if image is None:
        print('Failed to read image.')
        sys.exit()
    # 将图像的颜色空间从BGR转为HSV
    image_hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)

    # 计算2D直方图
    image_hist = cv.calcHist([image_hsv], [0, 1], None, [181, 256], [0, 181, 0, 256])
    # 展示图像及直方图结果
    cv.imshow('Origin Image', image)
    plt.imshow(image_hist, cmap='Reds', interpolation='nearest', origin='lower')
    plt.show()

    cv.waitKey(0)
    cv.destroyAllWindows()

运行结果如下:

在这里插入图片描述

之所以背景不是白色,而是略带红色,是因为颜色映射空间设置为红色,所以背景色为最浅的红色。详情见Matplotlib的使用介绍博文:https://www.hhai.cc/thread-210-1-1.html 

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值