若该文为原创文章,未经允许不得转载 目录 红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门) 红胖子来也!!! 在之前接触的相机录像中,遇到过白平衡,白平衡其实就是调整整个界面的亮度平衡,达到一个对比度合适的过程,原理其实就是直方图均衡化,在这之前先理解直方图的概念。 单独深入理解直方图,是因为直方图不仅在静态图均衡化的时候有作用,在后面的识别和跟踪等更多的过程中,部分算法都需要直方图,比如相邻帧间的直方图分析对比等等,是后续动态视频识别处理的一个重要概念。 关于直方图,其实在经典OTSU中的代码实现了计算,OTSU算法阈值化其实就是使用灰度图结合方差,计算出一个合适的阈值,使用该阈值做阈值化。 《OpenCV开发笔记(三十):带你学习图像识别之经典OTSU算法阈值化》 直方图是一种对数据分布情况的图形表示,是一种二维统计图表,有两个坐标,按照当前图像出来来说,主要是氛围属性和值,属性可理解为灰度级(从0到255),值可理解为分布的数量(概率,该等级的灰度点数量占所有数量中的点比例),所以: 直方图是图像中像素强度分布的图形表达方式; 统计了每一个属性值的个数; (注意:可以各种彩色向量都可以做直方图处理,此处以灰度图举例) 计算灰度级中每个像素在整幅图像中的个数; 较函数1重载了参数5输出类型,由OutputArray改为SparseMat; 重载了输入和输出的类型,为stl版本的,本身vector带了数量,因此少了几个参数; 归一化是指对矩阵cv::Mat进行归一化操作。 归一化是一种无量纲处理手段,使物理系统数值的绝对值变成某种相对值关系。简化计算,缩小量值的有效办法。 例如,滤波器中各个频率值以截止频率作归一化后,频率都是截止频率的相对值,没有了量纲。阻抗以电源内阻作归一化后,各个阻抗都成了一种相对阻抗值,“欧姆”这个量纲也没有了。等各种运算都结束后,反归一化一切都复原了。信号处理工具箱中经常使用的是nyquist频率,它被定义为采样频率的二分之一,在滤波器的阶数选择和设计中的截止频率均使用nyquist频率进行归一化处理。例如对于一个采样频率为500hz的系统,400hz的归一化频率就为400/500=0.8,归一化频率范围在[0,1]之间。 对应版本号v1.42.0 . 原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105797267
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
OpenCV开发专栏(点击传送门)
OpenCV开发笔记(四十七):红胖子8分钟带你深入了解直方图(图文并茂+浅显易懂+程序源码)
前言
相关博客
Demo
直方图
概述
原理
编码一个通道的直方图计算代码
int grayScale[256] = {0}; // 每个灰度级所占像素的 double grayPro[256] = {0}; // 每个灰度级所占像素比例: 为 该像素出现的次数/总像素 // 步骤一:计算灰度级中每个像素在整幅图像中的个数;灰度级8位为256级别0~255 for(int row = 0; row < srcMat.rows; row++) { for(int col = 0; col < srcMat.cols; col++) { grayScale[srcMat.at<uchar>(row, col)]++; } }
重载函数原型1
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 );
重载函数原型2(参照函数原型1)
void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const float** ranges, bool uniform = true, bool accumulate = false );
重载函数原型3(参照函数原型1)
void calcHist( InputArrayOfArrays images, const std::vector<int>& channels, InputArray mask, OutputArray hist, const std::vector<int>& histSize, const std::vector<float>& ranges, bool accumulate = false );
归一化
概述
函数原型
void normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
Demo源码
void OpenCVManager::testCalcHist() { QString fileName1 = "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/2.jpg"; cv::Mat srcMat = cv::imread(fileName1.toStdString()); cv::Mat dstMat; int width = 400; int height = 300; cv::resize(srcMat, srcMat, cv::Size(width, height)); cv::String windowName = _windowTitle.toStdString(); cvui::init(windowName); cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, srcMat.rows * 4), srcMat.type()); cv::Mat allMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); allMat = cv::Scalar(0, 0, 0); while(true) { // 刷新全图黑色 windowMat = cv::Scalar(0, 0, 0); // 原图复制 cv::Mat mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1), cv::Range(srcMat.cols * 0, srcMat.cols * 1)); cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat); // 计算直方图 { // 直方图存放,需要有东西,所以使用cv::MatND,其等于createHist cv::MatND dstHistRed; // 计算通道0,1,2(brg三个通道) int channels[] = {2}; // 直方图的条数 int hueBinNum = 256; int histSize[] = {hueBinNum}; // 变化范围 float range[] = {0, 256}; const float *ranges[] = {range}; // brg三个 cv::calcHist(&srcMat, // 只有1个mat 1, // 只有1个mat channels, // 只有1个mat的3个通道,bgr cv::Mat(), // 不使用掩码 dstHistRed, // 输出的目标直方图 1, // 计算直方图的维度 histSize, // 每个维度的直方图条数(例如灰度为一维,多少条) ranges, // 每个维度的范围 true, // 直方图是否均匀 false); // 累计标识符,false表示直方图在配置阶段会被清零 dstMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); dstMat = cv::Scalar(0, 0, 0); for(int index = 0; index < hueBinNum; index++) { cv::line(dstMat, cv::Point(15 + index, srcMat.rows), cv::Point(15 + index, srcMat.rows - dstHistRed.at<float>(index)), cv::Scalar(0, 0, 255)); } // 原图复制 cv::Mat mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2), cv::Range(srcMat.cols * 0, srcMat.cols * 1)); cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat); // 计算出最大的,进行归一化操作 cv::normalize(dstHistRed, dstHistRed, 0, srcMat.rows, cv::NORM_MINMAX, -1, cv::Mat()); dstMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); dstMat = cv::Scalar(0, 0, 0); // 此处并没有进行归一化操作,像素总共为300*200个点 // 如果全是红色,则该店的数据能得到60000个点,实际显示图片的高度为300 for(int index = 0; index < hueBinNum; index++) { cv::line(dstMat, cv::Point(15 + index, srcMat.rows), cv::Point(15 + index, srcMat.rows - dstHistRed.at<float>(index)), cv::Scalar(0, 0, 255)); // 右上角,三色统计图 cv::circle(allMat, cv::Point(15 + index, srcMat.rows - dstHistRed.at<float>(index)), 1, cv::Scalar(0, 0, 255)); } // 原图复制 mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2), cv::Range(srcMat.cols * 1, srcMat.cols * 2)); cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat); } // 计算直方图 { // 直方图存放,需要有东西,所以使用cv::MatND,其等于createHist cv::MatND dstHistGreen; // 计算通道0,1,2(brg三个通道) int channels[] = {1}; // 直方图的条数 int hueBinNum = 256; int histSize[] = {hueBinNum}; // 变化范围 float range[] = {0, 256}; const float *ranges[] = {range}; // brg三个 cv::calcHist(&srcMat, // 只有1个mat 1, // 只有1个mat channels, // 只有1个mat的3个通道,bgr cv::Mat(), // 不使用掩码 dstHistGreen, // 输出的目标直方图 1, // 计算直方图的维度 histSize, // 每个维度的直方图条数(例如灰度为一维,多少条) ranges, // 每个维度的范围 true, // 直方图是否均匀 false); // 累计标识符,false表示直方图在配置阶段会被清零 dstMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); dstMat = cv::Scalar(0, 0, 0); for(int index = 0; index < hueBinNum; index++) { cv::line(dstMat, cv::Point(15 + index, srcMat.rows), cv::Point(15 + index, srcMat.rows - dstHistGreen.at<float>(index)), cv::Scalar(0, 255, 0)); } // 原图复制 cv::Mat mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3), cv::Range(srcMat.cols * 0, srcMat.cols * 1)); cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat); // 计算出最大的,进行归一化操作 cv::normalize(dstHistGreen, dstHistGreen, 0, srcMat.rows, cv::NORM_MINMAX, -1, cv::Mat()); dstMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); dstMat = cv::Scalar(0, 0, 0); for(int index = 0; index < hueBinNum; index++) { cv::line(dstMat, cv::Point(15 + index, srcMat.rows), cv::Point(15 + index, srcMat.rows - dstHistGreen.at<float>(index)), cv::Scalar(0, 255, 0)); // 右上角,三色统计图 cv::circle(allMat, cv::Point(15 + index, srcMat.rows - dstHistGreen.at<float>(index)), 1, cv::Scalar(0, 255, 0)); } // 原图复制 mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3), cv::Range(srcMat.cols * 1, srcMat.cols * 2)); cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat); } // 计算直方图 { // 直方图存放,需要有东西,所以使用cv::MatND,其等于createHist cv::MatND dstHistBlue; // 计算通道0,1,2(brg三个通道) int channels[] = {0}; // 直方图的条数 int hueBinNum = 256; int histSize[] = {hueBinNum}; // 变化范围 float range[] = {0, 256}; const float *ranges[] = {range}; // brg三个 cv::calcHist(&srcMat, // 只有1个mat 1, // 只有1个mat channels, // 只有1个mat的3个通道,bgr cv::Mat(), // 不使用掩码 dstHistBlue, // 输出的目标直方图 1, // 计算直方图的维度 histSize, // 每个维度的直方图条数(例如灰度为一维,多少条) ranges, // 每个维度的范围 true, // 直方图是否均匀 false); // 累计标识符,false表示直方图在配置阶段会被清零 dstMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); dstMat = cv::Scalar(0, 0, 0); // 此处并没有进行归一化操作,像素总共为300*200个点 // 如果全是红色,则该店的数据能得到60000个点,实际显示图片的高度为300 for(int index = 0; index < hueBinNum; index++) { cv::line(dstMat, cv::Point(15 + index, srcMat.rows), cv::Point(15 + index, srcMat.rows - dstHistBlue.at<float>(index)), cv::Scalar(255, 0, 0)); } // 原图复制 cv::Mat mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4), cv::Range(srcMat.cols * 0, srcMat.cols * 1)); cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat); // 计算出最大的,进行归一化操作 cv::normalize(dstHistBlue, dstHistBlue, 0, srcMat.rows, cv::NORM_MINMAX, -1, cv::Mat()); dstMat = cv::Mat(srcMat.rows, srcMat.cols, srcMat.type()); dstMat = cv::Scalar(0, 0, 0); // 此处并没有进行归一化操作,像素总共为300*200个点 // 如果全是红色,则该店的数据能得到60000个点,实际显示图片的高度为300 for(int index = 0; index < hueBinNum; index++) { cv::line(dstMat, cv::Point(15 + index, srcMat.rows), cv::Point(15 + index, srcMat.rows - dstHistBlue.at<float>(index)), cv::Scalar(255, 0, 0)); // 右上角,三色统计图 cv::circle(allMat, cv::Point(15 + index, srcMat.rows - dstHistBlue.at<float>(index)), 1, cv::Scalar(255, 0, 0)); } // 原图复制 mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4), cv::Range(srcMat.cols * 1, srcMat.cols * 2)); cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat); } // 原图复制 mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1), cv::Range(srcMat.cols * 1, srcMat.cols * 2)); cv::addWeighted(mat, 0.0f, allMat, 1.0f, 0.0f, mat); // 更新 cvui::update(); // 显示 cv::imshow(windowName, windowMat); // esc键退出 if(cv::waitKey(25) == 27) { break; } } }
工程模板:对应版本号v1.42.0
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105797267
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算