文章目录

  • 前言
  • 一、函数介绍
    • 1 split
    • 2 calcHist
    • 3 normalize
  • 二、演示
    • 1、GUI
    • 2、实现代码
  • 总结

前言

越来越多的开发人员选择基于开源的Qt框架与OpenCV来实现界面和算法,其原因不单单是无版权问题,更多是两个社区的发展蓬勃,可用来学习的资料与例程特别丰富。以下是关于利用Qt构建GUI并使用OpenCV中的split/calcHist/normalize函数进行直方图计算。
软件版本:Qt-5.12.0/OpenCV-4.5.3
平台:Windows10/11–64


一、函数介绍

1 split

cv::split(const Mat& src, Mat *mvBegin)
cv::split(InputArray m, OutputArrayOfArrays mv);
参数解释:
src/m:要进行分离的图像矩阵;
mvBegin:Mat数组的首地址;
mv:vector对象;

2 calcHist

cv::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 )

cv::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 )

参数解释:
images:源图像数组,它们有同样的位深CV_8U或 CV_32F ,同样的尺寸;图像阵列中的每一个图像都可以有任意多个通道;
nimages:源图像的数目;
channels:维度通道序列,第一幅图像的通道标号从0~image[0].channels( )-1。Image[0]表示图像数组中的第一幅图像,channels()表示该图像的通道数量。同理,图像阵列中的第二幅图像,通道标号从image[0].channerls( )开始,到image[1].channels( )-1为止;第三、四幅图像的通道标号顺序依此类推;也就是说图像阵列中的所有图像的通道根据图像排列顺序,排成一个通道队列;
mask: 可选择的mask。如果该矩阵不空的话,它必须是一个8-bit的矩阵,与images[i]同尺寸。在图像中,只有被mask覆盖的区域的像素才参与直方图统计。如果这个参数想用默认值,输入Mat()就可以了;
hist:输出直方图, 它是一个稠密或稀疏矩阵,具有dims个维度;
dims :直方图的维度,一定是正值, CV_MAX_DIMS(当前OpenCV版本是32个);
histSize:数组,即histSize[i]表示第i个维度上bin的个数;这里的维度可以理解为通道;
ranges: 当uniform=true时,ranges是多个二元数组组成的数组;当uniform=false时,ranges是多元数组组成的数组。当在每个维度(或通道)上每个直方条等宽时,即uniform=true时,灰度值的有效统计范围的下界用L0表示,上界用UhistSize[i]-1表示,角标中的i表示第i个维度(或通道),上下界值可以表示为hrange[i]={ L0, UhistSize[i]-1}, 在统计时, L0和UhistSize[i]-1不在统计范围内。而ranges={ hrange[0], hrange[1], …… , hrange[dims]}。ranges的元素个数由参数dims决定。其中,L0表示在该通道上第0个直方条(bin)的下边界,UhistSize[i]-1表示最后一个直方条histSize[i]-1的上边界。在该维度上直方条的个数为histSize[i],如hrange[0]={ L0, UhistSize[0]},hrange[1]={ L1, UhistSize[1]}, hrange[2]={ L2, UhistSize[2]}, …… , hrange[dims]={ L0, UhistSize[0]}。当uniform=false时,ranges中的每个元素ranges[i]都是一个多元数组,元素个数为histSize[i]+1,它们分别是:L0 , U0=L1, U1= L2, …… ,UhistSize[i]-2 , LhistSize[i]-1 , UhistSize[i]-1 。所以,ranges[i]={ L0 , L1, L2, …… , LhistSize[i]-1 ,UhistSize[i]-1};
uniform:标识,用于说明直方条bin是否是均匀等宽的;
accumulate: 累积标识。如果该项设置,当直方图重新分配时,直方图在开始清零。这个特征可以使你通过几幅图像,累积计算一个简单的直方图,或者及时更新直方图;

函数calcHist可以计算一幅或多幅图像的直方图。在元组中增量一个直方图的时候,就是从输入图像组中的原位置提取一幅图像,并计算出它的直方图,并添加到元组中。当参数dims>1时,输出矩阵Hist是二维矩阵。

