opencv学习笔记(二十五)直方图计算

1.基本概念

(1)bin指的是直方图每个级数范围,可以每个数为一个级别,也可以一个范围为一个级别统计频率,一个级别为一个bin。

(2)dims 表示维度,对灰度图像来说只有一个通道值dims=1

(3)range 表示值得范围,灰度值范围为[0~255]之间

(4)对图像梯度、每个像素的角度、等一切图像的属性值,我们都可以建立直方图。这个才是直方图的概念真正意义,不过是基于图像像素灰度直方图是最常见的。

2.相关API

(1)void split(const Mat& src,Mat *mvBegin),作用是:把多通道图像分为多个单通道图像

src:需分离的图像矩阵

*mvBegin:可以是Mat数组的首地址,或者一个vector<Mat>对象

(2)void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false );作用:计算图像直方图

参数解释参考:https://blog.csdn.net/sydnash/article/details/7451039

arrays:输入的图像的指针,可以是多幅图像

narrays:输入的图像的个数

channels:用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通和第一副图像的第2和第0个通道来计算直方图。(存在争议,不过个人认为该解释正确)

mask:掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。一般直接用Mat()

hist:计算出来的直方图

dims:计算出来的直方图维数

*histSIze:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。即级别数。

**range:用来进行统计的范围。比如 float rang1[] = {0, 20}; float rang2[] = {30, 40}; const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计

uniform:每一个竖条的宽度是否相等

accumulate:该特性允许您从多个直方图中计算单个直方图数组的集合,一般不用取false

3.代码实现

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;

//直方图计算
char inputName[] = "input name";
char outputName[] = "output name";
int main()
{
	Mat src, dst,srcGray;
	src = imread("D:/demo.jpg");
	if (src.empty())
	{
		cout << "找不到图像" << endl;
		return -1;
	}
	namedWindow(inputName, CV_WINDOW_AUTOSIZE);	
	namedWindow(outputName, CV_WINDOW_AUTOSIZE);
	imshow(inputName, src);
	//分通道显示
	vector<Mat> bgrChannels;
	split(src, bgrChannels);

	//计算直方图
	int c = 1;
	int histSize[] = {255};
	const float range[] = {0,256};
	const float *histRange = { range };
	Mat bHist, gHist, rHist;
	calcHist(&bgrChannels[0], 1 ,0, Mat(), bHist, 1, histSize, &histRange, true, false);//channel为图像的第一通道取0
	calcHist(&bgrChannels[1], 1, 0, Mat(), gHist, 1, histSize, &histRange, true, false);
	calcHist(&bgrChannels[2], 1, 0, Mat(), rHist, 1, histSize, &histRange, true, false);

	//归一化,控制数值在0到400之间
	int histH = 400;
	int histW = 512;
	int binW = histW / 255;//每条宽度
	Mat histImage(histW, histH, CV_8UC3, Scalar(0, 0, 0));
	normalize(bHist, bHist, 0, histH, NORM_MINMAX, -1, Mat());
	normalize(gHist, gHist, 0, histH, NORM_MINMAX, -1, Mat());
	normalize(rHist, rHist, 0, histH, NORM_MINMAX, -1, Mat());

	//构建
	for (int i = 1; i < 255; i++)
	{
		line(histImage, Point((i - 1)*binW, histH - cvRound(bHist.at<float>(i - 1))), 
			Point((i)*binW, histH - cvRound(bHist.at<float>(i))), Scalar(255, 0, 0), 2);//cvRound():返回跟参数最接近的整数值,即四舍五入
		line(histImage, Point((i - 1)*binW, histH - cvRound(gHist.at<float>(i - 1))),
			Point((i)*binW, histH - cvRound(gHist.at<float>(i))), Scalar(0, 255, 0), 2);
		line(histImage, Point((i - 1)*binW, histH - cvRound(rHist.at<float>(i - 1))),
			Point((i)*binW, histH - cvRound(rHist.at<float>(i))), Scalar(0, 0, 255), 2);
	}
	imshow(outputName, histImage);
	waitKey(0);
	return 0;
}

其中for循环中使用line方法进行画线,由于初始坐标点左上角为(0,0),所以,用整体高度减去直方图值才可以直观显示频率大小,出现频率越高那么像素值越大,相减后值越小,画图直观就在越靠近图像上方,借此做出图像的直方图。

4.运行结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值