OpenCV2编程手册笔记之 4.2计算图像的直方图
来源:互联网 发布:市场大数据分析 编辑:程序博客网 时间:2024/06/10 14:19
在一个单通道的灰度图像中,每个像素的值都介于0(黑色)——255(白色)之间
根据这点,灰度图像的直方图拥有256个条目,这些条目也称之为容器。
现在,我们以灰度形式读取一张图片,并且定义一个直方图处理类来方便的处理直方图操作。
在这个类中,我们先声明变量并编写构造函数:
private:
int histSize[1];
float hranges[2];
const float * ranges[1];
int channels[1];
public:
Histogram1D()
{
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0;
}
这是一个单通道图像的变量初设值
之后,我们定义一个直方图获取方法:
其中最主要的函数就是calcHist
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是待处理的图像
nimages是图像的数量,输入1就是一张图片
channels是指针类型,因此在变量声明中使用数组进行声明,代表着图像的通道数,例如灰度图就是单通道
mask是掩码,这里可以默认为cv::Mat
hist是返回的直方图,推荐采用MatND进行定义
dims是维数,一维直方图就输入1就好
histSize是项的数量,也就是容器的数量。但注意它是指针类型,因此变量声明也采用了数组形式。这里有256个容器,因此构造时为256
ranges是像素范围,注意这是一个二维数组。在这个图像中,像素范围是0-255
这里要注意,ranges是float型的,如果使用.at操作获取数值,<>中应为float,后面代码中会看到
其他两个量被opencv初始化,不需要管了
这样,我们只需要初始化对象并调用方法,就可以获取直方图了。
源代码:
class Histogram1D
{
private:
int histSize[1];
float hranges[2];
const float * ranges[1];
int channels[1];
public:
Histogram1D()
{
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0;
}
cv::MatND getHistogram(const cv::Mat &image);
};
cv::MatND Histogram1D::getHistogram(const cv::Mat &image)
{
cv::MatND hist;
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges);
return hist;
}
int main()
{
cv::Mat image = cv::imread("F:\\group.jpg", 0);
Histogram1D h;
cv::MatND histo = h.getHistogram(image);
for (int i = 0; i < 256; i++)
{
std::cout << histo.at<float>(i) << std::endl;
}
cv::waitKey(0);
return 0;
}
for这里可以遍历得到数据,注意那个float
--------------------------------------------这时一条华丽的分割线------------------------------------------------------
如果上面看懂了,那么就可以来看看下面
大家可能会了获取直方图,但是用柱状图的方式表示出来,就会显得更加直观
在这个类中,我们首先获取传入图像的直方图数据,并且获得最大值和最小值,这里采取minMaxLoc函数
之后,生成一个空白的长宽都为256的底板图像histImg
由于每个直方图都必然有一个最高点,而这个最高点如果触顶了显得不那么美观。所以,我们设置一个直方图最高点(hpt)来避免这种事情。
之后,就是逐点画出直线了,我们采取比例的办法。例如:
某一个“容器”,例如128这个灰度值,它容纳了1000个点。上文已经知道,最大值是maxVal,那么我们的线的相对长度就是:
hist.at<float>(128) * hpt / maxVal ->128为例计算相对长度
现在,就都做好了。
源代码:
Histogram1D类中的getHistogramImage处理方法:
cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image)
{
cv::MatND hist = getHistogram(image);
double maxVal;
double minVal;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
cv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255));
int hpt = static_cast<int>(0.9 * histSize[0]);
for (int h = 0; h < histSize[0]; h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal * hpt / maxVal);
cv::line(histImg, cv::Point(h, histSize[0]), cv::Point(h, histSize[0] - intensity), cv::Scalar::all(0));
}
return histImg;
}
这个类中,我想说的是那个减号
用减号的原因大家可以想想,图像的坐标系和坐标变换,在这里就不再叙述了
主函数:
int main()
{
cv::Mat image = cv::imread("F:\\group.jpg", 0);
Histogram1D h;
cv::MatND histo = h.getHistogram(image);
for (int i = 0; i < 256; i++)
{
std::cout << histo.at<float>(i) << std::endl;
}
cv::imshow("Histogram", h.getHistogramImage(image));
cv::waitKey(0);
return 0;
}
- OpenCV2编程手册笔记之 4.2计算图像的直方图
- OpenCV2编程手册笔记之 4.2计算图像的直方图(彩色)
- opencv2学习笔记:4.2计算图像直方图
- OpenCV2编程手册笔记之 6.5计算图像的拉普拉斯变换
- OpenCV2编程手册笔记之 4.5反投影直方图以检测特定图像内容
- OpenCV2编程手册笔记之 4.4直方图均衡化
- OpenCV2编程手册笔记之 2.3指针遍历图像
- OpenCV2编程手册笔记之 2.4迭代器遍历图像
- OpenCV2编程手册笔记之 7.6计算连通区域的形状描述符
- OpenCV2:图像的直方图
- opencv2对读书笔记——计算图像的直方图
- opencv2—(7)计算图像的直方图
- 图像处理学习笔记之直方图的计算与绘制
- OpenCV2编程手册笔记之 5.2形态学滤波对图像进行腐蚀、膨胀运算
- OpenCV2编程手册笔记之 5.3形态学滤波对图像进行开闭运算
- OpenCV2编程手册笔记之 5.5分水岭算法对图像进行分割
- OpenCV2编程手册笔记之 4.3查找表修改图像外观
- OpenCV2学习笔记(二):图像的直方图
- javascript读书笔记之变量、作用域和内存问题
- Android学习笔记三十六之网络数据解析
- 第一个接口性能测试实例
- github使用
- 关于ArcSDE用户模式
- OpenCV2编程手册笔记之 4.2计算图像的直方图
- HDOJ1233. 还是畅通工程(并查集+最小生成树)
- SQL Injection(1)
- Java Collection的操作示例
- 面试OR笔试30——单链表环入口节点
- 1008. Elevator (20)
- leetcode 52. N-Queens II DFS深度优先遍历
- Android学习笔记三十七之基于TCP的socket通信
- Spark 机器学习《一》