#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/// 调用OpenCV接口求彩色图像各个通道的直方图
void CalcHist_OpenCV(const Mat * image,Mat & b_hist,Mat & g_hist,Mat &r_hist,int histSize)
{
vector<Mat> bgr_planes; //定于一个Mat向量
split( *image, bgr_planes ); //将彩色图像image中的三个通道分离后,分别保存至向量bgr_planes
float range[] = { 0, 256 } ; //设置直方图的统计范围为0到255
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
/// 计算B通道直方图
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform,
accumulate );
/// 计算G通道直方图
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform,
accumulate );
/// 计算R通道直方图
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform,
accumulate );
}
/// 用自定义的方法统计彩色图像各个通道直方图
void CalcHist_ColorImg(const Mat * image,Mat & b_hist,Mat & g_hist,Mat &r_hist,int histSize)
{
int nRows = image->rows;
int nCols = image->cols; if (image->isContinuous())// 若图像数据是连续存放的,将所有图像数据当作一行数据看待
{
nCols *= nRows;
nRows = 1;
} b_hist = Mat::zeros(1,histSize, CV_32F); // 定义存放b通道直方图的数据尺寸为:1*histSize g_hist = Mat::zeros(1,histSize, CV_32F); // 定义存放g通道直方图的数据尺寸为:1*histSize r_hist = Mat::zeros(1,histSize, CV_32F); // 定义存放r通道直方图的数据尺寸为:1*histSize
int i,j;
const uchar* p; for( i = 0; i < nRows; ++i) //访问第i行像素
{
p = (*image).ptr<uchar>(i); // 得到第i行像素的首地址
for ( j = 0; j < nCols*3; j+=3) // 访问第i行第j列像素的值,每个像素有三个字节
{
/// 根据特定通道的数值在对应直方图条目上加1
b_hist.at<float>(p[j]/(256/histSize)) ++;// p[j]为第i行第j列像素的b通道的值
g_hist.at<float>(p[j+1]/(256/histSize)) ++;// p[j+1]为第i行第j列像素的g通道的值
r_hist.at<float>(p[j+2]/(256/histSize)) ++;// p[j+2]为第i行第j列像素的r通道的值
}
}
}
/// 重载自定义方法统计彩色图像各个通道的直方图
void CalcHist_ColorImg(unsigned char data[],float b_hist[],float g_hist[],float r_hist[],int
dataSize,int histSize)
{
int i;
memset(b_hist,0,histSize*sizeof(float)); //b通道直方图数据初始化为0
memset(g_hist,0,histSize*sizeof(float)); //g通道直方图数据初始化为0
memset(r_hist,0,histSize*sizeof(float)); //r通道直方图数据初始化为0
for(i=0;i<dataSize;i+=3) //访问第i个像素,一共dataSize/3个像素
{
//根据第i个像素的值将对应通道直方图的对应条目的值加1
b_hist[data[i]/(256/histSize)] ++ ; // data[i]为第i个像素的b通道的值
g_hist[data[i+1]/(256/histSize)] ++ ; // data[i+1]为第i个像素的g通道的值
r_hist[data[i+2]/(256/histSize)] ++ ; // data[i+2]为第i个像素的r通道的值
}
}
/// 图像绘制
void DrawHist(const string& winname,Mat & b_hist,Mat & g_hist,Mat &r_hist,int histSize)
{
int hist_w = 512; int hist_h = 400; //设置显示的直方图图像的尺寸为512*400
int bin_w = cvRound( (double) hist_w/histSize ); //直方图每个条目的宽度
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) ); //创建一个三通道8位图像
/// 将三个直方图数据线性映射到[ 0, histImage.rows ]区间内,最小值映射为0,最大值映射为
//histImage.rows
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_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(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 );
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(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 );
}
/// Display
namedWindow(winname, CV_WINDOW_AUTOSIZE );
imshow(winname, histImage );
}
int main( int argc, char** argv )
{
Mat src, dst;
/// 载入图像,以灰度图像的方式载入
src = imread( argv[1], CV_LOAD_IMAGE_COLOR ); if( !src.data ) // 检查是否读文件成功
{ return -1; }
int histSize = 256; //直方图条目为256
Mat b_hist, g_hist, r_hist; //定义Mat类型的三个直方图数据
/// 用opencv的接口函数求直方图,然后绘制该直方图
CalcHist_OpenCV(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcColorImgHistogram1",b_hist,g_hist,r_hist,histSize);
/// 用自定义的彩色图像三个通道直方图统计函数求直方图,然后绘制该直方图
CalcHist_ColorImg(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcColorImgHistogram2",b_hist,g_hist,r_hist,histSize);
/// 用另外一种自定义的彩色图像三个通道直方图统计函数求直方图,然后绘制该直方图
if (src.isContinuous())// 检查像素矩阵中的数据是否是连续存放的
{
b_hist = Mat::zeros(1,histSize, CV_32F);
g_hist = Mat::zeros(1,histSize, CV_32F);
r_hist = Mat::zeros(1,histSize, CV_32F);
CalcHist_ColorImg(src.data,
(float*)(b_hist.data),(float*)(g_hist.data),(float*)(r_hist.data),src.cols*src.rows*3,histSize);
DrawHist("calcColorImgHistogram3",b_hist,g_hist,r_hist,histSize);
}
//装箱直方图的条目设置为32
histSize = 32;
///用opencv的接口函数求装箱直方图,然后绘制该装箱直方图
CalcHist_OpenCV(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcBinnedColorImgHistogram1",b_hist,g_hist,r_hist,histSize);
/// 用自定义的彩色图像三个通道直方图统计函数求装箱直方图,然后绘制该装箱直方图
CalcHist_ColorImg(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcBinnedColorImgHistogram2",b_hist,g_hist,r_hist,histSize);
/// 用另外一种自定义的彩色图像三个通道直方图统计函数求装箱直方图,然后绘制该装箱直方图
if (src.isContinuous())// 检查像素矩阵中的数据是否是连续存放的
{
b_hist = Mat::zeros(1,histSize, CV_32F);
g_hist = Mat::zeros(1,histSize, CV_32F);
r_hist = Mat::zeros(1,histSize, CV_32F);
CalcHist_ColorImg(src.data,
(float*)(b_hist.data),(float*)(g_hist.data),(float*)(r_hist.data),src.cols*src.rows*3,histSize);
DrawHist("calcBinnedColorImgHistogram3",b_hist,g_hist,r_hist,histSize);
}
waitKey(0);
return 0;
}
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/// 调用OpenCV接口求彩色图像各个通道的直方图
void CalcHist_OpenCV(const Mat * image,Mat & b_hist,Mat & g_hist,Mat &r_hist,int histSize)
{
vector<Mat> bgr_planes; //定于一个Mat向量
split( *image, bgr_planes ); //将彩色图像image中的三个通道分离后,分别保存至向量bgr_planes
float range[] = { 0, 256 } ; //设置直方图的统计范围为0到255
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
/// 计算B通道直方图
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform,
accumulate );
/// 计算G通道直方图
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform,
accumulate );
/// 计算R通道直方图
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform,
accumulate );
}
/// 用自定义的方法统计彩色图像各个通道直方图
void CalcHist_ColorImg(const Mat * image,Mat & b_hist,Mat & g_hist,Mat &r_hist,int histSize)
{
int nRows = image->rows;
int nCols = image->cols; if (image->isContinuous())// 若图像数据是连续存放的,将所有图像数据当作一行数据看待
{
nCols *= nRows;
nRows = 1;
} b_hist = Mat::zeros(1,histSize, CV_32F); // 定义存放b通道直方图的数据尺寸为:1*histSize g_hist = Mat::zeros(1,histSize, CV_32F); // 定义存放g通道直方图的数据尺寸为:1*histSize r_hist = Mat::zeros(1,histSize, CV_32F); // 定义存放r通道直方图的数据尺寸为:1*histSize
int i,j;
const uchar* p; for( i = 0; i < nRows; ++i) //访问第i行像素
{
p = (*image).ptr<uchar>(i); // 得到第i行像素的首地址
for ( j = 0; j < nCols*3; j+=3) // 访问第i行第j列像素的值,每个像素有三个字节
{
/// 根据特定通道的数值在对应直方图条目上加1
b_hist.at<float>(p[j]/(256/histSize)) ++;// p[j]为第i行第j列像素的b通道的值
g_hist.at<float>(p[j+1]/(256/histSize)) ++;// p[j+1]为第i行第j列像素的g通道的值
r_hist.at<float>(p[j+2]/(256/histSize)) ++;// p[j+2]为第i行第j列像素的r通道的值
}
}
}
/// 重载自定义方法统计彩色图像各个通道的直方图
void CalcHist_ColorImg(unsigned char data[],float b_hist[],float g_hist[],float r_hist[],int
dataSize,int histSize)
{
int i;
memset(b_hist,0,histSize*sizeof(float)); //b通道直方图数据初始化为0
memset(g_hist,0,histSize*sizeof(float)); //g通道直方图数据初始化为0
memset(r_hist,0,histSize*sizeof(float)); //r通道直方图数据初始化为0
for(i=0;i<dataSize;i+=3) //访问第i个像素,一共dataSize/3个像素
{
//根据第i个像素的值将对应通道直方图的对应条目的值加1
b_hist[data[i]/(256/histSize)] ++ ; // data[i]为第i个像素的b通道的值
g_hist[data[i+1]/(256/histSize)] ++ ; // data[i+1]为第i个像素的g通道的值
r_hist[data[i+2]/(256/histSize)] ++ ; // data[i+2]为第i个像素的r通道的值
}
}
/// 图像绘制
void DrawHist(const string& winname,Mat & b_hist,Mat & g_hist,Mat &r_hist,int histSize)
{
int hist_w = 512; int hist_h = 400; //设置显示的直方图图像的尺寸为512*400
int bin_w = cvRound( (double) hist_w/histSize ); //直方图每个条目的宽度
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) ); //创建一个三通道8位图像
/// 将三个直方图数据线性映射到[ 0, histImage.rows ]区间内,最小值映射为0,最大值映射为
//histImage.rows
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_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(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 );
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(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 );
}
/// Display
namedWindow(winname, CV_WINDOW_AUTOSIZE );
imshow(winname, histImage );
}
int main( int argc, char** argv )
{
Mat src, dst;
/// 载入图像,以灰度图像的方式载入
src = imread( argv[1], CV_LOAD_IMAGE_COLOR ); if( !src.data ) // 检查是否读文件成功
{ return -1; }
int histSize = 256; //直方图条目为256
Mat b_hist, g_hist, r_hist; //定义Mat类型的三个直方图数据
/// 用opencv的接口函数求直方图,然后绘制该直方图
CalcHist_OpenCV(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcColorImgHistogram1",b_hist,g_hist,r_hist,histSize);
/// 用自定义的彩色图像三个通道直方图统计函数求直方图,然后绘制该直方图
CalcHist_ColorImg(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcColorImgHistogram2",b_hist,g_hist,r_hist,histSize);
/// 用另外一种自定义的彩色图像三个通道直方图统计函数求直方图,然后绘制该直方图
if (src.isContinuous())// 检查像素矩阵中的数据是否是连续存放的
{
b_hist = Mat::zeros(1,histSize, CV_32F);
g_hist = Mat::zeros(1,histSize, CV_32F);
r_hist = Mat::zeros(1,histSize, CV_32F);
CalcHist_ColorImg(src.data,
(float*)(b_hist.data),(float*)(g_hist.data),(float*)(r_hist.data),src.cols*src.rows*3,histSize);
DrawHist("calcColorImgHistogram3",b_hist,g_hist,r_hist,histSize);
}
//装箱直方图的条目设置为32
histSize = 32;
///用opencv的接口函数求装箱直方图,然后绘制该装箱直方图
CalcHist_OpenCV(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcBinnedColorImgHistogram1",b_hist,g_hist,r_hist,histSize);
/// 用自定义的彩色图像三个通道直方图统计函数求装箱直方图,然后绘制该装箱直方图
CalcHist_ColorImg(&src,b_hist,g_hist,r_hist,histSize);
DrawHist("calcBinnedColorImgHistogram2",b_hist,g_hist,r_hist,histSize);
/// 用另外一种自定义的彩色图像三个通道直方图统计函数求装箱直方图,然后绘制该装箱直方图
if (src.isContinuous())// 检查像素矩阵中的数据是否是连续存放的
{
b_hist = Mat::zeros(1,histSize, CV_32F);
g_hist = Mat::zeros(1,histSize, CV_32F);
r_hist = Mat::zeros(1,histSize, CV_32F);
CalcHist_ColorImg(src.data,
(float*)(b_hist.data),(float*)(g_hist.data),(float*)(r_hist.data),src.cols*src.rows*3,histSize);
DrawHist("calcBinnedColorImgHistogram3",b_hist,g_hist,r_hist,histSize);
}
waitKey(0);
return 0;
}