OpenCV中積分圖函數(shù)與應用
一:圖像積分圖概念
積分圖像是Crow在1984年首次提出,是為了在多尺度透視投影中提高渲染速度。隨后這種技術(shù)被應用到基于NCC的快速匹配、對象檢測和SURF變換中、基于統(tǒng)計學的快速濾波器等方面。積分圖像是一種在圖像中快速計算矩形區(qū)域和的方法,這種算法主要優(yōu)點是一旦積分圖像首先被計算出來我們可以計算圖像中任意大小矩形區(qū)域的和而且是在常量時間內(nèi)。這樣在圖像模糊、邊緣提取、對象檢測的時候極大降低計算量、提高計算速度。第一個應用積分圖像技術(shù)的應用是在Viola-Jones的對象檢測框架中出現(xiàn)。
上圖左側(cè)四個點的矩形區(qū)域像素求和,只要根據(jù)每個點左上方所有像素和表值,進行兩次減法與一次加法即可=》46 – 22 – 20 + 10 = 14
二:OpenCV中積分圖函數(shù)
OpenCV中通過integral()函數(shù)可以很容易的計算圖像的積分圖,該函數(shù)支持和表積分圖、平方和表積分圖、瓦塊和表積分圖計算。integral函數(shù)與參數(shù)解釋如下:
-
void cv::integral(
-
InputArray src, // 輸入圖像
-
OutputArray sum, // 和表
-
OutputArray sqsum, // 平方和表
-
int sdepth = -1, // 和表數(shù)據(jù)深度常見CV_32S
-
int sqdepth = -1 // 平方和表數(shù)據(jù)深度 常見 CV_32F
-
)
三:使用積分圖函數(shù)
通過代碼演示計算積分圖實現(xiàn)任意窗口大小的盒子模糊與垂直邊緣提取,完整的代碼實現(xiàn)如下:
-
#include
-
#include
-
-
using namespace cv;
-
using namespace std;
-
-
void blur_demo(Mat &image, Mat &sum);
-
void edge_demo(Mat &image, Mat &sum);
-
int getblockSum(Mat &sum, int x1, int y1, int x2, int y2, int i);
-
int main(int argc, char** argv) {
-
Mat src = imread("D:/vcprojects/images/yuan_test.png");
-
if (src.empty()) {
-
printf("could not load image... ");
-
return -1;
-
}
-
namedWindow("input", CV_WINDOW_AUTOSIZE);
-
imshow("input", src);
-
-
namedWindow("output", CV_WINDOW_AUTOSIZE);
-
-
// 計算積分圖
-
Mat sum, sqrsum;
-
integral(src, sum, sqrsum, CV_32S, CV_32F);
-
-
// 積分圖應用
-
int type = 0;
-
while (true) {
-
char c = waitKey(100);
-
if (c > 0) {
-
type = (int)c;
-
printf("c : %d ", type);
-
}
-
-
if (c == 27) {
-
break; // ESC
-
}
-
if (type == 49) { // 數(shù)字鍵 1
-
blur_demo(src, sum);
-
}
-
else if (type == 50) { // 數(shù)字鍵 2
-
edge_demo(src, sum);
-
}
-
else {
-
blur_demo(src, sum);
-
}
-
}
-
-
waitKey(0);
-
return 0;
-
}
-
-
void blur_demo(Mat &image, Mat &sum) {
-
int w = image.cols;
-
int h = image.rows;
-
Mat result = Mat::zeros(image.size(), image.type());
-
int x2 = 0, y2 = 0;
-
int x1 = 0, y1 = 0;
-
int ksize = 5;
-
int radius = ksize / 2;
-
int ch = image.channels();
-
int cx = 0, cy = 0;
-
for (int row = 0; row < h + radius; row++) {
-
y2 = (row + 1)>h ? h : (row + 1);
-
y1 = (row - ksize) < 0 ? 0 : (row - ksize);
-
for (int col = 0; col < w + radius; col++) {
-
x2 = (col + 1)>w ? w : (col + 1);
-
x1 = (col - ksize) < 0 ? 0 : (col - ksize);
-
cx = (col - radius) < 0 ? 0 : col - radius;
-
cy = (row - radius) < 0 ? 0 : row - radius;
-
int num = (x2 - x1)*(y2 - y1);
-
for (int i = 0; i < ch; i++) {
-
// 積分圖查找和表,計算卷積
-
int s = getblockSum(sum, x1, y1, x2, y2, i);
-
result.at<Vec3b>(cy, cx)[i] = saturate_cast
(s / num); -
}
-
}
-
}
-
imshow("output", result);
-
imwrite("D:/result.png", result);
-
}
-
-
/**
-
* 3x3 sobel 垂直邊緣檢測演示
-
*/
-
void edge_demo(Mat &image, Mat &sum) {
-
int w = image.cols;
-
int h = image.rows;
-
Mat result = Mat::zeros(image.size(), CV_32SC3);
-
int x2 = 0, y2 = 0;
-
int x1 = 0, y1 = 0;
-
int ksize = 3; // 算子大小,可以修改,越大邊緣效應越明顯
-
int radius = ksize / 2;
-
int ch = image.channels();
-
int cx = 0, cy = 0;
-
for (int row = 0; row < h + radius; row++) {
-
y2 = (row + 1)>h ? h : (row + 1);
-
y1 = (row - ksize) < 0 ? 0 : (row - ksize);
-
for (int col = 0; col < w + radius; col++) {
-
x2 = (col + 1)>w ? w : (col + 1);
-
x1 = (col - ksize) < 0 ? 0 : (col - ksize);
-
cx = (col - radius) < 0 ? 0 : col - radius;
-
cy = (row - radius) < 0 ? 0 : row - radius;
-
int num = (x2 - x1)*(y2 - y1);
-
for (int i = 0; i < ch; i++) {
-
// 積分圖查找和表,計算卷積
-
int s1 = getblockSum(sum, x1, y1, cx, y2, i);
-
int s2 = getblockSum(sum, cx, y1, x2, y2, i);
-
result.at<Vec3i>(cy, cx)[i] = saturate_cast
(s2 - s1); -
}
-
}
-
}
-
Mat dst, gray;
-
convertScaleAbs(result, dst);
-
normalize(dst, dst, 0, 255, NORM_MINMAX);
-
cvtColor(dst, gray, COLOR_BGR2GRAY);
-
imshow("output", gray);
-
imwrite("D:/edge_result.png", gray);
-
}
-
-
int getblockSum(Mat &sum, int x1, int y1, int x2, int y2, int i) {
-
int tl = sum.at<Vec3i>(y1, x1)[i];
-
int tr = sum.at<Vec3i>(y2, x1)[i];
-
int bl = sum.at<Vec3i>(y1, x2)[i];
-
int br = sum.at<Vec3i>(y2, x2)[i];
-
int s = (br - bl - tr + tl);
-
return s;
-
}
這里最重要的是要注意到上面的圖示,積分圖對象的Mat(1,1)對應實際圖像Mat(0,0),如果不加處理的話會導致結(jié)果有明顯的中心遷移。edge_demo實現(xiàn)了積分圖查找提取圖像邊緣、blur_demo函數(shù)實現(xiàn)積分圖查找圖像均值模糊,getblockSum函數(shù)實現(xiàn)和表查找功能,運行顯示:
原圖:
模糊效果
邊緣效果
審核編輯 :李倩
-
圖像
+關(guān)注
關(guān)注
2文章
1083瀏覽量
40449 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4327瀏覽量
62573 -
OpenCV
+關(guān)注
關(guān)注
31文章
634瀏覽量
41338
原文標題:OpenCV中積分圖介紹與應用
文章出處:【微信號:CVSCHOOL,微信公眾號:OpenCV學堂】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論