Opencv Cookbook阅读笔记(四):用直方图统计像素

灰度直方图的定义

灰度直方图是灰度级的函数,描述图像中该灰度级的像素个数(或该灰度级像素出现的频率):其横坐标是灰度级,纵坐标表示图像中该灰度级出现的个数(频率)。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>  

using namespace cv;
using namespace std;

class Histogram1D
{
    //定义一个处理单通道的类
private:
    int histSize[1];//bin的数量
    float hranges[2];//值范置
    const float* ranges[1];//值范围的指针.指向常量的指针(所指对像不一定是个常量),不能通过指针修改其值
    int channels[1];//通道数量

    Mat getHistogram(const Mat &image)
    {
        //统计直方图
        Mat hist;
        calcHist(&image, 1,//一个图像的直方图
            channels,//使用的通道
            Mat(),//不使用掩码
            hist,//作为结果的直方图
            1,//一维直方图
            histSize,
            ranges
            );

        return hist;
    }

public:
    Histogram1D()
    {
        histSize[0] = 256;
        hranges[0] = 0;//从0到256
        hranges[1] = 256;

        ranges[0] = hranges;

        channels[0] = 0;
    }

    Mat getImageOfHistogram(const Mat &image, int zoom=1)
    {
        //zoom通道数
        //画出直方图

        Mat hist = getHistogram(image);

        return getImageOfHistogram1(hist, zoom);
    }

    //定义为静态,不对成员变量进行操作
    static Mat getImageOfHistogram1(const Mat &hist, int zoom)
    {
        //取得箱子的最大值和最小值
        double maxVal = 0, minVal = 0;
        minMaxLoc(hist, &minVal, &maxVal,0,0);

        int histSize = hist.rows;
        //用于显示的直方图
        Mat histImg(histSize*zoom, histSize*zoom, CV_8U, Scalar(255));
        //设置最高点为90%的箱子个数
        int hpt = static_cast<int>(0.9*histSize);

        //为每个箱子画垂线
        for (int h = 0; h < histSize; h++)
        {
            float binVal = hist.at<float>(h);
            if (binVal>0)
            {
                int intensity = static_cast<int>(binVal*hpt / maxVal);//相对高度
                line(histImg, Point(h*zoom, histSize*zoom),
                    Point(h*zoom, (histSize - intensity)*zoom),
                    Scalar(0), zoom);
            }
        }

        return histImg;
    }
};

int main()
{

    Mat image = imread("1.jpg");
    //判断是否为空
    Histogram1D h;
    //Mat histo = h.getHistogram(image);
    Mat histo = h.getImageOfHistogram(image);
    //namedWindow("Histogram");
    //imshow("Histogram",histo);
    //输出二值图像
    Mat thresholded;
    threshold(image, thresholded, 200,//阈值
        255,//对超过域值的像素赋值
        THRESH_BINARY);//阈值化类型

    imshow("threshold", thresholded);
    waitKey(0);

    return 0;
}

上面的程序是计算并画出单通下图像的直方图,主要就是calcHist函数。类似的可以定义一个计算彩色直方图的类。

class ColorHistgoram
{
private:
    int histSize[3];
    float hranges[2];
    const float*ranges[3];
    int channels[3];
public:
    ColorHistgoram()
    {
        histSize[0] = histSize[1] = histSize[2] = 256;
        hranges[0] = 0;
        hranges[1] = 256;

        ranges[0] = hranges;
        ranges[1] = hranges;
        ranges[2] = hranges;

        channels[0] = 0;
        channels[1] = 1;
        channels[2] = 2;
    }

    Mat getHistogram(const Mat &image)
    {
        Mat hist;

        calcHist(&image,1, channels, Mat(), hist, 3, histSize, ranges);

        return hist;
    }
};

提高图像对比度

有两种方法,一是应用查找表来伸展直方图(有的强度值范围没有被利用),另一种是直方图均衡化(对所有可用的像素强度值都均衡使用)。

//查找表函数
    static Mat applyLookUp(const Mat &image, const Mat &lookup)
    {
        Mat result;
        LUT(image, lookup, result);

        return result;
    }

    //通过查找表提高图像的对比度
    Mat stretch(const Mat &image, int minValue = 0)
    {
        Mat hist = getHistogram(image);

        //找到直方图的左右限值
        float imin;
        for (imin=0;imin < histSize[0]; imin++)
        {
            //忽略数量较少的箱子
            float x = hist.at<float>(imin);
            if (x>minValue)
                break;
        }
        int imax = histSize[0] - 1;
        for (; imax >= 0; imax--)
        {
            if (hist.at<float>(imax)>minValue)
                break;
        }

        //创建查找表
        int dim(256);
        Mat lookup(1,//一维
            &dim, CV_8U);
        for (int i = 0; i < 256; i++)
        {
            //
            if (i < imin)lookup.at<uchar>(i) = 0;
            else if (i>imax)lookup.at<uchar>(i) = 255;
            else
                lookup.at<uchar>(i) = cvRound(255.0*(i - imin) / (imax - imin));
        }

        Mat result;
        result = applyLookUp(image, lookup);

        return result;
    }

通过如下的函数可实现直方图均衡化。

//灰度图
    equalizeHist(image, result);
时间: 2024-08-28 10:38:08

Opencv Cookbook阅读笔记(四):用直方图统计像素的相关文章

【ShaderLab】Cookbook阅读笔记01

