iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0

一、 介紹

積分圖(Integral Image)是一個在影像處理中非常有用的數學工具,積分圖又稱總和面積表(Summed Area Table)。它是一種特殊的影像表示方法,可以快速計算圖像中任何區域內像素值的總和。能夠在計算區域總合時能夠提供高效率的運算,不是像傳統方法一樣需要對影像進行摺積運算,廣泛應用於計算影像的各種區域特性,如總和、平均值等。

二、 原理

1. 積分圖(Integral Image)

積分圖可以用以下的數學公式表示:
https://ithelp.ithome.com.tw/upload/images/20230920/201617329xLZ0T0ESR.png

  • f(x,y):一張大小為NxM的輸入的影像函數。
  • I(x,y):積分圖輸出,矩陣的大小為N+1xM+1

如果你對影像函數f(x,y)的表示法還很陌生,你可以先參考這篇文章:【Day8】影像處理的數學基礎:深入解析影像摺積原理

積分圖的核心概念是將原始影像的像素值累加形成一個新的影像,其中每個像素值表示從圖片的左上角開始到目前位置的加總。而因為積分圖會對第一行、第一列的像素做初始化填0,所以輸出的矩陣會多一行、多一列。以下是積分圖的例子,請搭配下圖參考。

  1. 對第一行、第一列的像素全部填0,代表積分之前的初始值。
  2. 將影像左上角的像素f(0,0)直接複製到積分圖上I(1,1)的位置,這裡為2。
  3. 對於其他位置的積分圖I(x,y)像素,我們可以想像從影像f(0,0)的左上角拉一個矩形到f(x-1,y-1)的位置,將被這個矩形覆蓋到的元素做加總,並把加總值放到積分圖I(x,y)位置。如下圖,假設我們要求I(3,3),意思就是將矩形的左上角f(0,0)和右下角f(2,2)位置包括的區域元素加總,就為此積分圖的值4。

https://ithelp.ithome.com.tw/upload/images/20230920/2016173243XA3aMn0P.png

我們可以透過積分圖加總的特性,求出某個區域的加總,進而算出平均值。如下圖,下圖左為一個7x7的f(x,y)影像,右邊為f(x,y)的積分圖I(x,y)。

那我們要怎麼透過積分圖I(x,y)求出下圖E區域的總合呢,其實很簡單。我們只要將積分圖的值帶入下列的公式,就可以求出面積E內元素的加總。
https://ithelp.ithome.com.tw/upload/images/20230920/20161732ivxqHu8y8f.png

其中,我們把在每一個色塊區域分別做標號,並將我們要求的E區域稱為核函數:

  • E:核函數包括的區域面積,也是我們要透過積分圖求出的解,這裡請先想像我們不知道這個區域的面積為多少。
  • D:從f(0,0)到核函數右下角所有包含的面積,面積可以從積分圖得知為37。
  • C:從f(0,0)到核函數左下角所有包含的面積,面積可以從積分圖得知為18。
  • B:從f(0,0)到核函數右上角所有包含的面積,面積可以從積分圖得知為13。
  • A:從f(0,0)到核函數左上角所有包含的面積,面積可以從積分圖得知為4。

注意這邊的面積是指被描述為所有被包含元素的加總,不是像素的總數。
https://ithelp.ithome.com.tw/upload/images/20230920/20161732NnXfhFMM3e.png

三、 程式碼

1. 逐行解釋

1) 使用OpenCV計算出積分圖

使用OpenCV函式cv::integral計算影像的積分圖。

cv::integral(raw, integral,CV_8U);
  1. raw:要計算積分圖的輸入影像。
  2. integral:用於儲存計算得到的積分圖。
  3. CV_8U:表示生成的積分圖的資料類型,這裡表示積分圖的像素值將使用8位元無符號整數來表示。

2. 完整程式碼

  1. 定義一個7x7大小的灰階影像數據 data,這是一個包含49個像素值的陣列,表示了一個7x7的影像。
  2. 建立一個7x7的灰階影像 raw,使用OpenCV的 cv::Mat 類型來表示。這個影像是根據前面定義的 data 數據建立的。
  3. 建立一個空的 cv::Mat 來存儲計算得到的積分影像,即 integral
  4. 使用 cv::integral 函數計算積分圖,並將結果存儲在 integral 中。在這裡,CV_8U 參數指定了積分圖的像素值將使用8位元無符號整數來表示。
  5. 最後,程式將原始影像和積分圖輸出到控制台,以便檢查結果。
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/core/utils/logger.hpp"

using namespace std;

int main()
{
    // 定義一個7x7大小的灰階影像數據
    uint8_t data[] = {
        2, 1, 0, 0, 3, 0, 0,
        0, 1, 0, 3, 2, 0, 3,
        0, 0, 0, 0, 1, 2, 0,
        3, 3, 2, 0, 1, 3, 0,
        3, 2, 3, 0, 2, 3, 0,
        0, 3, 0, 2, 0, 0, 0,
        1, 0, 3, 3, 2, 0, 3};
    
    // 創建一個7x7的灰階影像
    cv::Mat raw = cv::Mat(7, 7, CV_8UC1, data);
    
    // 創建一個空的Mat來存儲積分影像
    cv::Mat integral;
    
    // 計算積分圖
    cv::integral(raw, integral,CV_8U);
    
    // 輸出原始影像
    printf("f(x,y)=\n");
    print(raw);
    
    printf("\n----------\n");
    
    // 輸出積分圖
    printf("I(x,y)=\n");
    print(integral);
    
    printf("\n----------\n");
    
    return 0;
}

3. 輸出結果

f(x,y)=
[  2,   1,   0,   0,   3,   0,   0;
   0,   1,   0,   3,   2,   0,   3;
   0,   0,   0,   0,   1,   2,   0;
   3,   3,   2,   0,   1,   3,   0;
   3,   2,   3,   0,   2,   3,   0;
   0,   3,   0,   2,   0,   0,   0;
   1,   0,   3,   3,   2,   0,   3]
----------
I(x,y)=
[0, 0, 0, 0, 0, 0, 0, 0;
 0, 2, 3, 3, 3, 6, 6, 6;
 0, 2, 4, 4, 7, 12, 12, 15;
 0, 2, 4, 4, 7, 13, 15, 18;
 0, 5, 10, 12, 15, 22, 27, 30;
 0, 8, 15, 20, 23, 32, 40, 43;
 0, 8, 18, 23, 28, 37, 45, 48;
 0, 9, 19, 27, 35, 46, 54, 60]
----------

上一篇
【Day10】OpenCV 直方圖均衡化:增強影像對比度
下一篇
【Day12】OpenCV 自適應二值化(Adaptive Thresholding):降低亮度干擾
系列文
圖解C++影像處理與OpenCV應用:從基礎到高階,深入學習超硬核技術!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言