C++OpenCV绘制直方图

1.直方图概述

直方图是变量分布的统计图,他可以让我们能够了解数据的密度估计和概率分布。

2.原理理解

首先创建三个矩阵来处理每个输入图像通道。并用split来对通道分离,如下所示:

vector<Mat> bgr;
split(image, bgr);

然后定义直方图的区间数:

int numbins = 256;

定义变量范围,并创建3个矩阵来存储每个直方图

float range[] = { 0, 256 };
const float* histRange = { range };
Mat b_hist, g_hist, r_hist;

使用calcHist函数计算直方图:

calcHist(&bgr[0], 1, 0, Mat(), b_hist, 1, &numbins, &histRange);
calcHist(&bgr[1], 1, 0, Mat(), g_hist, 1, &numbins, &histRange);
calcHist(&bgr[2], 1, 0, Mat(), r_hist, 1, &numbins, &histRange);

在计算每个通道直方图之后,还要绘制它并显示给用户。因此创建一个512*300像素的彩色图像:

int width = 512;
int height = 300;
Mat histImage(height, width, CV_8UC3, Scalar(20, 20, 20));
	

在直方图绘制到图像之前,我们会在最小值0和最大值之间标准化直方图矩阵,最大值与输出直方图图像的高度相同:

//将图像直方图的高度标准化为与输出直方图的高度一样
normalize(b_hist, b_hist, 0, height, NORM_MINMAX);
normalize(g_hist, g_hist, 0, height, NORM_MINMAX);
normalize(r_hist, r_hist, 0, height, NORM_MINMAX);

现在,我们从区间0-1绘制一条线,以此类推。之后,计算有多少像素在每个区间之间,然后通过将宽度除以区间数来计算binStep变量。从水平位置i-1到i绘制每条小线,垂直位置是相应的i中的直方图值,并使用彩色通道绘制:

int binStep = cvRound((float)width / (float)numbins);
for (int i = 1; i < numbins; i++)
{
    line(histImage, Point(binStep * (i - 1), height - cvRound(b_hist.at<float>(i - 1))),
		Point(binStep * (i), height - cvRound(b_hist.at<float>(i))),
		Scalar(255, 0, 0));
	line(histImage, Point(binStep * (i - 1), height - cvRound(g_hist.at<float>(i - 1))),
		Point(binStep * (i), height - cvRound(g_hist.at<float>(i))),
		Scalar(0, 255, 0));
	line(histImage, Point(binStep * (i - 1), height - cvRound(r_hist.at<float>(i - 1))),
		Point(binStep * (i), height - cvRound(r_hist.at<float>(i))),
		Scalar(0, 0, 255));
}

3.完整代码

myApi.h文件

#pragma once
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

class myFun
{
public:
	Mat drawHist(Mat &image);
};

myApi.cpp文件

#include"myApi.h"

Mat myFun::drawHist(Mat& image)
{
	vector<Mat> bgr;
	split(image, bgr);
	//imshow("b", bgr[0]);
	int numbins = 256;
	float range[] = { 0, 256 };
	const float* histRange = { range };
	Mat b_hist, g_hist, r_hist;
	calcHist(&bgr[0], 1, 0, Mat(), b_hist, 1, &numbins, &histRange);
	calcHist(&bgr[1], 1, 0, Mat(), g_hist, 1, &numbins, &histRange);
	calcHist(&bgr[2], 1, 0, Mat(), r_hist, 1, &numbins, &histRange);

	int width = 512;
	int height = 300;
	Mat histImage(height, width, CV_8UC3, Scalar(20, 20, 20));
	
	//将图像直方图的高度标准化为与输出直方图的高度一样
	normalize(b_hist, b_hist, 0, height, NORM_MINMAX);
	normalize(g_hist, g_hist, 0, height, NORM_MINMAX);
	normalize(r_hist, r_hist, 0, height, NORM_MINMAX);

	int binStep = cvRound((float)width / (float)numbins);
	for (int i = 1; i < numbins; i++)
	{
		line(histImage, Point(binStep * (i - 1), height - cvRound(b_hist.at<float>(i - 1))),
			Point(binStep * (i), height - cvRound(b_hist.at<float>(i))),
			Scalar(255, 0, 0));
		line(histImage, Point(binStep * (i - 1), height - cvRound(g_hist.at<float>(i - 1))),
			Point(binStep * (i), height - cvRound(g_hist.at<float>(i))),
			Scalar(0, 255, 0));
		line(histImage, Point(binStep * (i - 1), height - cvRound(r_hist.at<float>(i - 1))),
			Point(binStep * (i), height - cvRound(r_hist.at<float>(i))),
			Scalar(0, 0, 255));
	}
	//imshow("histImage", histImage);
	return histImage;
}

主函数main.cpp文件

#include<opencv2/opencv.hpp>
#include<iostream>
#include"myApi.h"

using namespace cv;
using namespace std;


int main(int argc, char** argv)
{
	Mat src = imread("F:/testImage/test.png");
	if (!src.data)
	{
		cout << "图片没有找到" << endl;
		return -1;
	}
	imshow("src", src);
	myFun mf;
	Mat hist = mf.drawHist(src);
	imshow("histImage", hist);

	waitKey(0);
	return 0;
}

4.实验结果

 

 

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI炮灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值