《OpenCV2》编程手册——使用直方图统计像素

来源:互联网 发布:sql server 笛卡尔积 编辑:程序博客网 时间:2024/06/06 02:22

计算图像的直方图

  • 图像是由像素组成的,在一个单通道的灰度图像中,每个像素的值介于0~255之间。直方图是一个简单的表,给出了一副图像或一组图像中拥有给定数值的像素数量。灰度图像 的直方图有256个条目(容器)。0号容器给出值为0的像素个数,1号容器给出值为1的像素个数,以此类推。

定义一个专门的类处理单通道的灰度图像。

class Histogram1D{private:    int histSize[1];//项的数量    float hranges[2];//像素的最小及最大值    const float* ranges[1];    int channels[1];//仅用到一个通道public:    Histogram1D(){        //准备1D直方图的参数        histSize[0] = 256;        hranges[0] = 0.0;        hranges[1] = 255.0;        ranges [0] = hranges ;        channels[0] = 0;//默认情况考察0号通道    }

计算一个灰度直方图的方法,返回对象是一个拥有256个条目的一维数组。

//计算1D直方图MatND getHistogram(const Mat &image){    MatND hist;    calcHist(&image,        1,//计算单张图像的直方图        channels,//通道数量        Mat (),//不适用图像作为掩码        hist,//返回的直方图        1,//1D的直方图        histSize,//项的数量        ranges//像素值的范围        );    return hist;}

将直方图以柱状图的形式显示。

//计算1D直方图并返回一副图像Mat getHistogramImage(const Mat &image){    //首先计算直方图    MatND hist = getHistogram(image);    //获取最大值和最小值    double maxVal = 0;    double minVal = 0;    minMaxLoc(hist, &minVal, &maxVal, 0, 0);    //显示直方图的图像    Mat histImg(histSize[0], histSize [0], CV_8U, Scalar(255));    //设置最高点为nbins的90%    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);        //两点之间绘制一条直线        line(histImg, Point(h,histSize [0]),            Point(h,histSize [0]-intensity),            Scalar::all(0));    }    return histImg;}

结果图像峰值处的值可做为二值化的阈值。

使用查找表修改图像外观

  • 查找表是一个简单的一对一(多对一)函数,定义了如何将像素值转换为新的值,本质上是一个一维数组,对于常规灰度图像而言有256个项目,表的第i项表示相应的灰度的新值。

创建一个查找表反转像素的强度。

//创建图像的反向查找表int dim(256);Mat lut(1, //1D    &dim, //256项    CV_8U);//ucharfor(int i = 0; i<256; i++){    lut.at<char>(i) = 255-i;}

对图像应用查找表以生成新图像。

Mat applyLookUp(const Mat& image, const Mat& lookup){    Mat result;    //应用查找表    LUT(image, lookup, result);    return result;}

通过拉伸直方图能得到扩展后的对比度,旨在检测直方图中非零项的最低(imin)和最高(imax)强度值,强度值可以被重新映射,这样imin值是重新定位在强度0,imax是分配值255。

Mat stretch (const Mat&image, int minValue=0){    //计算直方图    MatND hist = getHistogram(image);    //寻找直方图的左端    int imin = 0;    for(;imin<histSize[0]; imin++){        std::cout<<hist.at<float>(imin)<<std::endl;        if(hist.at<float>(imin)>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++){        //确保数值位于imin与imax之间        if(i<imin){            lookup.at<uchar>(i)=0;        }        else{            if(i>imax){                lookup.at<uchar>(i) =255;            }            //线性映射            else {                lookup.at<uchar>(i) = static_cast<uchar>                    //中间强度线性映射                    (255.0*(i-imin)/(imax-imin)+0.5);            }        }    }    //应用查找表    Mat result;    result = applyLookUp(image, lookup);    return result;}
0 0