[OpenCV] Image Processing - Grayscale Transform & Histogram
颜色直方图
首先,先介绍一些Hist的基本使用。
官方文档:https://docs.opencv.org/trunk/d8/dbc/tutorial_histogram_calculation.html
不错博文:利用OpenCV的calcHist绘制灰度直方图、H-S直方图、BGR直方图和自定义直方图的源码及说明
From: compare histograms of grayscale images in opencv
- #include <opencv2/opencv.hpp>
- void show_histogram(std::string const& name, cv::Mat1b const& image)
- {
- // Set histogram bins count
- int bins = ;
- int histSize[] = {bins};
- // Set ranges for histogram bins
- float lranges[] = {, };
- const float* ranges[] = {lranges};
- // create matrix for histogram
- cv::Mat hist;
- int channels[] = {};
- // create matrix for histogram visualization
- int const hist_height = ;
- cv::Mat3b hist_image = cv::Mat3b::zeros(hist_height, bins);
- cv::calcHist(&image, , channels, cv::Mat(), hist, , histSize, ranges, true, false);
- double max_val=;
- minMaxLoc(hist, , &max_val);
- // visualize each bin
- for(int b = ; b < bins; b++) {
- float const binVal = hist.at<float>(b);
- int const height = cvRound(binVal*hist_height/max_val);
- cv::line
- ( hist_image
- , cv::Point(b, hist_height-height), cv::Point(b, hist_height)
- , cv::Scalar::all()
- );
- }
- cv::imshow(name, hist_image);
- }
- int main (int argc, const char* argv[])
- {
- // here you can use cv::IMREAD_GRAYSCALE to load grayscale image, see image2
- cv::Mat3b const image1 = cv::imread("C:\\workspace\\horse.png", cv::IMREAD_COLOR);
- cv::Mat1b image1_gray;
- cv::cvtColor(image1, image1_gray, cv::COLOR_BGR2GRAY);
- cv::imshow("image1", image1_gray);
- show_histogram("image1 hist", image1_gray);
- cv::Mat1b const image2 = cv::imread("C:\\workspace\\bunny.jpg", cv::IMREAD_GRAYSCALE);
- cv::imshow("image2", image2);
- show_histogram("image2 hist", image2);
- cv::waitKey();
- return ;
- }
Histogram equalization
偏差、增益参数
线性混合算子
非线性算子
覆盖算子
直方图均衡化
直方图的观看规则就是“左黑右白”,左边代表暗部,右边代表亮部,而中间则代表中间调。 纵向上的高度代表像素密集程度,越高,代表的就是分布在这个亮度上的像素很多。
对比度