<Unity Shaders and Effects Cookbook>阅读笔记,找了很久ShaderLab的教程......结合官网教程学习ShaderLab. 用一个最简单的Shader展示一下shader代码的结构: 第一行代码Shader后跟的是shader的名字,在给Material添加Shader时根据shader名找到对应shader: 以上这个再简单不过的Shader由Properties部分和SubShader部分构成. 其中Properties定义了一系列Shader中用到

阅读笔记四

软件需求模式的第四章--使用和编写需求模式阅读笔记 在学习了需求模式的机制之后,开始教我们学习如何来编写需求模式. 首先我们要知道,什么时候要用到需求模式.在定义系统期间,6种情况下需要用到需求模式,分别是当定义需求时,看是否存在可以指导如何定义这种需求.当考虑需求是否完全时,浏览主题覆盖的整套模式,是否还有遗漏,或者是否还需要添加什么东西.当评审需求规格时,模式可以帮助检查需求的质量,确定还有那些主题没有定义,理解特定需求的意义和内涵.当评估系统的规模以及开发所需的工作量时基于需求,需求模式可

构建之法阅读笔记四—团队开发

构建之法阅读笔记—团队开发 软件开发过程中有团队和非团队之分.其区别就在于目标利益的不同,团队中每个人的目标是一致的.共同的,会根据实际情况给每个人分配不同的任务,不会计较个人利益的得失.非团队每个人的目标都是不同的,大家都为自己的利益而奋斗. 在阅读了构建之法后,我了解到团队开发有以下的特点:1.团队开发有一致的集体目标,团队要完成这个目标.一个团队成员不一定要同时工作.2.团队成员有各自的分工,互相依赖合作,共同完成任务.还有完成一个项目开发的工作流有业务建模,需求,分析和设计,实现,测试,

《大型网站技术架构:核心原理与案例分析》阅读笔记四

本次第四章<瞬时响应:网站的高性能架构>的内容概述和阅读体会写一下. 网站的性能是客观的指标,可以具体体现到响应时间.吞吐量等技术指标,同时也是主观的感受,用户感受和工程师感受不同. 性能测试是性能优化的前提和基础,也是性能优化结果的检查和度量标准.不同视角下的网站性能是不同的,用户.开发人员和运维人员的视角是不同的.开发和测试人员的视角,网站性能测试的主要指标有响应时间.并发数.吞吐量和性能计数器等. 性能优化分为Web前端性能优化.应用服务器性能优化.存储服务器性能优化.浏览器访问优化可以

《架构之美》阅读笔记四

今天我阅读了<架构之美>第五章面向资源的架构在web中,这一章讲到现在我们过分强调了软件和服务,而却忽视了数据,现在大多数组织机构更容易在web上找到信息,而不是在他们自己的系统中.web在很大程度上是因为它增大了信息共享的可能性,同时也降低了门槛. 面向资源的架构的标识是向命名的资源发起逻辑请求的过程.这种请求由某种引擎解释,转成该资源的物理表现形式,面向资源的架构方法很优雅的实现了一些折中,一方面,对于传统的方法来说,这些方法可能看起来有些奇怪,而且没有尝试过.另一方面,它代表了人们设想和

构建之法阅读笔记四。

关于需求部分的分析,我又有了新的认识.一开始我只想到用户提出什么样的要求和建议才算得上是需求.现在发现,原来需求也可以是开发人员替用户想到的,例如游戏玩法方面,用户也不知道自己会喜欢什么样的玩法,这些就要由开发人员分析.而且需求也分功能需求,如学生选课得先修完某一课. 我对用户调查问卷这个部分也有一些看法.其实在让用户填写资料的时候也涉及这个问题,不格外注意的话我也描述不到尽善尽美,就是如何让用户明白他应该输入什么样的格式.注释越多,越显得冗杂.因此适量字数且清楚描述很重要.一谈到调查问卷,我就

Canny边缘检测及图像缩放之图像处理算法-OpenCV应用学习笔记四

在边缘检测算法中Canny颇为经典,我们就来做一下测试,并且顺便实现图像的尺寸放缩. 实现功能: 直接执行程序得到结果如下:将载入图像显示在窗口in内,同时进行图像两次缩小一半操作将结果显示到i1,i2窗口内,Canny边缘提取结果显示在i3. 函数精析: void cvPyrDown(const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 ) 使用Gaussian金字塔分解输入图像向下采样 dst:输出指定尺寸图像,跟原图像同类型 首先

架构之美阅读笔记四

首先要确定系统的功能和约束,也就是,它必须做什么以及在什么限制条件下工作,这样也就确定了问题空间.接下来我们要了解事实,重要问题和架构的关注点.确定工作流也是一个极为重要的步骤,来自于我们对于如何划分系统的考虑. 系统架构常见的关注点有,功能性:产品向特的用户提供哪些功能?可变性:软件将来可能需要哪些改变?性能:产品将达到怎样的性能?容量:多少用户可以并发使用该系统?该系统将为用户保存多少数据?生态系统:在不是的生态环境中,该系统将于其他系统进行哪些交互?模块化:如何将编写软件的任务分解为工作指

《需求分析与系统设计》阅读笔记四

信息系统从定义上就是多用户系统.多个用户和应用程序可以通过数据库管理系统并发访问同一个数据库.应用程序依赖与数据库的不仅仅是数据,还有数据库提供的解决并发冲突.保证数据的安全访问.保证数据一致性.事务错误恢复等功能.类模型和PCBMER子系统中只包含应用类,而不包含数据库结构的存储.实体类表示应用程序中持久数据库对象,但实体类不是数据库中的持久类.必须谨慎设计业务对象和持久数据库之间的关系. 数据库就像程序设计语言一样,为建模和程序设计提供了固有数据类型作为基本构造块,这些固有数据类型称为原始类