99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

OpenCV直方圖計算

2018-09-19 10:49 更新

目標

在本教程中,您將學習如何:

  • 使用OpenCV函數(shù)cv :: split將圖像分割成對應的平面。
  • 使用OpenCV函數(shù)cv :: calcHist來計算圖像數(shù)組的直方圖
  • 使用函數(shù)cv :: normalize對數(shù)組進行歸一化
注意
在上一個教程(直方圖均衡)中,我們討論了一種稱為“ 圖像直方圖”的特定類型的直方圖?,F(xiàn)在我們將在其更一般的概念中思考。

什么是直方圖?

  • 直方圖是將數(shù)據(jù)組織成一組預定義倉的收集計數(shù)
  • 當我們說數(shù)據(jù)時,我們并不把它限制為強度值(正如我們在前面的教程中看到的)。收集的數(shù)據(jù)可以是您發(fā)現(xiàn)有用的描述您的圖像的任何功能。
  • 我們來看一個例子。假設(shè)矩陣包含圖像的信息(即范圍內(nèi)的強度):0?255

OpenCV直方圖計算

  • 如果我們想以有組織的方式計算這些數(shù)據(jù)會怎么樣?由于我們知道這種情況下的信息值范圍是256個值,所以我們可以在子部分(稱為bins)中劃分我們的范圍,如:

OpenCV直方圖計算

我們可以保持落在每個范圍內(nèi)的像素數(shù)量。將其應用于上述示例,我們得到下面的圖像(x軸表示bins和軸y表示每個像素的數(shù)目)。

OpenCV直方圖計算

  • 這只是一個簡單的直方圖的例子,為什么它是有用的。直方圖不僅可以保持顏色強度的計數(shù),還可以保持我們想要測量的任何圖像特征(即梯度,方向等)。
  • 我們來確定直方圖的一些部分:
  1. dims:要收集數(shù)據(jù)的參數(shù)數(shù)。在我們的示例中,dims = 1,因為我們只計算每個像素的強度值(在灰度圖像中)。
  2. bins:每個暗淡的細分數(shù)。在我們的例子中,bin = 16
  3. range:要測量的值的限制。在這種情況下:range = [0,255]

如果你想計算兩個功能怎么辦?在這種情況下,您生成的直方圖將是一個3D圖(其中x和y將為和  ,而z將每個組合的計數(shù)。這同樣適用于更多的功能(當然會變得更棘手)。

OpenCV為您提供什么

為了簡單起見,OpenCV實現(xiàn)了函數(shù)cv :: calcHist,它計算一組數(shù)組(通常是圖像或圖像平面)的直方圖。它最多可以操作32個維度。我們將在下面的代碼中看到它!

Code

  • 這個程序是做什么的?加載圖像使用函數(shù)cv :: split將圖像分解為R,G和B平面通過調(diào)用函數(shù)cv :: calcHist計算每個1通道平面的直方圖在窗口中繪制三個直方圖
  • 可下載的代碼:點擊這里
  • 代碼一覽:
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
  Mat src, dst;
  String imageName( "../data/lena.jpg" ); // by default
  if (argc > 1)
  {
      imageName = argv[1];
  }
  src = imread( imageName, IMREAD_COLOR );
  if( src.empty() )
    { return -1; }
  vector<Mat> bgr_planes;
  split( src, bgr_planes );
  int histSize = 256;
  float range[] = { 0, 256 } ;
  const float* histRange = { range };
  bool uniform = true; bool accumulate = false;
  Mat b_hist, g_hist, r_hist;
  calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
  calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
  calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
  // Draw the histograms for B, G and R
  int hist_w = 512; int hist_h = 400;
  int bin_w = cvRound( (double) hist_w/histSize );
  Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
  normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
  normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
  normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
  for( int i = 1; i < histSize; i++ )
  {
      line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
                       Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
                       Scalar( 255, 0, 0), 2, 8, 0  );
      line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
                       Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
                       Scalar( 0, 255, 0), 2, 8, 0  );
      line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
                       Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
                       Scalar( 0, 0, 255), 2, 8, 0  );
  }
  namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
  imshow("calcHist Demo", histImage );
  waitKey(0);
  return 0;
}

