OpenCV中積分圖函數(shù)與應(yīng)用
一:圖像積分圖概念
積分圖像是Crow在1984年首次提出,是為了在多尺度透視投影中提高渲染速度。隨后這種技術(shù)被應(yīng)用到基于NCC的快速匹配、對(duì)象檢測(cè)和SURF變換中、基于統(tǒng)計(jì)學(xué)的快速濾波器等方面。積分圖像是一種在圖像中快速計(jì)算矩形區(qū)域和的方法,這種算法主要優(yōu)點(diǎn)是一旦積分圖像首先被計(jì)算出來我們可以計(jì)算圖像中任意大小矩形區(qū)域的和而且是在常量時(shí)間內(nèi)。這樣在圖像模糊、邊緣提取、對(duì)象檢測(cè)的時(shí)候極大降低計(jì)算量、提高計(jì)算速度。第一個(gè)應(yīng)用積分圖像技術(shù)的應(yīng)用是在Viola-Jones的對(duì)象檢測(cè)框架中出現(xiàn)。
上圖左側(cè)四個(gè)點(diǎn)的矩形區(qū)域像素求和,只要根據(jù)每個(gè)點(diǎn)左上方所有像素和表值,進(jìn)行兩次減法與一次加法即可=》46 – 22 – 20 + 10 = 14
二:OpenCV中積分圖函數(shù)
OpenCV中通過integral()函數(shù)可以很容易的計(jì)算圖像的積分圖,該函數(shù)支持和表積分圖、平方和表積分圖、瓦塊和表積分圖計(jì)算。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ù)
通過代碼演示計(jì)算積分圖實(shí)現(xiàn)任意窗口大小的盒子模糊與垂直邊緣提取,完整的代碼實(shí)現(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);
-
-
// 計(jì)算積分圖
-
Mat sum, sqrsum;
-
integral(src, sum, sqrsum, CV_32S, CV_32F);
-
-
// 積分圖應(yīng)用
-
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++) {
-
// 積分圖查找和表,計(jì)算卷積
-
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 垂直邊緣檢測(cè)演示
-
*/
-
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; // 算子大小,可以修改,越大邊緣效應(yīng)越明顯
-
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++) {
-
// 積分圖查找和表,計(jì)算卷積
-
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;
-
}
這里最重要的是要注意到上面的圖示,積分圖對(duì)象的Mat(1,1)對(duì)應(yīng)實(shí)際圖像Mat(0,0),如果不加處理的話會(huì)導(dǎo)致結(jié)果有明顯的中心遷移。edge_demo實(shí)現(xiàn)了積分圖查找提取圖像邊緣、blur_demo函數(shù)實(shí)現(xiàn)積分圖查找圖像均值模糊,getblockSum函數(shù)實(shí)現(xiàn)和表查找功能,運(yùn)行顯示:
原圖:
模糊效果
邊緣效果
審核編輯 :李倩
-
圖像
+關(guān)注
關(guān)注
2文章
1079瀏覽量
40375 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4284瀏覽量
62328 -
OpenCV
+關(guān)注
關(guān)注
29文章
625瀏覽量
41215
原文標(biāo)題:OpenCV中積分圖介紹與應(yīng)用
文章出處:【微信號(hào):CVSCHOOL,微信公眾號(hào):OpenCV學(xué)堂】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論