OpenCV 【九】——calcHist ——图像直方图统计
calcHist() 计算直方图实现(C++、opencv)
1.作用:
图像直方图是对数据集合的一种统计方法,将统计结果分布于一系列预定义的bin中,bin是直方图中经常用到的一个概念,其数值是从数据中计算出的特征统计量,这些数据不仅仅指的灰度值,统计数据可能是任何能有效描述图像的特征包括梯度、方向、色彩或任何其他特征。直方图获得的是数据分布的统计图,通常直方图的维数要低于原始数据。
图像直方图是用以表示数字图像中亮度分布的直方图,标绘了图像中亮度值的像素数。可以借助观察该直方图调整亮度分布,这种直方图中横坐标的左侧为纯黑或较暗区域,右侧为较亮纯白的区域。可用于实现图像的二值化。
假设有一个矩阵包含一张图像信息(灰度值0-255),如下:
2.函数原型
void calcHist( const Mat* images, int nimages,
const int* channels, InputArray mask,
OutputArray hist, int dims, const int* histSize,
const float** ranges, bool uniform=true, bool accumulate=false );
//1.输入的图像数组 2.输入数组的个数 3.通道数 4.掩码 5.直方图
//6.直方图维度 7.直方图每个维度的尺寸数组 8.每一维数组的范围 9.直方图是否是均匀 10.累加标志
参数详解:
images:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U or CV_32F)。同时一副图像可以有多个channes。
nimages:输入图像的个数
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:指的是直方图分成多少个区间,就是 bin的个数。在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
const float** ranges: 统计像素值得区间。比如:
float rang1[] = {0, 20};
float rang2[] = {30, 40};
const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
uniform=true::是否对得到的直方图数组进行归一化处理
accumulate=false:在多个图像时,是否累计计算像素值得个数
1.图像数组 2.图像数组个数 3.图像的通道数 4.图像掩码 5.计算得到的直方图
6.直方图的维度(灰度直方图为1维) 7.直方图每一维度上的数组个数(bin 的个数)
8.每一维进行直方图统计的数组的范围 范围如 0~256 表示统计 0~255的数组 这里注意 (0,256) 包含0而不包含256 包含的是256-1
9.是否均匀的统计
10.累加标志 在多幅图像输入时,对其中数据进行累加,单幅图像不进行累计所以例子中为false
void cv::normalize ( InputArray src,
InputOutputArray dst,
double alpha = 1,
double beta = 0,
int norm_type = NORM_L2,
int dtype = -1,
InputArray mask = noArray()
)
参数解释
. src: 输入数组
. dst: 输出数组,与src有相同的尺寸
. alpha: 将数组归一化范围的最大值,有默认值1
. beta: 归一化的最小值,有默认值0
. norm_type: 归一化方式,可以查看NormTypes()函数查看详细信息,有默认值NORM_L2
. dtype: 当该值取负数时,输出数组与src有相同类型,否则,与src有相同的通道并且深度为CV_MAT_DEPTH(dtype)
. mask: 可选的掩膜版
3.实现:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage;
srcImage = imread("E:\\workspace\\opencv_study\\example\\1.jpg");
if (srcImage.empty())
{
cout << "图像加载失败!" << endl;
return -1;
}
else
cout << "图像加载成功!" << endl << endl;
//分割成三通道图像
vector<Mat> channels;
split(srcImage, channels);
Mat gray_color;
cvtColor(srcImage, gray_color, COLOR_RGB2GRAY);
//设定bin数目
int histBinNum = 255;
//设定取值范围
float range[] = { 0, 255 };
const float* histRange = { range };
bool uniform = true;
bool accumulate = false;
//声明三个通道的hist数组
Mat red_hist, green_hist, blue_hist,gray_hist;
//计算直方图
calcHist(&channels[0], 1, 0, Mat(), red_hist, 1, &histBinNum, &histRange, uniform, accumulate);
calcHist(&channels[1], 1, 0, Mat(), green_hist, 1, &histBinNum, &histRange, uniform, accumulate);
calcHist(&channels[2], 1, 0, Mat(), blue_hist, 1, &histBinNum, &histRange, uniform, accumulate);
calcHist(&gray_color, 1, 0, Mat(), gray_hist, 1, &histBinNum, &histRange, uniform, accumulate);
//创建直方图窗口
int hist_w = 400;
int hist_h = 400;
int bin_w = cvRound((double)srcImage.cols / histBinNum);
Mat histImage(srcImage.cols, srcImage.rows, CV_8UC3, Scalar(0, 0, 0));
//将直方图归一化到范围[0, histImage.rows]
normalize(red_hist, red_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(green_hist, green_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(blue_hist, blue_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(gray_hist, gray_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
//循环绘制直方图
for (int i = 1; i < histBinNum+1; i++)
{
line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(red_hist.at<float>(i - 1))),
Point(bin_w * (i), srcImage.rows - cvRound(red_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(green_hist.at<float>(i - 1))),
Point(bin_w * (i), srcImage.rows - cvRound(green_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(blue_hist.at<float>(i - 1))),
Point(bin_w * (i), srcImage.rows - cvRound(blue_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w * (i - 1), srcImage.rows - cvRound(blue_hist.at<float>(i - 1))),
Point(bin_w * (i), srcImage.rows - cvRound(gray_hist.at<float>(i))), Scalar(255, 255, 255), 2, 8, 0);
}
/* namedWindow("原图像", WINDOW_AUTOSIZE);
imshow("原图像", srcImage);*/
namedWindow("图像直方图", WINDOW_AUTOSIZE);
imshow("图像直方图", histImage);
waitKey(0);
return 0;
}
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/background_segm.hpp>
#include "opencv2/calib3d/calib3d.hpp"
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
cv::Mat temp_thin = cv::imread("../example/2.jpg", CV_LOAD_IMAGE_UNCHANGED);
//cv::imshow("temp_thin",temp_thin);
cv::Mat gray_image, dst, temp_thin_image, binary_image, edge_image;
cvtColor(temp_thin, gray_image, CV_RGB2GRAY);
GaussianBlur(gray_image, edge_image, Size(3, 3), 0, 0);
//blur(gray, edge, Size(3, 3));
Canny(edge_image, edge_image, 10, 150, 3, false);
cv::imshow("edge_image", edge_image);
std:; string anme_pic = "..\\example\\edge_image.bmp";
cv::imwrite(anme_pic, edge_image);
cv::waitKey(0);
return 0;
}
4.效果
5.原理
6.参考
【1】 https://blog.csdn.net/nanguazhuo/article/details/53509695
【3】https://blog.csdn.net/keith_bb/article/details/56680997
更多推荐
所有评论(0)