当然,也有看起来不错的低对比度图片,但它的直方图不会像上图那样极端,一般都是没有纯黑,但高光都比较足:
均衡化
(a) vs (e) 对比度有所加强。
However,可能放大暗区域的噪声。
- 它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。
- http://blog.csdn.net/xiaowei_cqu/article/details/7606607
从分布图上的理解就是希望原始图像中y轴的值在新的分布中尽可能的展开。
变换过程是利用累积分布函数对原始分布进行映射,生成新的均匀拉伸的分布。
因此,对应每个点的操作是寻找原始分布中y值在均匀分布中的位置,如下图是理想的单纯高斯分布映射的示意图:
- int main()
- {
- IplImage * image= cvLoadImage("baboon.jpg");
- //显示原图及直方图
- myShowHist("Source",image);
- IplImage* eqlimage=cvCreateImage(cvGetSize(image),image->depth,);
- //分别均衡化每个信道
- IplImage* redImage=cvCreateImage(cvGetSize(image),image->depth,);
- IplImage* greenImage=cvCreateImage(cvGetSize(image),image->depth,);
- IplImage* blueImage=cvCreateImage(cvGetSize(image),image->depth,);
- cvSplit(image,blueImage,greenImage,redImage,NULL);
- cvEqualizeHist(redImage,redImage);
- cvEqualizeHist(greenImage,greenImage);
- cvEqualizeHist(blueImage,blueImage);
- //均衡化后的图像
- cvMerge(blueImage,greenImage,redImage,NULL,eqlimage);
- myShowHist("Equalized",eqlimage);
- }
cvEqualizeHist
此函数只能处理单通道的灰色图像,对于彩色图像,我们可以把每个信道分别均衡化,再Merge为彩色图像。
算法演示:
自定义均衡化
(直方图匹配 or 直方图规定化)
- //将图像与特定函数分布histv[]匹配
- void myHistMatch(IplImage *img,double histv[])
- {
- int bins = ;
- int sizes[] = {bins};
- CvHistogram *hist = cvCreateHist(,sizes,CV_HIST_ARRAY);
- cvCalcHist(&img,hist);
- cvNormalizeHist(hist,);
- double val_1 = 0.0;
- double val_2 = 0.0;
- uchar T[] = {};
- double S[] = {};
- double G[] = {};
- for (int index = ; index<; ++index)
- {
- val_1 += cvQueryHistValue_1D(hist,index);
- val_2 += histv[index];
- G[index] = val_2;
- S[index] = val_1;
- }
- double min_val = 0.0;
- int PG = ;
- for ( int i = ; i<; ++i)
- {
- min_val = 1.0;
- for(int j = ;j<; ++j)
- {
- if( (G[j] - S[i]) < min_val && (G[j] - S[i]) >= )
- {
- min_val = (G[j] - S[i]);
- PG = j;
- }
- }
- T[i] = (uchar)PG;
- }
- uchar *p = NULL;
- for (int x = ; x<img->height;++x)
- {
- p = (uchar*)(img->imageData + img->widthStep*x);
- for (int y = ; y<img->width;++y)
- {
- p[y] = T[p[y]];
- }
- }
- }
- // 生成高斯分布
- void GenerateGaussModel(double model[])
- {
- double m1,m2,sigma1,sigma2,A1,A2,K;
- m1 = 0.15;
- m2 = 0.75;
- sigma1 = 0.05;
- sigma2 = 0.05;
- A1 = ;
- A2 = 0.07;
- K = 0.002;
- double c1 = A1*(1.0/(sqrt(*CV_PI))*sigma1);
- double k1 = *sigma1*sigma1;
- double c2 = A2*(1.0/(sqrt(*CV_PI))*sigma2);
- double k2 = *sigma2*sigma2;
- double p = 0.0,val= 0.0,z = 0.0;
- for (int zt = ;zt < ;++zt)
- {
- val = K + c1*exp(-(z-m1)*(z-m1)/k1) + c2*exp(-(z-m2)*(z-m2)/k2);
- model[zt] = val;
- p = p +val;
- z = z + 1.0/;
- }
- for (int i = ;i<; ++i)
- {
- model[i] = model[i]/p;
- }
- }
cvCalcHist
将图像规定化为高斯分布函数。
算法演示:
计算变换函数 根据 规定的直方图 得来。但非严格单调,所以需要:
(a:s值) --> (b:z值)
发现:S0与G(Z3)竟然一致,正好匹配。
对比直方图
通过直方图匹配,可以使图像的相似度变高,但也仅仅是从颜色的角度。
- int main()
- {
- IplImage * image= cvLoadImage("myhand1.jpg");
- IplImage * image2= cvLoadImage("myhand2.jpg");
- int hist_size=;
- float range[] = {,};
- float* ranges[]={range};
- IplImage* gray_plane = cvCreateImage(cvGetSize(image),,);
- cvCvtColor(image,gray_plane,CV_BGR2GRAY);
- CvHistogram* gray_hist = cvCreateHist(,&hist_size,CV_HIST_ARRAY,ranges,);
- cvCalcHist(&gray_plane,gray_hist,,);
- IplImage* gray_plane2 = cvCreateImage(cvGetSize(image2),,);
- cvCvtColor(image2,gray_plane2,CV_BGR2GRAY);
- CvHistogram* gray_hist2 = cvCreateHist(,&hist_size,CV_HIST_ARRAY,ranges,);
- cvCalcHist(&gray_plane2,gray_hist2,,);
- //相关:CV_COMP_CORREL
- //卡方:CV_COMP_CHISQR
- //直方图相交:CV_COMP_INTERSECT
- //Bhattacharyya距离:CV_COMP_BHATTACHARYYA
- double com=cvCompareHist(gray_hist,gray_hist2,CV_COMP_BHATTACHARYYA);
- cout<<com<<endl;
- }
cvCompareHist
cvCompareHist的结果为【0,1】的浮点数,越小表示两幅图匹配度越高,0.0时两幅图精确匹配。
提供的对比方法有四种:
局部增强 (涉及到统计,大有可为)
分辨亮区域与暗区域的不同,同时只增强暗区域。
[OpenCV] Image Processing - Grayscale Transform & Histogram的更多相关文章
- [OpenCV] Image Processing - Grayscale Transform
"每个像素的输出值只取决于其输入值" 重难点:Histogram equalization 参考:笑得很甜 http://blog.csdn.net/xiaowei_cqu/art ...
- [OpenCV] Image Processing - Fuzzy Set
使用模糊技术进行 (灰度变换Grayscale Transform) 和 (空间滤波Spatial Filtering) 模糊集合为处理不严密信息提供了一种形式. 首先,需要将输入量折算为隶属度,这个 ...
- 使用OpenMP加快OpenCV图像处理性能 | speed up opencv image processing with openmp
本文首发于个人博客https://kezunlin.me/post/7a6ba82e/,欢迎阅读! speed up opencv image processing with openmp Serie ...
- 使用OpenCL提升OpenCV图像处理性能 | speed up opencv image processing with OpenCL
本文首发于个人博客https://kezunlin.me/post/59afd8b3/,欢迎阅读最新内容! speed up opencv image processing with OpenCL G ...
- opencv python:图像直方图 histogram
直接用matplotlib画出直方图 def plot_demo(image): plt.hist(image.ravel(), 256, [0, 256]) # image.ravel()将图像展开 ...
- [OpenCV] Image Processing - Spatial Filtering
"利用给定像素周围的像素的值决定此像素的最终的输出值“ 教学效果: 策略: 1. 拉普拉斯,突出小细节: . 梯度,突出边缘: . 平滑过的梯度图像用于掩蔽: . 灰度变换,增加灰度动态范围 ...
- [OpenCV] Image Processing - Image Elementary Knowledge
"没有坚实的理论基础,实践只会浅尝于表面." 这是两本打基础的书,没系统学过的话,怎么好意思说自己会CV. 该领域,兴军亮 这个名字屡次出现,看来是计算机视觉领域国内的年轻才俊,向 ...
- [Python] python vs cplusplus
一些学习过程中的总结的两种语言的小对比,帮助理解OO programming. Continue... 字典 序列 --> 字典 Python: def get_counts(sequence) ...
- 本人AI知识体系导航 - AI menu
Relevant Readable Links Name Interesting topic Comment Edwin Chen 非参贝叶斯 徐亦达老板 Dirichlet Process 学习 ...
随机推荐
- java随机范围内的日期
使用了最新的java8的java.time类,并提供了LocalDateTime和java.util.Date之间的转换. 使用方法: randomLocalDateTime(-3,3) : 取距离今 ...
- [sed] linux sed 批量替换字符串
比如,要将目录/modules下面所有文件中的zhangsan都修改成lisi,这样做: sed -i "s/zhangsan/lisi/g" `grep zhangsan -rl ...
- linq to sql之组装where条件下的'或'语句
之前遇到过类似的需求,即前台传入几个过滤条件,后台动态组装where. 例如,前台传入name='张三',age=10, 其余的字段,类似email,QQ之类的本次查询时不做过滤. 用linq to ...
- android开发(38) 使用 DrawerLayou t实现左侧抽屉式导航菜单
最近流行 左侧抽屉式的导航条菜单,知乎,360,QQ都使用了这样的导航菜单,我们也了解下: Android Design 的流行趋势:Navigation Drawer 导航抽屉 参考这篇文章:htt ...
- C#内置泛型委托:Func委托
1.什么是Func委托 Func委托代表有返回类型的委托 2.Func委托定义 查看Func的定义: using System.Runtime.CompilerServices; namespace ...
- 删除json对象中空值
function deleteEmptyProperty(obj){ var object = obj; for (var i in object) { var value = object[i]; ...
- 深入浅出学习Hibernate框架(二):JDBC基础操作
上篇博客<深入浅出学习Hibernate框架(一):从实例入手初识Hibernate框架>简单介绍了一下Hibernate框架,并且举了一个实例来了解Hibernate.这篇博客将介绍JD ...
- Sword protobuf学习三
#include <iostream> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> ...
- Qt之QLocalSocket
简述 QLocalSocket类提供了一个本地socket. 在Windows中,这是一个命名管道:在Unix中,这是一个本地网域socket. 如果发生错误,socketError()会返回错误的类 ...
- Java HashSet和HashMap源码剖析
转自: Java HashSet和HashMap源码剖析 总体介绍 之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说Ha ...