【OpenCV】OpenCV中积分图函数与应用
OpenCV中積分圖函數與應用
參考資料
opencv 查找integral,目前網上大部分的資料來自于opencv
- https://docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#gadeaf38d7701d7ad371278d663c50c77d
- https://blog.csdn.net/jia20003/article/details/52710751
- https://cloud.tencent.com/developer/article/1084469
一:圖像積分圖概念
積分圖像是Crow在1984年首次提出,是為了在多尺度透視投影中提高渲染速度。隨后這種技術被應用到基于NCC的快速匹配、對象檢測和SURF變換中、基于統計學的快速濾波器等方面。積分圖像是一種在圖像中快速計算矩形區域和的方法,這種算法主要優點是一旦積分圖像首先被計算出來我們可以計算圖像中任意大小矩形區域的和而且是在常量時間內。這樣在圖像模糊、邊緣提取、對象檢測的時候極大降低計算量、提高計算速度。第一個應用積分圖像技術的應用是在Viola-Jones的對象檢測框架中出現。
上圖左側四個點的矩形區域像素求和,只要根據每個點左上方所有像素和表值,進行兩次減法與一次加法即可=》46 – 22 – 20 + 10 = 14
二:OpenCV中積分圖函數
OpenCV中通過integral()函數可以很容易的計算圖像的積分圖,該函數支持和表積分圖、平方和表積分圖、瓦塊和表積分圖計算。integral函數與參數解釋如下:
void cv::integral(InputArray src, // 輸入圖像OutputArray sum, // 和表OutputArray sqsum, // 平方和表OutputArray tilted, // 瓦塊和表int sdepth = -1, // 和表數據深度常見CV_32Sint sqdepth = -1 // 平方和表數據深度 常見 CV_32F
)
三:使用積分圖函數
通過代碼演示計算積分圖實現任意窗口大小的盒子模糊與垂直邊緣提取,完整的代碼實現如下:
#include <opencv2/opencv.hpp>
#include <iostream>
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...\n");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\n", type);}if (c == 27) {break; // ESC}if (type == 49) { // 數字鍵 1blur_demo(src, sum);}else if (type == 50) { // 數字鍵 2edge_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<uchar>(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<int>(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),如果不加處理的話會導致結果有明顯的中心遷移。edge_demo實現了積分圖查找提取圖像邊緣、blur_demo函數實現積分圖查找圖像均值模糊,getblockSum函數實現和表查找功能,運行顯示:
總結
以上是生活随笔為你收集整理的【OpenCV】OpenCV中积分图函数与应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 驾照一分多少钱啊?
- 下一篇: 【C++】LINK类型错误分析记录