OpenCV直方图的应用实践

2025-01-14 02:08:52

1、构建图像的一维直方图彩色图像的颜色通道一般为RGB 3通道,而黑白图像也就是灰度图像为一维通道图像,我们展现图像的一维直方图主要思路:1)以灰度方式读取图像内容2)计算图像的直方图,需要用到calcHist函数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 );images:处理的输入图像Source arraysnimages:处理的图像数量Number of source imageschannels:图像通道数List of the dims channels used to compute the histogrammask:掩码hist:直方图输出对象dims :计算出来的直方图的维数histSize:在每一维上直方图的个数ranges:用来进行统计的范围。比如float rang1[] = {0, 20};uniform:每一个竖条的宽度是否相等 3)画出直方图

OpenCV直方图的应用实践

2、1)以灰度方式读取图像内容,也可以将图像对象Mat直接通过函数转为灰度图像//图像转为灰度图像 cvtColor(img, img, CV_BGR2GRAY);

OpenCV直方图的应用实践

3、2)calcHist函数计算直方图的值改还是实现图像输入后返回一个直方图对象MatND:MatND testZhifangtu(Mat& img){ //图像转为灰度图像 cvtColor(img, img, CV_BGR2GRAY); //灰度图像为一维通道 const int channels[1] = { 0 }; //256种像素值 const int histSize[1] = { 256 }; //像素值范围 float hranges[2] = { 0,255 }; const float* ranges[1] = { hranges }; MatND hist; //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 ); calcHist(&img, 1, channels, Mat(), hist, 1, histSize, ranges); return hist;}

OpenCV直方图的应用实践

4、3)绘制直方图,需要将直方图的数值映射到图像对象中显示出来该函数实现输入一个直方图对象,通过将个像素的直方图值binValue绘制直线,输出一个可显示的Mat图像。Mat getHistImage(const MatND& hist){ double maxVal = 0; double minVal = 0; minMaxLoc(hist, &minVal, &maxVal, 0, 0); int histSize = hist.rows; printf("HistSize %d",histSize); //定义一个新的图像Mat对象 Mat histImg(histSize, histSize, CV_8U, Scalar(255)); //坐标比例缩放 0.9,最大峰值为图像高度的90% //histSize图像像素总行数,即图像的高度 //y表示点binVlaue在图像上的y坐标值:y/histSize = binValue/MaxValue*0.9 //y =binValue/MaxValue*0.9 * histSize //坐标和图像的映射比率:(hist/maxValue) * 0.9 double rate = (histSize / maxVal)*0.9; for (int h = 0; h < histSize; h++) { float binVal = hist.at<float>(h); printf("pos=%d,binValue= %f \n",h,binVal); //通过划线把一个灰度直方图显示 line(histImg, Point(h, histSize), Point(h, histSize - binVal*rate), Scalar::all(0)); }return histImg;}

OpenCV直方图的应用实践

5、绘制一个一维绘图直方图的完整代码:#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;//直方图应用MatND testZhifangtu(Mat& img){ //图像转为灰度图像 cvtColor(img, img, CV_BGR2GRAY); imshow("灰度图像", img); //灰度图像为一维通道 const int channels[1] = { 0 }; //256种像素值 const int histSize[1] = { 256 }; //像素值范围 float hranges[2] = { 0,255 }; const float* ranges[1] = { hranges }; MatND hist; //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 ); calcHist(&img, 1, channels, Mat(), hist, 1, histSize, ranges); return hist;}Mat getHistImage(const MatND& hist){ double maxVal = 0; double minVal = 0; minMaxLoc(hist, &minVal, &maxVal, 0, 0); int histSize = hist.rows; printf("HistSize %d",histSize); //定义一个新的图像Mat对象 Mat histImg(histSize, histSize, CV_8U, Scalar(255)); //坐标比例缩放 0.9,最大峰值为图像高度的90% //histSize图像像素总行数,即图像的高度 //y表示点binVlaue在图像上的y坐标值:y/histSize = binValue/MaxValue*0.9 //y =binValue/MaxValue*0.9 * histSize //坐标和图像的映射比率:(hist/maxValue) * 0.9 double rate = (histSize / maxVal)*0.9; for (int h = 0; h < histSize; h++) { float binVal = hist.at<float>(h); printf("pos=%d,binValue= %f \n",h,binVal); //通过划线把一个灰度直方图显示 line(histImg, Point(h, histSize), Point(h, histSize - binVal*rate), Scalar::all(0)); } return histImg;}int main(){ //读取本地的一张图片便显示出来 Mat img = imread("F:/mm/01.jpg"); imshow("原始图像",img); MatND newImg = testZhifangtu(img); imshow("灰度直方图", getHistImage(newImg)); //等待用户按键 waitKey(0); return 0;}

OpenCV直方图的应用实践

6、进行运行测试,可以以看到3个图像像是框1)原始图像2)灰度图像3)直方图图像4)控制台输出各个直方图的值

OpenCV直方图的应用实践

7、绘制三维通道直方图void testMultiChannelZhifangtu(Mat& img){ //图像分为三通道图像 vector<Mat> channels; split(img, channels); //设定bin数目 int histBinNum = 255; //设定取值范围 float range[] = {0,255}; const float* histRange = { range }; bool uniform = true; bool accumulate = true; //申明三通道的hist数组 Mat redHist, greenHist, blueHist; calcHist(&channels[0], 1, 0, Mat(),redHist,1, &histBinNum, &histRange,uniform,accumulate); calcHist(&channels[1], 1, 0, Mat(), greenHist, 1, &histBinNum, &histRange, uniform, accumulate); calcHist(&channels[2], 1, 0, Mat(), blueHist, 1, &histBinNum, &histRange, uniform, accumulate); //创建直方图窗口 int histW = 400; int histH = 400; int binW = cvRound((double)img.cols / histBinNum); Mat histImg(img.cols, img.rows, CV_8UC3, Scalar(0, 0, 0)); //将直方图归一化到范围【9,histImg.rows】 normalize(redHist, redHist, 0, img.rows, NORM_MINMAX, -1, Mat()); normalize(greenHist, greenHist, 0, img.rows, NORM_MINMAX, -1, Mat()); normalize(blueHist, blueHist, 0, img.rows, NORM_MINMAX, -1, Mat()); for (int i = 1; i < histBinNum; i++) { line(histImg, Point(binW*(i - 1), img.rows - cvRound(redHist.at<float>(i - 1))), Point(binW*(i), img.rows - cvRound(redHist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0); line(histImg, Point(binW*(i - 1), img.rows - cvRound(greenHist.at<float>(i - 1))), Point(binW*(i), img.rows - cvRound(greenHist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0); line(histImg, Point(binW*(i - 1), img.rows - cvRound(blueHist.at<float>(i - 1))), Point(binW*(i), img.rows - cvRound(blueHist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0); } namedWindow("原始图像", WINDOW_AUTOSIZE); imshow("原始图像", img); namedWindow("3通道直方图图像", WINDOW_AUTOSIZE); imshow("3通道直方图图像", histImg);}

OpenCV直方图的应用实践
猜你喜欢