1 #include "openCVtrilateralFilter.h" 3 #include "opencv2/opencv.hpp" 4 #include "opencv/highgui.h" 8 bool OpenCVtrilateralFilter::trilateralFilter(
18 if (inputImg.cols != outputImg.cols
19 || inputImg.rows != outputImg.rows
20 || inputImg.depth() != outputImg.depth()
21 || inputImg.channels() != outputImg.channels()
22 || inputImg.channels() != 1)
27 if (inputImg.depth() != IPL_DEPTH_32F)
31 cv::Mat adaptiveNeighbourhood = cv::Mat(inputImg.rows, inputImg.cols, inputImg.type(),cv::Scalar(1));
34 cv::Mat xGradient = cv::Mat(inputImg.rows, inputImg.cols, inputImg.type(),cv::Scalar(1));
35 cv::Mat yGradient = cv::Mat(inputImg.rows, inputImg.cols, inputImg.type(),cv::Scalar(1));
38 cv::Mat xGradientSmooth = cv::Mat(inputImg.rows, inputImg.cols, inputImg.type(),cv::Scalar(1));
39 cv::Mat yGradientSmooth = cv::Mat(inputImg.rows, inputImg.cols, inputImg.type(),cv::Scalar(1));
42 cv::Mat gradientMagnitude = cv::Mat(inputImg.rows, inputImg.cols, inputImg.type(),cv::Scalar(1));
48 const float beta = 0.15f;
51 computeGradients(inputImg, xGradient, yGradient );
54 computeMagnitude(xGradient, yGradient, gradientMagnitude);
57 double minGrad, maxGrad;
58 minMaxLoc(gradientMagnitude, &minGrad, &maxGrad);
59 sigmaR = beta * ( (float) maxGrad - (
float) minGrad );
65 if (filterType == TYPE_LUT)
68 levelMax = log2( __min( inputImg.cols, inputImg.rows ) );
69 maxLUT = pow( 2.f, levelMax-1) + 1;
75 maxLUT = int( sigmaC * sqrt( fabs( log(epsilon) ) ) ) + 1;
77 levelMax = log2(2 * maxLUT + 1,
true);
81 setAdaptiveNeighbourHood(gradientMagnitude, sigmaR, levelMax, adaptiveNeighbourhood);
86 if (filterType == TYPE_LUT)
87 BilateralGradientFilterLUT(
88 xGradient,yGradient, gradientMagnitude, sigmaC, sigmaR,
89 xGradientSmooth, yGradientSmooth);
91 BilateralGradientFilter(
92 xGradient, yGradient, gradientMagnitude, sigmaC, sigmaR, epsilon,
93 xGradientSmooth, yGradientSmooth );
97 if (filterType == TYPE_LUT)
98 DetailBilateralFilterLUT(
99 inputImg, adaptiveNeighbourhood, xGradientSmooth, yGradientSmooth,
100 sigmaC, sigmaR, maxLUT, outputImg);
102 DetailBilateralFilter(
103 inputImg, adaptiveNeighbourhood, xGradientSmooth, yGradientSmooth,
104 sigmaC, sigmaR, maxLUT, epsilon, outputImg);
110 void OpenCVtrilateralFilter::computeGradients(
111 cv::Mat& inputImg, cv::Mat& xGradient, cv::Mat& yGradient )
115 float kernel[] = { -1, 1 };
116 cv::Mat xKernel = cv::Mat(1,2,CV_32FC1,kernel);
117 cv::Mat yKernel = cv::Mat(2,1,CV_32FC1,kernel);
118 cv::Point anchorPt = cv::Point(0,0);
120 cv::filter2D(inputImg,xGradient, CV_32FC1, xKernel, anchorPt);
121 cv::filter2D(inputImg,yGradient,CV_32FC1, yKernel, anchorPt);
125 void OpenCVtrilateralFilter::computeMagnitude(
126 cv::Mat& xGradient, cv::Mat& yGradient,
127 cv::Mat& gradientMagnitude)
129 gradientMagnitude = cv::norm(xGradient-yGradient);
141 void OpenCVtrilateralFilter::setAdaptiveNeighbourHood(
142 cv::Mat& gradientMagnitude,
const float sigmaR,
const int maxLevel,
143 cv::Mat& adaptiveNeighbourhood )
146 vector<cv::Mat> minGradientStack, maxGradientStack;
147 cv::Size imgSize = gradientMagnitude.size();
150 for(
int i = 0 ; i < maxLevel ; i++)
151 minGradientStack.push_back( cv::Mat(imgSize,gradientMagnitude.depth(),1) );
152 for(
int i = 0 ; i < maxLevel ; i++)
153 maxGradientStack.push_back( cv::Mat(imgSize,gradientMagnitude.depth(),1) );
156 buildMinMaxImageStack(gradientMagnitude, minGradientStack, maxGradientStack );
159 cv::Mat minImg, maxImg;
160 cv::Mat magImg = cv::Mat(gradientMagnitude);
161 cv::Mat adpImg = cv::Mat(adaptiveNeighbourhood);
163 for(
int y = 0; y < imgSize.width; y++)
165 for(
int x = 0; x < imgSize.height; x++)
168 const float upperThreshold = magImg.ptr(y)[x] + sigmaR;
169 const float lowerThreshold = magImg.ptr(y)[x] - sigmaR;
173 for(lev = 0; lev < maxLevel; lev++)
175 minImg = minGradientStack[lev];
176 maxImg = maxGradientStack[lev];
177 if ( maxImg.ptr(y)[x] > upperThreshold || minImg.ptr(y)[x] < lowerThreshold )
183 adpImg.ptr(y)[x] = pow(2.f, lev-1);
190 void OpenCVtrilateralFilter::buildMinMaxImageStack(
191 cv::Mat& gradientMagnitude,
192 vector<cv::Mat> minStack, vector<cv::Mat> maxStack )
194 const int imgWidth = gradientMagnitude.cols;
195 const int imgHeight = gradientMagnitude.rows;
198 cv::Mat minImg1, maxImg1, minImg2, maxImg2;
199 cv::Mat magImg = cv::Mat(gradientMagnitude);
202 minImg1 = minStack[0];
203 maxImg1 = maxStack[0];
206 for(
int y = 0; y < imgHeight ; y++)
208 for (
int x = 0; x < imgWidth; x++)
211 float outMax = -1e12;
215 for(
int n = __max(y-1,0) ; n < __min(y+2, imgHeight); n++)
217 for(
int m=__max(x-1,0); m < __min(x+2, imgWidth) ; m++)
219 outMin = __min(magImg.ptr(n)[m], outMin);
220 outMax = __max(magImg.ptr(n)[m], outMax);
223 minImg1.ptr(y)[x] = outMin;
224 maxImg1.ptr(y)[x] = outMax;
229 for (
int i = 1 ; i < minStack.size(); i++)
232 minImg1 = minStack[i-1];
233 maxImg1 = maxStack[i-1];
236 minImg2 = minStack[i];
237 maxImg2 = maxStack[i];
239 for(
int y = 0; y < imgHeight ; y++)
241 for (
int x = 0; x < imgWidth; x++)
244 float outMax = -1e12;
248 for(
int n = __max(y-1,0) ; n < __min(y+2, imgHeight); n++)
250 for(
int m =__max(x-1,0); m < __min(x+2, imgWidth) ; m++)
252 outMin = __min(minImg1.ptr(n)[m], outMin);
253 outMax = __max(maxImg1.ptr(n)[m], outMax);
256 minImg2.ptr(y)[x] = outMin;
257 maxImg2.ptr(y)[x] = outMax;
271 void OpenCVtrilateralFilter::BilateralGradientFilter(
272 cv::Mat& xGradient, cv::Mat& yGradient,
273 cv::Mat& gradientMagnitude,
274 const float sigmaC,
const float sigmaR,
const float epsilon,
275 cv::Mat& xGradientSmooth, cv::Mat& yGradientSmooth )
278 const int imgWidth = xGradient.cols;
279 const int imgHeight = xGradient.rows;
282 const float domainConst = -2.f * sigmaC * sigmaC;
283 const float rangeConst = -2.f * sigmaR * sigmaR;
287 const int halfSize = int(sigmaC / 2.f);
288 cv::Mat domainWeightLUT =
289 cv::Mat(cvSize(halfSize+1,halfSize+1),xGradient.depth(),1);
292 cv::Mat domainWeight = cv::Mat(domainWeightLUT);
294 for (
int y = 0; y < domainWeightLUT.rows ; y++)
296 for (
int x = 0; x < domainWeightLUT.cols ; x++)
299 const float diff = (float) (x*x+y*y);
300 domainWeight.ptr(y)[x] = (float) exp( diff / domainConst );
305 cv::Mat xImg = cv::Mat(xGradient);
306 cv::Mat yImg= cv::Mat(yGradient);
307 cv::Mat xSmoothImg = cv::Mat(xGradientSmooth);
308 cv::Mat ySmoothImg= cv::Mat(yGradientSmooth);
309 cv::Mat magImg= cv::Mat(gradientMagnitude);
313 for(
int y = 0; y < imgHeight ; y++)
315 for(
int x = 0; x < imgWidth ; x++)
317 double normFactor = 0.f;
322 const float g2 = magImg.ptr(y)[x];
325 for (
int n = -halfSize; n <= halfSize; n++)
327 for(
int m = -halfSize; m <= halfSize; m++)
330 const float dWeight = domainWeight.ptr(abs(n))[abs(m)];
333 if( dWeight < epsilon )
continue;
336 const int localX = x + m;
337 if (localX < 0)
continue;
338 if (localX >= imgWidth)
continue;
340 const int localY = y + n;
341 if (localY < 0)
continue;
342 if (localY >= imgHeight)
continue;
345 const float g1 = magImg.ptr(localY)[localX];
348 const float gradDiffSq = (float) pow(g1 - g2, 2);
352 const float rangeWeight = (float) exp( gradDiffSq / rangeConst );
355 if (rangeWeight < epsilon)
continue;
357 tmpX += xImg.ptr(localY)[localX] * dWeight * rangeWeight;
358 tmpY += yImg.ptr(localY)[localX] * dWeight * rangeWeight;
361 normFactor += dWeight * rangeWeight;
366 xSmoothImg.ptr(y)[x] = tmpX / normFactor;
367 ySmoothImg.ptr(y)[x] = tmpY / normFactor;
374 void OpenCVtrilateralFilter::DetailBilateralFilter(
375 cv::Mat& inputImage, cv::Mat& adaptiveRegion,
376 cv::Mat& xGradientSmooth, cv::Mat& yGradientSmooth,
377 const float sigmaC,
const float sigmaR,
378 const int maxDomainSize,
const float epsilon,
383 const int imgWidth = inputImage.cols;
384 const int imgHeight = inputImage.rows;
387 const double domainConst = -2.f * sigmaC * sigmaC;
388 const double rangeConst = -2.f * sigmaR * sigmaR;
391 cv::Mat xImg = cv::Mat(xGradientSmooth);
392 cv::Mat yImg = cv::Mat(yGradientSmooth);
393 cv::Mat srcImg = cv::Mat(inputImage);
394 cv::Mat outImg = cv::Mat(outputImg);
395 cv::Mat adpImg = cv::Mat(adaptiveRegion);
401 cv::Mat domainWeightLUT =
402 cv::Mat( cvSize(maxDomainSize+1,maxDomainSize+1), inputImage.depth(), 1);
405 cv::Mat domainWeight = cv::Mat(domainWeightLUT);
407 for (
int y = 0; y < domainWeightLUT.rows ; y++)
409 for (
int x = 0; x < domainWeightLUT.cols ; x++)
412 const float diff = (float) (x*x+y*y);
413 domainWeight.ptr(y)[x] = (float) exp( diff / domainConst );
417 for(
int y = 0; y < imgHeight; y++)
419 for(
int x = 0; x < imgWidth; x++)
421 double normFactor = 0.f;
426 const int halfSize = (int) __min( adpImg.ptr(y)[x], maxDomainSize );
432 const float coeffA = xImg.ptr(y)[x];
433 const float coeffB = yImg.ptr(y)[x];
434 const float coeffC = srcImg.ptr(y)[x];
436 for (
int n = -halfSize; n <= halfSize; n++)
438 for(
int m = -halfSize; m <= halfSize; m++)
441 const float dWeight = domainWeight.ptr(abs(n))[abs(m)];
444 if( dWeight < epsilon )
continue;
447 const int localX = x + m;
448 if (localX < 0)
continue;
449 if (localX >= imgWidth)
continue;
451 const int localY = y + n;
452 if (localY < 0)
continue;
453 if (localY >= imgHeight)
continue;
459 srcImg.ptr(localY)[localX] - coeffA * float(m) - coeffB * float(n) - coeffC;
463 const float rangeWeight = exp( pow(detail,2) / rangeConst );
465 if ( dWeight < epsilon )
continue;
467 tmp += detail * dWeight * rangeWeight;
470 normFactor += dWeight * rangeWeight;
475 outImg.ptr(y)[x] = tmp / normFactor + coeffC;
487 void OpenCVtrilateralFilter::BilateralGradientFilterLUT(
488 cv::Mat& xGradient, cv::Mat& yGradient,
489 cv::Mat& gradientMagnitude,
490 const float sigmaC,
const float sigmaR,
491 cv::Mat& xGradientSmooth, cv::Mat& yGradientSmooth )
494 const int imgWidth = xGradient.cols;
495 const int imgHeight = xGradient.rows;
498 const float domainConst = -2.f * sigmaC * sigmaC;
499 const float rangeConst = -2.f * sigmaR * sigmaR;
503 const int halfSize = int(sigmaC - 1.f / 2.f);
504 cv::Mat domainWeightLUT = cv::Mat(cv::Size(halfSize+1,halfSize+1), xGradient.depth(),1);
507 cv::Mat domainWeight = cv::Mat(domainWeightLUT);
509 for (
int y = 0; y < domainWeightLUT.rows ; y++)
511 for (
int x = 0; x < domainWeightLUT.cols ; x++)
514 const float diff = (float) (x*x+y*y);
515 domainWeight.ptr(y)[x] = (float) exp( diff / domainConst );
520 cv::Mat xImg = cv::Mat(xGradient);
521 cv::Mat yImg = cv::Mat(yGradient);
522 cv::Mat xSmoothImg = cv::Mat(xGradientSmooth);
523 cv::Mat ySmoothImg = cv::Mat(yGradientSmooth);
524 cv::Mat magImg = cv::Mat(gradientMagnitude);
528 for(
int y = 0; y < imgHeight ; y++)
530 for(
int x = 0; x < imgWidth ; x++)
532 double normFactor = 0.f;
537 const float g2 = magImg.ptr(y)[x];
540 for (
int n = -halfSize; n <= halfSize; n++)
542 for(
int m = -halfSize; m <= halfSize; m++)
545 const float dWeight = domainWeight.ptr(abs(n))[abs(m)];
548 const int localX = x + m;
549 if (localX < 0)
continue;
550 if (localX >= imgWidth)
continue;
552 const int localY = y + n;
553 if (localY < 0)
continue;
554 if (localY >= imgHeight)
continue;
557 const float g1 = magImg.ptr(localY)[localX];
560 const float gradDiffSq = (float) pow(g1 - g2, 2);
564 const float rangeWeight = (float) exp( gradDiffSq / rangeConst );
566 tmpX += xImg.ptr(localY)[localX] * dWeight * rangeWeight;
567 tmpY += yImg.ptr(localY)[localX] * dWeight * rangeWeight;
570 normFactor += dWeight * rangeWeight;
575 xSmoothImg.ptr(y)[x] = tmpX / normFactor;
576 ySmoothImg.ptr(y)[x] = tmpY / normFactor;
583 void OpenCVtrilateralFilter::DetailBilateralFilterLUT(
584 cv::Mat& inputImage, cv::Mat& adaptiveRegion,
585 cv::Mat& xGradientSmooth, cv::Mat& yGradientSmooth,
586 const float sigmaC,
const float sigmaR,
587 const int maxDomainSize, cv::Mat& outputImg)
591 const int imgWidth = inputImage.cols;
592 const int imgHeight = inputImage.rows;
595 const double domainConst = -2.f * sigmaC * sigmaC;
596 const double rangeConst = -2.f * sigmaR * sigmaR;
599 cv::Mat xImg = cv::Mat(xGradientSmooth);
600 cv::Mat yImg = cv::Mat(yGradientSmooth);
601 cv::Mat srcImg = cv::Mat(inputImage);
602 cv::Mat outImg = cv::Mat(outputImg);
603 cv::Mat adpImg = cv::Mat(adaptiveRegion);
609 cv::Mat domainWeightLUT = cv::Mat( cv::Size(maxDomainSize,maxDomainSize), inputImage.depth(), 1);
612 cv::Mat domainWeight = cv::Mat(domainWeightLUT);
614 for (
int y = 0; y < domainWeightLUT.rows ; y++)
616 for (
int x = 0; x < domainWeightLUT.cols ; x++)
619 const float diff = (float) (x*x+y*y);
620 domainWeight.ptr(y)[x] = (float) exp( diff / domainConst );
625 for(
int y = 0; y < imgHeight; y++)
627 for(
int x = 0; x < imgWidth; x++)
629 double normFactor = 0.f;
634 const int halfSize = (int) adpImg.ptr(y)[x];
640 const float coeffA = xImg.ptr(y)[x];
641 const float coeffB = yImg.ptr(y)[x];
642 const float coeffC = srcImg.ptr(y)[x];
644 for (
int n = -halfSize; n <= halfSize; n++)
646 for(
int m = -halfSize; m <= halfSize; m++)
649 const float dWeight = domainWeight.ptr(abs(n))[abs(m)];
652 const int localX = x + m;
653 if (localX < 0)
continue;
654 if (localX >= imgWidth)
continue;
656 const int localY = y + n;
657 if (localY < 0)
continue;
658 if (localY >= imgHeight)
continue;
664 srcImg.ptr(localY)[localX] - coeffA * float(m) - coeffB * float(n) - coeffC;
668 const float rangeWeight = exp( pow(detail,2) / rangeConst );
671 tmp += detail * dWeight * rangeWeight;
674 normFactor += dWeight * rangeWeight;
679 outImg.ptr(y)[x] = tmp / normFactor + coeffC;