3 normalize

cv::normalize(InputArry src, InputOutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mark=noArry())
参数解释:
src:输入数组;
**dst **:输出数组,数组的大小和原数组一致;
alpha:1-用来规范值,2-规范范围,并且是下限;
beta:只用来规范范围并且是上限;
**norm_type **: 归一化选择的数学公式类型;
**dtype **:当为负,输出的宽高通道数都等于输入,当为正,输出只在深度与输入不同,不同的地方由dtype决定;
mark:掩码,选择感兴趣区域,选定后只能对该区域进行操作;

函数作用归一化数据,该函数分为范围归一化与数据值归一化,经常应用在将数值限定在一个范围,以便使用同一套阈值参数的情况。

二、演示

1、GUI


如上图创建Histgram的功能按钮QPushButton, 直方图展示在Histgram的窗口中。

2、实现代码

histBtn的clicked()槽函数实现如下:

void MainWindow::on_histBtn_clicked()
{std::size_t numView = ui->tabWidget->currentIndex() % 4;if (dispMat[numView]->empty()){outputInfo(2, tr("Please make sure the Mat exist!"));}std::vector<cv::Mat> rgb_planes;if (dispMat[numView]->channels() == 3)         {cv::split(*dispMat[numView], rgb_planes);      // split函数,分离通道;}else{rgb_planes.push_back(*dispMat[numView]);rgb_planes.push_back(*dispMat[numView]);rgb_planes.push_back(*dispMat[numView]);}outputInfo(1, "Channels: " + QString::number(dispMat[numView]->channels()));int histSize = 255;float range[] = {0, 255};const float* histRange = {range};bool uniform = true;bool accumulate = false;cv::Mat r_hist, g_hist, b_hist;cv::calcHist(&rgb_planes[0], 1, nullptr, cv::Mat(), r_hist, 1, \        // 直方图计算&histSize, &histRange, uniform, accumulate);cv::calcHist(&rgb_planes[1], 1, nullptr, cv::Mat(), g_hist, 1,\&histSize, &histRange, uniform, accumulate);cv::calcHist(&rgb_planes[0], 1, nullptr, cv::Mat(), b_hist, 1,\&histSize, &histRange, uniform, accumulate);int hist_w = 512;int hist_h = 800;cv::Mat tmpMat(hist_w, hist_h, CV_8UC3, cv::Scalar(0, 0, 0));         // 准备画布/*cv::normalize(r_hist, r_hist, 0, tmpMat.rows, cv::NORM_MINMAX, \       // 归一化-1, cv::Mat());cv::normalize(g_hist, g_hist, 0, tmpMat.rows, cv::NORM_MINMAX, \-1, cv::Mat());cv::normalize(b_hist, b_hist, 0, tmpMat.rows, cv::NORM_MINMAX, \-1, cv::Mat());int bin_w = cvRound(static_cast<double> (hist_w/histSize));for (int i = 1; i < histSize; i++){cv::line(tmpMat, cv::Point(bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1))),cv::Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))),cv::Scalar(0, 0, 255), 2, 8, 0);cv::line(tmpMat, cv::Point(bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1))),cv::Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))),cv::Scalar(0, 0, 255), 2, 8, 0);cv::line(tmpMat, cv::Point(bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1))),cv::Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))),cv::Scalar(0, 0, 255), 2, 8, 0);}*/double rMax, gMax, bMax;cv::minMaxLoc(r_hist, nullptr, &rMax, nullptr, nullptr);cv::minMaxLoc(g_hist, nullptr, &gMax, nullptr, nullptr);cv::minMaxLoc(b_hist, nullptr, &bMax, nullptr, nullptr);double rBin_w = static_cast<double>(tmpMat.cols / histSize);double rBin_h = static_cast<double>(tmpMat.rows / rMax);double gBin_w = static_cast<double>(tmpMat.cols / histSize);double gBin_h = static_cast<double>(tmpMat.rows / gMax);double bBin_w = static_cast<double>(tmpMat.cols / histSize);double bBin_h = static_cast<double>(tmpMat.rows / bMax);for (int i = 1; i < histSize; i++){cv::Point rP_0 = cv::Point(static_cast<int>(i*rBin_w), tmpMat.rows);int rVal = static_cast<int>(r_hist.at<float>(i));cv::Point rP_1 = cv::Point(static_cast<int>((i + 1)*rBin_w), \static_cast<int>(tmpMat.rows - rVal*rBin_h));cv::rectangle(tmpMat, rP_0, rP_1, cv::Scalar(0, 0, 255), 2, 8, 0);cv::Point gP_0 = cv::Point(static_cast<int>(i*gBin_w), tmpMat.rows);int gVal = static_cast<int>(g_hist.at<float>(i));cv::Point gP_1 = cv::Point(static_cast<int>((i + 1)*gBin_w), \static_cast<int>(tmpMat.rows - gVal*gBin_h));cv::rectangle(tmpMat, gP_0, gP_1, cv::Scalar(0, 255, 0), 2, 8, 0);cv::Point bP_0 = cv::Point(static_cast<int>(i*bBin_w), tmpMat.rows);int bVal = static_cast<int>(b_hist.at<float>(i));cv::Point bP_1 = cv::Point(static_cast<int>((i + 1)*bBin_w), \static_cast<int>(tmpMat.rows - bVal*bBin_h));cv::rectangle(tmpMat, bP_0, bP_1, cv::Scalar(255, 0, 0), 2, 8, 0);}char string[12];int mark = 0;for (int i = 1; mark < static_cast<int>(rMax); i++){mark = static_cast<int>(i * rMax / 20);itoa(mark, string, 10);cv::putText(tmpMat, string, cv::Point(0, static_cast<int>(tmpMat.rows - \mark * rBin_h)), 1, 1, \cv::Scalar(0, 255, 255));}mark = 0;for (int i = 1; mark < 256; i++){mark = i * 20;itoa(mark, string, 10);cv::putText(tmpMat, string, cv::Point(mark * (tmpMat.cols / 256),tmpMat.rows), 1, 1, cv::Scalar(0, 255, 255));}*dispMat[3] = tmpMat.clone();cvtMatPixmap(dispMat, dispPixmap, 3);outputInfo(1, tr("Histogram Action done."));double minVal, maxVal;cv::Point minLoc, maxLoc;if (dispMat[numView]->channels() == 3){cv::cvtColor(*dispMat[numView], tmpMat, cv::COLOR_RGB2GRAY);}else{tmpMat = *dispMat[numView];}cv::minMaxLoc(tmpMat, &minVal, &maxVal, &minLoc, &maxLoc);QString minMaxLocVal = "minVal: " + QString::number(minVal) + \" maxVal: " + QString::number(maxVal);std::stringstream tmpStream;std::streambuf* coutBuf = std::cout.rdbuf();std::cout.rdbuf(tmpStream.rdbuf());std::cout << " minLoc: " << minLoc << " maxLoc: " << maxLoc << std::endl;std::string minMaxLocString(tmpStream.str());std::cout.rdbuf(coutBuf);QString infoMinMaxLoc = minMaxLocVal + QString::fromStdString(minMaxLocString);outputInfo(1, infoMinMaxLoc);
}

总结

以上是关于利用Qt进行GUI构建并使用OpenCV中的split/calcHist/normalized函数进行图像缩放的介绍。
参考:
链接: 往期/前期https://blog.csdn.net/richard_yuu/article/details/127859793
链接: 往期/前期https://blog.csdn.net/richard_yuu/article/details/124140746
其中疑问或错误,欢迎联系交流,微信:electrical_program

【QtOpenCV 直方图计算 split/calcHist/normalize】相关推荐

  1. 详解为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0

    在使用OpenCV的直方图计算函数calcHist()时,发现灰度值为255的像素个数总是为0. 哪怕图像中灰度值为255的像素个数不为0,使用OpenCV的直方图计算函数calcHist()计算出的 ...

  2. OpenCV直方图计算函数calcHist详解

    原文转自https://docs.opencv.org/2.4/modules/imgproc/doc/histograms.html 文档是英文的,应该不难看懂,就不给翻译了. ---------- ...

  3. 【opencv学习笔记】025之直方图计算 - calcHist函数详解

    前言 如果你想了解更多有关于计算机视觉.OpenCV.机器学习.深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧! 1.calcHist函数是干什么滴? 这个问题嘛,看看标 ...

  4. OpenCV 图像直方图计算calcHist()

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/keith_bb/article/details/56680997 图像直方图是对数据集合的一种统计方 ...

  5. OpenCV-Python直方图计算calcHist函数详解

    ☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython ░ 一.引言 在<<数字图像处理>第三章学习总结感悟2:直方图处理: h ...

  6. OpenCV-Python图像直方图计算calcHist函数详解、示例及图形呈现

    ☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython ░ 一.引言 在前面几篇直方图相关的文章中介绍了直方图均衡.直方图匹配.局部直方图处理.基 ...

  7. 【OpenCV 】直方图均衡化,直方图计算,直方图对比

    目录 1.直方图均衡化¶ 1.1 原理 1.2 直方图均衡化 1.3 直方图均衡化原理 1.4 代码实例 1.5 运行效果 2. 直方图计算¶ 2.1 目标 2.2 直方图 2.3 代码实例 2.4 ...

  8. OpenCV之imgproc 模块. 图像处理(4)直方图均衡化 直方图计算 直方图对比 反向投影 模板匹配

    直方图均衡化 目标 在这个教程中你将学到: 什么是图像的直方图和为什么图像的直方图很有用 用OpenCV函数 equalizeHist 对图像进行直方图均衡化 原理 图像的直方图是什么? 直方图是图像 ...

  9. 【opencv450 Image Processing】Histogram Calculation直方图计算

    Goal 在本教程中,您将学习如何: 使用 OpenCV 函数 cv::split 将图像划分为其对应的平面. 使用 OpenCV 函数 cv::calcHist 计算图像数组的直方图 使用函数 cv ...

最新文章

  1. usaco Overfencing 穿越栅栏(BFS)
  2. 皮一皮:35岁后你做什么?
  3. 学生籍贯信息管理系统c语言,学生籍贯信息管理系统(c).doc
  4. 分区供水条件口诀_口诀+总结!耐火等级要求及调整原则及记忆方式
  5. BZOJ3230 相似子串 字符串 SA ST表
  6. php识别号码格式豹子,[转载]php新手入门之PHP常用特殊运算符号
  7. matlab图像的腐蚀和膨胀_OpenCV图像处理系列八 --- 腐蚀与膨胀
  8. html php打开,html格式如何打开
  9. centos 7 php7 yum源
  10. c语言编译器app官网下载,c语言编译器
  11. C语言代码输出星期几,C语言程序设计: 输入年月日 然后输出是星期几
  12. java基础练习 2
  13. 菜鸟python_菜鸟爱Python第1期:Python发展史?对Python最深刻的解读
  14. 图书馆占座系统(四)
  15. 快递鸟预约快递员上门揽件API开发指南
  16. uniapp唤醒手机地图app
  17. Tomcat遇到500 The server encountered an internal error that prevented it from fulfilling this request
  18. 电机远计算机控制,电机控制器
  19. thinkpad重装系统不引导_联想Y400电脑装WIN7无法重装系统的解决方法
  20. 超详细的k8s对接ceph RBD存储

热门文章

  1. (转)塔吉特读心术——用户数据分析的魔力
  2. 笔试题-2023-思特威-FPGA【纯净题目版】
  3. 台式计算机接地,台式电脑主机漏电怎么办?
  4. Java HashMap1.7头插法扩容时出现循环链表 1.8换成尾插法
  5. 西农新版锐捷linux系统客户端联网方法
  6. windows 下实现socket编程_传送文件
  7. c语言堆栈基本代码入栈出栈_顺序栈基本操作(入栈和出栈)C语言详解
  8. “信创产业”是什么?2020“信创”脱颖而出
  9. 苹果13和苹果14的差异
  10. 登陆qq时显示服务器错误,刚才想上QQ的时候,显示无法登陆QQ,显示连接服务器超时,错误代码0x00000001是怎么回事啊!!急...