opencv中,怎么计算彩色图像的直方图calchist
发布网友
发布时间:2022-05-03 03:39
我来回答
共2个回答
懂视网
时间:2022-05-05 03:42
1.一些小概念: (1) 像素在图像中的分布情况是这幅图像的一个重要特征。 (2) 直方图是一个简单的表,它给出了一幅图像或一组图像中用于给定数的像素数量。 2.calcHist 函数 calHist 是opencv 中可以计算直方图。 private:int histSize[1];//色度变换宽度floa
1.一些小概念:
(1) 像素值在图像中的分布情况是这幅图像的一个重要特征。
(2) 直方图是一个简单的表,它给出了一幅图像或一组图像中用于给定数值的像素数量。
2.calcHist 函数
calHist 是opencv 中可以计算直方图。
private:
int histSize[1];//色度变换宽度
float hranges[2];//像素的最小值及最大值
const float * ranges[1];//
int channels[1];//使用的通道
public:
Histogram1D(){
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0;
}
cv::MatND getHistogram(const cv::Mat &image){
cv::MatND hist;
cv::calcHist(&image,1,channels,cv::Mat(),hist,1,histSize,ranges);
return hist;
}
下面给出对一个具体图像求出直方图的例子
#include
#include
#include "cv.h"
#include "highgui.h"
#include
using namespace std;
class Histogram1D {
private:
int histSize[1];
float hranges[2];
const float* ranges[1];
int channels[1];
public:
Histogram1D() {
histSize[0]= 256;
hranges[0]= 0.0;
hranges[1]= 255.0;
ranges[0]= hranges;
channels[0]= 0;
}
cv::MatND getHistogram(const cv::Mat &image) {
cv::MatND hist;
cv::calcHist(&image, //目标图像
1, // 计算一张直方图
channels, // 使用的通道数量
cv::Mat(), // 图像开关
hist, // 返回的直方图
1, // 1D直方图
histSize, // 色图宽度
ranges // 像素值的范围
);
return hist;
}
cv::Mat getHistogramImage(const cv::Mat &image){
cv::MatND hist= getHistogram(image);
double maxVal=0;
double minVal=0;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
cv::Mat histImg(histSize[0], histSize[0], CV_8U,cv::Scalar(255));
int hpt = static_cast(0.9*histSize[0]);
for( int h = 0; h < histSize[0]; h++ ) {
float binVal = hist.at(h);
int intensity = static_cast(binVal*hpt/maxVal);
cv::line(histImg,cv::Point(h,histSize[0]),cv::Point(h,histSize[0]-intensity),cv::Scalar::all(0));
}
return histImg;
}
};
int main()
{
cv::Mat image= cv::imread("group.jpg",0);
if (!image.data)
return 0;
cv::namedWindow("Image");
cv::imshow("Image",image);
Histogram1D h;
cv::MatND histo= h.getHistogram(image);
for (int i=0; i<256; i++)
cout << "Value " << i << " = " << histo.at(i) << endl;
cv::namedWindow("Histogram");
cv::imshow("Histogram",h.getHistogramImage(image));
cv::waitKey();
return 0;
}
输出结果
热心网友
时间:2022-05-05 00:50
CV_EXPORTS 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的出现主要是考虑到输入的每一张图像有可能是多通道的,比如说RGB图就是3通道的,那么从统计意义上来讲,
一张RGB图其实就是3张单通道的图像,而计算直方图时其本质也是针对单张图像进行的。这里虽然我们输入的图像序列images中有很多图片,但是并不是
每一张图片的每一个通道都会被用来计算。所以参数3的功能是指定哪些通道的图像被用来计算(后面的解释都假设图像序列中图像是3通道的,那么有的图像可能
有多个通道都被用来计算,有的图像可能连一个通道都没有被采用),这时参数3里面保存的是通道的序号,那么图像序列images中的第一张图片的通道序号
(假设图像时3通道的)为0,1,2;images中第二张图片的图像序列接着上一次的,为3,4,5,;依次类推即可。
参数4是mask掩膜操作,即指定每张图片的哪些像素被用于计算直方图,这个掩膜矩阵不能够针对特定图像设定特定的掩膜,因此在这里是一视同仁对待的。
参数5是保存计算的直方图结果的矩阵,有可能是*矩阵。
参数6是需要计算的直方图的维数。
参数7是所需计算直方图的每一维的大小,即每一维bin的个数。
参数8是所需计算直方图的每一维的范围,如果参数9的uniform为true,这此时的参数8的大小为2,里面的
元素值表示的是每一维的上下限这两个数字;如果参数9的uniform为false,则此时的参数8的大小为bin的个数,即参数7的值,参数8里面的元
素值需要人为的指定,即每一维的坐标值不一定是均匀的,需要人为指定。
参数9如果为true的话,则说明所需计算的直方图的每一维按照它的范围和尺寸大小均匀取值;如果为false的话,说明直方图的每一维不是均匀分布取值的,参考参数8的解释。
参数10如果为false,则表示直方图输出矩阵hist在使用该函数的时候被清0了,如果为true,则表示hist在使用calcHist()函数时没有被清0,计算的结果会累加到前一次保存的值中。
使用该函数的时候需要注意,如果在默认参数的情况下uniform = true,则此时的ranges大小必须是histSize大小的两倍,并且channels的大小必须等于dims维数。
从上面可以理解,channels里的值已经指定了使用哪些单通道的图像来计算目标直方图,因此一旦channels的尺寸确定,则对应的直方图的维数也就确定了,所以我们不能使用多张图像来计算一个一维的直方图。
以上内容来自:基础学习笔记之opencv(19):有关图像序列的直方图计算
[cpp] view plain copy print?
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/** @函数 main */
int main( int argc, char** argv )
{
Mat src, dst;
/// 装载图像
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
/// 分割成3个单通道图像 ( R, G 和 B )
vector<Mat> rgb_planes;
split( src, rgb_planes );
/// 设定bin数目
int histSize = 255;
/// 设定取值范围 ( R,G,B) )
float range[] = { 0, 255 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat r_hist, g_hist, b_hist;
/// 计算直方图:
calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
// 创建直方图画布
int hist_w = 400; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) );
/// 将直方图归一化到范围 [ 0, histImage.rows ]
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// 在直方图画布上画出直方图
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
}
/// 显示直方图
namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
imshow("calcHist Demo", histImage );
waitKey(0);
return 0;
}