OpenCV学習(画像のヒストグラム計算)

5978 ワード

OpenCV計算画像のヒストグラム
画像のヒストグラムを計算することは画像処理分野で非常に一般的な基本動作である.OpenCVには、画像ヒストグラムを計算するためのcalcHist関数が用意されています.しかし、この関数は正直に言うと使いにくいので、長い間研究してやっと基本的な使い方を身につけました.
CalcHist関数C++の関数プロトタイプは以下の通りです.
void calcHist(const Mat* images, 
    int nimages, 
    const int* channels, 
    InputArray mask, 
    SparseMat& hist, 
    int dims, 
    const int* histSize, 
    const float** ranges, 
    bool uniform=true, 
    bool accumulate=false )

各パラメータの意味は次のとおりです.
  • images:入力された画像のポインタは、複数の画像であってもよいが、すべての画像に同じ深さ(CV_8 U or CV_32 F)が必要である.1つの副画像に複数のchannelsを有することができる.
  • nimages:入力された画像の個数.
  • channels:ヒストグラムのchannelsを計算するための配列.
  • mask:マスクです.maskが空でない場合は、8ビット(CV_8 U)の配列でなければなりません.入力された画像と同じサイズで、0以外の値の点がヒストグラムを計算するために使用されます.
  • hist:パラメータを出力し、計算したヒストグラム.
  • dims:ヒストグラムの次元数、CV_より大きくないMAX_DIMS(既存バージョンでは32).
  • histSize:各次元のヒストグラムの要素の数.
  • ranges:ヒストグラムの各次元の範囲を計算する必要があります.rangesは配列を指す配列です.私たちはそれが指す配列をrangesの要素と呼び、要素の大きさ、つまりこれらの配列の長さです.

  • パラメータuniformがtrueの場合、このときのrangesの要素の大きさは2(つまりrangesは一連の長さ2の配列を指す)であり、1次元当たりの上下限の2つの数字が格納される.パラメータuniformがfalseである場合、このときのrangesの要素の大きさはbinの個数であり、1次元当たりの座標値が必ずしも均一ではなく、人為的に指定する必要がある.
  • uniform:trueの場合、計算するヒストグラムの各次元がその範囲と寸法の大きさに従って均一に値を取ることを示します.falseの場合、ヒストグラムの各次元が均一に分布して値を取らないことを説明し、パラメータrangesの説明を参照します.
  • accumulate:受信したhistをクリアするかどうかを示します.クリアしないと複数の画像のヒストグラムを加算できます.

  • 上の説明を見ると、この関数がどれほど面倒なのか、皆さんは感じられるでしょう.しかし、私たちは一般的に最も基本的な機能しか使いません.たとえば、単一チャネル階調画像のヒストグラムを計算します.ヒストグラムの値の範囲は一般的に0から255です.このとき、この関数をもう一度カプセル化して、より使いやすくすることができます.
    次のコードは『OpenCV 2 Computer Vision Application Programming Cookbook』から来ています.本の著者はHistogram 1 Dというクラスを書いた.
    このクラスの宣言は次のとおりです.
    class Histogram1D
    {
    public:
        Histogram1D()
        {
            // Prepare arguments for 1D histogram
            histSize[0] = 256;
            hranges[0] = 0.0;
            hranges[1] = 255.0;
            ranges[0] = hranges;
            channels[0] = 0; // by default, we look at channel 0
        }
        ~Histogram1D();
        // Computes the 1D histogram and returns an image of it.
        cv::Mat getHistogramImage(const cv::Mat &image);
        // Computes the 1D histogram.
        cv::MatND getHistogram(const cv::Mat &image);
    private:
        int histSize[1]; // number of bins
        float hranges[2]; // min and max pixel value
        const float* ranges[1];
        int channels[1]; // only 1 channel used here
    
    };
    

    getHistogram関数はヒストグラムを計算するために使用されます.次のようになります.
    // Computes the 1D histogram.
    cv::MatND Histogram1D::getHistogram(const cv::Mat &image)
    {
        cv::MatND hist;
        // Compute histogram
        cv::calcHist(&image,
            1, // histogram from 1 image only
            channels, // the channel used
            cv::Mat(), // no mask is used
            hist, // the resulting histogram
            1, // it is a 1D histogram
            histSize, // number of bins
            ranges // pixel value range
        );
        return hist;
    }
    

    getHistogramImage関数は、ヒストグラムの画像を生成するために使用されます.
    // Computes the 1D histogram and returns an image of it.
    cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image)
    {
        // Compute histogram first
        cv::MatND hist = getHistogram(image);
        // Get min and max bin values
        double maxVal = 0;
        double minVal = 0;
        cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
        // Image on which to display histogram
        cv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255));
        // set highest point at 90% of nbins
        int hpt = static_cast<int>(0.9 * histSize[0]);
        // Draw a vertical line for each bin
        for( int h = 0; h < histSize[0]; h++ )
        {
            float binVal = hist.at<float>(h);
            int intensity = static_cast<int>(binVal * hpt / maxVal);
            // This function draws a line between 2 points
            cv::line(histImg, cv::Point(h, histSize[0]),
            cv::Point(h,histSize[0]-intensity), cv::Scalar::all(0));
        }
        return histImg;
    }
    

    カラー画像のヒストグラムを計算できる別のクラスもあります.しかし、この用途はあまり大きくありません.カラー画像の色空間が大きすぎるからです.そして形成されたヒストグラムは3次元の配列である.使いづらい.完全なために、ここではコードを列挙しました.
    class ColorHistogram
    {
    public:
        ColorHistogram()
        {
            // Prepare arguments for a color histogram
            histSize[0] = histSize[1] = histSize[2] = 256;
            hranges[0] = 0.0; // BRG range
            hranges[1] = 255.0;
            ranges[0] = hranges; // all channels have the same range
            ranges[1] = hranges;
            ranges[2] = hranges;
            channels[0] = 0; // the three channels
            channels[1] = 1;
            channels[2] = 2;
        }
        cv::MatND getHistogram(const cv::Mat &image) ;
        cv::SparseMat getSparseHistogram(const cv::Mat &image) ;
    private:
        int histSize[3];
        float hranges[2];
        const float* ranges[3];
        int channels[3];
    };
    

    ここでは2つの関数getHistogramとgetSparseHistogramを実現した.唯一の違いはgetSparseHistogramが返すのは疎行列です.
    cv::MatND ColorHistogram::getHistogram(const cv::Mat &image)
    {
        cv::MatND hist;
        // Compute histogram
        cv::calcHist(&image,
                     1, // histogram of 1 image only
                     channels, // the channel used
                     cv::Mat(), // no mask is used
                     hist, // the resulting histogram
                     3, // it is a 3D histogram
                     histSize, // number of bins
                     ranges // pixel value range
                     );
        return hist;
    }
    
    cv::SparseMat ColorHistogram::getSparseHistogram(const cv::Mat &image)
    {
        cv::SparseMat hist(3,histSize,CV_32F);
        // Compute histogram
        cv::calcHist(&image,
                     1, // histogram of 1 image only
                     channels, // the channel used
                     cv::Mat(), // no mask is used
                     hist, // the resulting histogram
                     3, // it is a 3D histogram
                     histSize, // number of bins
                     ranges // pixel value range
                     );
        return hist;
    }