積分圖(Integral Image)是一個在影像處理中非常有用的數學工具,積分圖又稱總和面積表(Summed Area Table)。它是一種特殊的影像表示方法,可以快速計算圖像中任何區域內像素值的總和。能夠在計算區域總合時能夠提供高效率的運算,不是像傳統方法一樣需要對影像進行摺積運算,廣泛應用於計算影像的各種區域特性,如總和、平均值等。
積分圖可以用以下的數學公式表示:
如果你對影像函數f(x,y)的表示法還很陌生,你可以先參考這篇文章:【Day8】影像處理的數學基礎:深入解析影像摺積原理
積分圖的核心概念是將原始影像的像素值累加形成一個新的影像,其中每個像素值表示從圖片的左上角開始到目前位置的加總。而因為積分圖會對第一行、第一列的像素做初始化填0,所以輸出的矩陣會多一行、多一列。以下是積分圖的例子,請搭配下圖參考。
我們可以透過積分圖加總的特性,求出某個區域的加總,進而算出平均值。如下圖,下圖左為一個7x7的f(x,y)影像,右邊為f(x,y)的積分圖I(x,y)。
那我們要怎麼透過積分圖I(x,y)求出下圖E區域的總合呢,其實很簡單。我們只要將積分圖的值帶入下列的公式,就可以求出面積E內元素的加總。
其中,我們把在每一個色塊區域分別做標號,並將我們要求的E區域稱為核函數:
注意這邊的面積是指被描述為所有被包含元素的加總,不是像素的總數。
使用OpenCV函式cv::integral
計算影像的積分圖。
cv::integral(raw, integral,CV_8U);
raw
:要計算積分圖的輸入影像。integral
:用於儲存計算得到的積分圖。CV_8U
:表示生成的積分圖的資料類型,這裡表示積分圖的像素值將使用8位元無符號整數來表示。data
,這是一個包含49個像素值的陣列,表示了一個7x7的影像。raw
,使用OpenCV的 cv::Mat
類型來表示。這個影像是根據前面定義的 data
數據建立的。cv::Mat
來存儲計算得到的積分影像,即 integral
。cv::integral
函數計算積分圖,並將結果存儲在 integral
中。在這裡,CV_8U
參數指定了積分圖的像素值將使用8位元無符號整數來表示。#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;
}
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]
----------