OpenCV 4.12.0
開源計算機視覺
載入中...
搜尋中...
無匹配項
直方圖計算

上一個教程: 直方圖均衡化
下一個教程: 直方圖比較

原始作者Ana Huamán
相容性OpenCV >= 3.0

目標

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

  • 使用 OpenCV 函式 cv::split 將影像分成其對應的平面。
  • 使用 OpenCV 函式 cv::calcHist 計算影像陣列的直方圖
  • 使用函式 cv::normalize 對陣列進行歸一化
注意
在上一篇教程(直方圖均衡化)中,我們討論了一種特殊型別的直方圖,稱為 影像直方圖。現在我們將從更一般的概念來考慮它。繼續閱讀!

什麼是直方圖?

  • 直方圖是將資料組織成一組預定義 bins(資料區間)計數 集合
  • 當我們說 資料 時,我們不將其限制為強度值(如我們在上一個教程 直方圖均衡化 中所看到的)。收集到的資料可以是您認為對描述影像有用的任何特徵。
  • 讓我們看一個例子。想象一個矩陣包含影像資訊(即強度範圍在 \(0-255\) 之間)
  • 如果我們想以有組織的方式 計數 這些資料,會發生什麼?由於我們知道在這種情況下,資訊值的 範圍 是 256 個值,我們可以將範圍分割成子部分(稱為 bins),例如:

    \[\begin{array}{l} [0, 255] = { [0, 15] \cup [16, 31] \cup ....\cup [240,255] } \\ range = { bin_{1} \cup bin_{2} \cup ....\cup bin_{n = 15} } \end{array}\]

    我們可以統計落入每個 \(bin_{i}\) 範圍內的畫素數量。將其應用於上面的示例,我們得到下圖(x 軸代表資料區間,y 軸代表每個資料區間中的畫素數量)。

  • 這只是一個關於直方圖如何工作以及為什麼它有用的簡單例子。直方圖不僅可以統計顏色強度,還可以統計我們想要測量的任何影像特徵(即梯度、方向等)。
  • 讓我們識別直方圖的一些部分
    1. dims(維度):您想要收集資料的引數數量。在我們的例子中,dims = 1,因為我們只統計每個畫素的強度值(在灰度影像中)。
    2. bins(資料區間):每個維度中的 細分 數量。在我們的例子中,bins = 16
    3. range(範圍):要測量的值的限制。在這種情況下:range = [0,255]
  • 如果您想統計兩個特徵怎麼辦?在這種情況下,您的結果直方圖將是一個 3D 圖(其中 x 和 y 是每個特徵的 \(bin_{x}\) 和 \(bin_{y}\),z 是每個 \((bin_{x}, bin_{y})\) 組合的計數)。對於更多特徵也是如此(當然會變得更復雜)。

OpenCV 為您提供了什麼

出於簡單目的,OpenCV 實現了函式 cv::calcHist,它計算一組陣列(通常是影像或影像平面)的直方圖。它可以操作多達 32 個維度。我們將在下面的程式碼中看到它!

程式碼

  • 此程式的作用是什麼?
    • 載入影像
    • 使用函式 cv::split 將影像分割成其 R、G 和 B 平面。
    • 透過呼叫函式 cv::calcHist 計算每個 1 通道平面的直方圖
    • 在一個視窗中繪製三個直方圖

解釋

  • 載入源影像

  • 將源影像分離成其三個 R、G 和 B 平面。為此我們使用 OpenCV 函式 cv::split

    我們的輸入是要分割的影像(本例中具有三個通道),輸出是一個 Mat 向量。

  • 現在我們已準備好開始為每個平面配置 直方圖。由於我們處理的是 B、G 和 R 平面,我們知道我們的值將在 \([0,255]\) 區間內。
  • 設定資料區間的數量(5、10...)

  • 設定值的範圍(如我們所說,在 0 到 255 之間)

  • 我們希望資料區間大小相同(uniform),並在開始時清除直方圖,所以

  • 我們使用 OpenCV 函式 cv::calcHist 來計算直方圖

  • 其中引數是(C++ 程式碼
    • &bgr_planes[0]: 源陣列
    • 1: 源陣列的數量(本例中我們使用 1。我們也可以在此處輸入陣列列表)
    • 0: 要測量的通道(維度)。在這種情況下,它只是強度(每個陣列都是單通道),所以我們只寫 0。
    • Mat(): 用於源陣列的掩碼(零表示要忽略的畫素)。如果未定義則不使用。
    • b_hist: 儲存直方圖的 Mat 物件
    • 1: 直方圖的維度。
    • histSize: 每個使用維度的 bin 數量
    • histRange: 每個維度要測量的值的範圍
    • uniformaccumulate: bin 大小相同,並且直方圖在開始時被清除。
  • 建立影像以顯示直方圖

  • 請注意,在繪製之前,我們首先對直方圖進行 cv::normalize,使其值落在輸入的引數所指示的範圍內。

  • 此函式接收以下引數(C++ 程式碼
    • b_hist: 輸入陣列
    • b_hist: 輸出歸一化陣列(可以是同一個)
    • 0histImage.rows: 在本例中,它們是歸一化 r_hist 值的下限和上限
    • NORM_MINMAX: 指示歸一化型別的引數(如上所述,它將值調整到之前設定的兩個限制之間)
    • -1: 表示輸出歸一化陣列將與輸入型別相同
    • Mat(): 可選掩碼
  • 請注意,要訪問 bin(在此 1D 直方圖中)

    我們使用表示式(C++ 程式碼

    b_hist.at<float>(i)

    其中 \(i\) 表示維度。如果它是 2D 直方圖,我們將使用類似以下內容:

    b_hist.at<float>( i, j )
  • 最後,我們顯示直方圖並等待使用者退出

結果

  1. 使用如下圖所示的影像作為輸入引數
  1. 生成以下直方圖