• 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;
    }
    View Code

    上面的程序是计算并画出单通下图像的直方图,主要就是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;
        }
    };
    View Code

    提高图像对比度

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

    //查找表函数
        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;
        }
    View Code

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

    //灰度图
        equalizeHist(image, result);
  • 相关阅读:
    15个让人惊讶的 CSS3 动画效果演示
    40免费的 jQuery & CSS3 图片热点特效
    分享35款最新出炉的免费个人博客模板
    美!视差滚动在图片滑块中的应用【附源码下载】
    让人惊叹的的创意404错误页面设计
    经典网页设计:10个响应式设计的购物网站
    20幅妙不可言的光涂鸦摄影作品
    值得一试的8个最佳云端集成开发环
    新入行程序员应知的十个秘密
    赞!超炫的页面切换动画效果【附源码下载】
  • 原文地址:https://www.cnblogs.com/573177885qq/p/5672841.html
Copyright © 2020-2023  润新知