說明

  • 創(chuàng)建必要的矩陣:
Mat src,dst;
  • 加載源圖像
src = imread( argv[1], 1 );
if( !src.data )
  { return -1; }
  • 在三個R,G和B平面中分離源圖像。為此,我們使用OpenCV函數(shù)cv :: split
vector<Mat> bgr_planes;
split( src, bgr_planes );

我們的輸入是要分割的圖像(這種情況下有三個通道),輸出是Mat的向量)

  • 現(xiàn)在我們準備開始為每個平面配置直方圖。由于我們正在使用B,G和R planes,我們知道我們的值將在間隔范圍內(nèi)[0,255]

建立箱數(shù)(5,10 ...):

int histSize = 256; //from 0 to 255

設(shè)置值的范圍(如我們所說,在0到255之間)

float range[] = { 0, 256 } ; //the upper boundary is exclusive
const float* histRange = { range };

我們希望我們的箱子具有相同的尺寸(均勻),并在開始時清除直方圖,所以:

bool uniform = true ; bool accumulate = false ;

最后,我們創(chuàng)建Mat對象來保存直方圖。創(chuàng)建3(每個planes一個):

Mat b_hist,g_hist,r_hist;

我們繼續(xù)使用OpenCV函數(shù)cv :: calcHist計算直方圖:

calcHist(&bgr_planes [0],1,0,Mat(),b_hist,1,&histSize,&histRange,uniform,accumulate);
calcHist(&bgr_planes [1],1,0,Mat(),g_hist,1,&histSize,&histRange,uniform,accumulate);
calcHist(&bgr_planes [2],1,0,Mat(),r_hist,1,&histSize,&histRange,uniform,accumulate);

其中的論點是:

  1. **&bgr_planes [0]:**源數(shù)組(s)
  2. 1:源數(shù)組的數(shù)量(在這種情況下,我們正在使用1.我們可以在這里輸入一個數(shù)組列表)
  3. 0:要測量的通道(dim)。在這種情況下,它只是強度(每個陣列是單通道),所以我們只寫0。
  4. Mat():在源數(shù)組上使用的掩碼(指示要忽略的像素的零)。如果未定義,則不使用它
  5. b_hist:要存儲直方圖的Mat對象
  6. 1:直方圖維度。
  7. histSize:每個使用的維數(shù)的數(shù)量
  8. histRange:每個維度要測量的值的范圍
  9. uniformaccumulate:紙箱尺寸相同,直方圖在開始時清除。
  • 創(chuàng)建一個圖像以顯示直方圖:
// Draw the histograms for R, G and B
int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
  • 請注意,在繪制之前,我們首先cv ::歸一化直方圖,使其值落在由輸入的參數(shù)指示的范圍內(nèi):
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );

此函數(shù)接收這些參數(shù):

  1. b_hist:輸入數(shù)組
  2. b_hist:輸出歸一化數(shù)組(可以相同)
  3. 0和** histImage.rows:對于這個例子,它們是對r_hist **的值進行歸一化的下限和上限
  4. NORM_MINMAX:指示歸一化類型的參數(shù)(如上所述,它調(diào)整之前設(shè)置的兩個限制之間的值)
  5. ** - 1:**意味著輸出歸一化數(shù)組將與輸入的類型相同
  6. Mat():可選掩碼
  • 最后,觀察到訪問bin(在這種情況下在這個1D直方圖中):
for( int i = 1; i < histSize; i++ )
{
    line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
                     Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
                     Scalar( 255, 0, 0), 2, 8, 0  );
    line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
                     Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
                     Scalar( 0, 255, 0), 2, 8, 0  );
    line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
                     Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
                     Scalar( 0, 0, 255), 2, 8, 0  );
}

我們使用表達式:

b_hist.at < float >(i)

其中 i 表示尺寸。如果它是一個二維直方圖,我們將使用如下:

b_hist.at<float>( i, j )

最后我們顯示直方圖,等待用戶退出:

namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
imshow("calcHist Demo", histImage );
waitKey(0);
return 0;

結(jié)果

  • 作為輸入?yún)?shù)使用如下所示的圖像:

OpenCV直方圖計算

  • 生成以下直方圖:

OpenCV直方圖計算


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號