OpenCV中图像直方图与应用
OpenCV中图像直方图与应用
图像直方图数据在图像处理中应用十分广泛,根据直方图数据不同常见的有如下三种:
- 图像像素直方图、
- 像素梯度直方图
- 像素角度直方图
后面两个在图像特征提取SIFT与HOG中均有应用。最常见的图像直方图一般都是图像像素值统计直方图。通常我们把每个直方图的单元叫做BIN,对RGB图像来说像素的取值范围为0~255之间,BIN的个数是对取值范围的间隔区分,可以为32、64、128、256。OpenCV中提供了几个非常有用的直方图操作函数,实现了直方图统计计算、到直方图均衡化、直方图反向投影等功能。
图像像素直方图
OpenCV3.1.0中计算直方图的对应函数calcHist
原图如下:
计算得到的直方图如下:
直方图统计与绘制代码如下:
// 加载图像 Mat src = imread("D:/gloomyfish/flower.png"); if (src.empty()) { printf("could not load image...n"); return -1; } namedWindow("refer faces", CV_WINDOW_AUTOSIZE); imshow("refer faces", src); // 三通道分离 vector<Mat> bgr_plane; split(src, bgr_plane); // 定义参数变量 const int channels[1] = { 0 }; const int bins[1] = { 256 }; float hranges[2] = { 0,255 }; const float* ranges[1] = { hranges }; Mat b_hist; Mat g_hist; Mat r_hist; // 计算Blue, Green, Red通道的直方图 calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges); calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges); calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges); // 显示直方图 int hist_w = 512; int hist_h = 400; int bin_w = cvRound((double)hist_w / bins[0]); Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3); // 归一化直方图数据 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 < bins[0]; 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); } // 显示直方图 namedWindow("Histogram Demo", WINDOW_AUTOSIZE); imshow("Histogram Demo", histImage);
直方图均衡化
直方图均衡化是利用统计得到的直方图数据实现直方图分布的调整,然后根据调整之后的直方图对原图像建立查找表,重新映射得到新的像素值,基本原理就是这样。OpenCV中的API函数为 equalizeHist
- src参数表示输入的图像,必须是8位灰度图像
- dst参数表示均衡化之后的图像,大小和类型必须跟输入图像一致
输入原图如下:
直方图均衡化的结果如下:
对于三通道的彩色图像,可以先拆分通道对各个通道进行直方图均衡化之后再合并通道即可。实现代码如下: // 直方图均衡化处理
vector<Mat> dst_bgr(3); equalizeHist(bgr_plane[0], dst_bgr[0]); equalizeHist(bgr_plane[1], dst_bgr[1]); equalizeHist(bgr_plane[2], dst_bgr[2]); Mat dst = Mat::zeros(bgr_plane[0].size(), CV_8UC3); merge(dst_bgr, dst); imshow("EH Demo", dst);
直方图反向投影
直方图反向投影直观的理解就是生成一个模板直方图,然后用它在一副更大的图像上去匹配相似区域,说白了就跟模板匹配类似。为了消除光照对直方图的影响,通常会先对取得的直方图做归一化之后在去做直方图反向投影。直方图反向投影的基本步骤可以分为如下三步
- 获取图像特征的区域-ROI
- 根据ROI生成直方图特征
- 利用直方图特征进行反向投影,在未知图像上寻找特征
OpenCV3.1.0中对应的直方图反向投影API函数为 calcBackProject, 参数就不再赘述啦,各位自己看一下API文档吧! 这里以车牌识别中获取车牌区域为例,通过直方图反向投影可以获取。首先看模板图像
测试图像
直方图反向投影结果
从上面可以根据直方图反向投影结果直接获取车牌ROI区域,只要对车牌模板的蓝色通道直方图生成模板,反向投影即可。反向投影的演示代码如下:
// 归一化直方图数据 normalize(b_hist, b_hist, 1.0, 0.0); // 直方图反向映射 - 加载测试图片 Mat testImg = imread("D:/gloomyfish/5.jpg"); if (testImg.empty()) { printf("could not load test image...n"); return -1; } imshow("test image", testImg); // 反向映射 vector<Mat> bgr; split(testImg, bgr); Mat result; calcBackProject(&bgr[0], 1, channels, b_hist, result, ranges, 255); // 将结果进行阈值化 threshold(result, result, 255*0.1, 255, THRESH_BINARY); imshow("Histogram Back Projection Result", result);
- 数据结构03 线性表之链表
- Java基础-12(01)总结Scanner,String
- 通过shell绑定系统进程调优 (r4笔记第34天)
- Mybatis【入门】
- 数据结构04 链表的面试题
- 数据结构05 栈
- Mybatis【配置文件】
- Java 非线程安全的HashMap如何在多线程中使用
- Java基础-12(02)总结Scanner,String
- MySQL和Oracle对比学习之数据字典元数据(r4笔记第33天)
- Java中ArrayList与LinkedList的区别
- Mybatis【关联映射】
- Java中String、StringBuffer、StringBuilder的区别
- 一条全表扫描sql语句的分析 (r4笔记第32天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 国标GB28181协议客户端EasyGBS国标视频平台级联EasyNVR:EasyGBS如何实现调阅EasyNVR的视频通道?
- gitlab CI/CD 相关问题
- 微信jssdk分享接口
- 有赞 Flutter 混编方案
- 最近开发问题
- echarts相关问题总结
- 视频上云EasyNTS组网硬件设备登录后自动下线并清除设备信息是什么原因?
- 震惊! 再也不怕蹭网被发现了!
- 国标GB28181协议客户端EasyGBS国标视频平台级联EasyNVR:EasyNVR到EasyGBS上是如何注册及注销的?
- git全局忽略文件配置
- 2018-10-16近期vue开发总结
- 有赞埋点实践
- 树莓派配置LEDE(openwrt衍生版)拨号
- Android 沉浸式解析和轮子使用
- 腾讯云CDN使用(接入方式:COS源)