Box Filtering and Separable Filters in OpenCV
Box Filtering
Box filtering computes the mean or sum of pixel values within a rectangular neighborhood. The boxFilter function handles normalization, while sqrBoxFilter processes squared pixel values.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
Mat srcImg = imread("input.jpg", IMREAD_COLOR);
if (srcImg.empty()) {
cerr << "Error loading image" << endl;
return -1;
}
imshow("Original", srcImg);
float sampleVals[25] = {1,2,3,4,5,
6,7,8,9,10,
11,12,13,14,15,
16,17,18,19,20,
21,22,23,24,25};
Mat sampleMat(5, 5, CV_32FC1, sampleVals);
Mat floatImg;
srcImg.convertTo(floatImg, CV_32F, 1.0/255.0);
Mat normResult, rawResult, sqrNorm, sqrRaw, floatSqrs;
boxFilter(srcImg, rawResult, -1, Size(3,3), Point(-1,-1), false);
boxFilter(srcImg, normResult, -1, Size(3,3), Point(-1,-1), true);
sqrBoxFilter(sampleMat, sqrNorm, -1, Size(3,3), Point(-1,-1), true);
sqrBoxFilter(sampleMat, sqrRaw, -1, Size(3,3), Point(-1,-1), false);
sqrBoxFilter(floatImg, floatSqrs, -1, Size(3,3), Point(-1,-1), true);
imshow("Normalized", normResult);
imshow("Summation", rawResult);
imshow("Squared Norm", floatSqrs);
waitKey(0);
destroyAllWindows();
return 0;
}
Separable Filters
Separable filters decompose 2D convolution into sequential 1D operations along orthogonal axes, improving efficiency. The sepFilter2D function impelments this approach.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
float sampleVals[25] = {1,2,3,4,5,
6,7,8,9,10,
11,12,13,14,15,
16,17,18,19,20,
21,22,23,24,25};
Mat sampleMat(5, 5, CV_32FC1, sampleVals);
Mat vertKernel = (Mat_<float>(3,1) << -1, 3, -1);
Mat horizKernel = vertKernel.t();
Mat combinedKernel = vertKernel * horizKernel;
Mat gaussX = getGaussianKernel(3, 1);
Mat gaussDirect, gaussSep;
GaussianBlur(sampleMat, gaussDirect, Size(3,3), 1);
sepFilter2D(sampleMat, gaussSep, -1, gaussX, gaussX);
cout << "Gaussian Direct:\n" << gaussDirect << endl;
cout << "Gaussian Separated:\n" << gaussSep << endl;
Mat tempVert, tempComb, directConv, sepConv;
filter2D(sampleMat, tempVert, -1, vertKernel);
filter2D(tempVert, tempComb, -1, horizKernel);
filter2D(sampleMat, directConv, -1, combinedKernel);
sepFilter2D(sampleMat, sepConv, -1, horizKernel, vertKernel);
cout << "Vertical Pass:\n" << tempVert << endl;
cout << "Combined Pass:\n" << tempComb << endl;
cout << "Direct 2D:\n" << directConv << endl;
cout << "Separated 1D:\n" << sepConv << endl;
Mat img = imread("input.jpg");
if (img.empty()) {
cerr << "Error loading image" << endl;
return -1;
}
imshow("Source", img);
Mat imgVert, imgComb, imgDirect;
filter2D(img, imgVert, -1, vertKernel);
filter2D(imgVert, imgComb, -1, horizKernel);
filter2D(img, imgDirect, -1, combinedKernel);
imshow("Vertical Stage", imgVert);
imshow("Combined Result", imgComb);
imshow("Direct 2D Conv", imgDirect);
waitKey(0);
destroyAllWindows();
return 0;
}