/* * Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved. * * This file is part of BoofCV (http://boofcv.org). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package boofcv.demonstrations.transform.pyramid; import boofcv.abst.filter.blur.BlurStorageFilter; import boofcv.abst.filter.convolve.ConvolveInterface; import boofcv.abst.filter.derivative.ImageGradient; import boofcv.alg.filter.derivative.GradientThree; import boofcv.alg.filter.kernel.GKernelMath; import boofcv.alg.misc.GImageMiscOps; import boofcv.core.image.GeneralizedImageOps; import boofcv.core.image.border.BorderType; import boofcv.factory.filter.blur.FactoryBlurFilter; import boofcv.factory.filter.convolve.FactoryConvolve; import boofcv.factory.filter.derivative.FactoryDerivative; import boofcv.factory.filter.kernel.FactoryKernelGaussian; import boofcv.struct.convolve.Kernel1D; import boofcv.struct.image.GrayF32; import boofcv.struct.image.ImageGray; /** * Empirically validates some theoretical predictions. * * @author Peter Abeles */ public class EdgeIntensitiesApp<T extends ImageGray> { Class<T> imageType; int width = 200; int height = 200; T input; T derivY; double sigma = 1; int radius = FactoryKernelGaussian.radiusForSigma(sigma,1); public EdgeIntensitiesApp(Class<T> imageType) { this.imageType = imageType; input = GeneralizedImageOps.createSingleBand(imageType, width, height); derivY = GeneralizedImageOps.createSingleBand(imageType, width, height); } public void init() { GImageMiscOps.fillRectangle(input, 100, width / 2, 0, width / 2, height); } private void printIntensity( String message , T deriv ) { System.out.printf("%20s: ",message); int middle = width/2; for( int i = middle-10; i <= middle+10; i++ ) { double val = GeneralizedImageOps.get(deriv,i,height/2); System.out.printf("%5.1f ",val); } System.out.println(); } /** * Validate that convolution/derivative is in fact associative */ public void convolveDerivOrder() { T blur = GeneralizedImageOps.createSingleBand(imageType, width, height); T blurDeriv = GeneralizedImageOps.createSingleBand(imageType, width, height); T deriv = GeneralizedImageOps.createSingleBand(imageType, width, height); T derivBlur = GeneralizedImageOps.createSingleBand(imageType, width, height); BlurStorageFilter<T> funcBlur = FactoryBlurFilter.gaussian(imageType,sigma,radius); ImageGradient<T,T> funcDeriv = FactoryDerivative.three(imageType,imageType); funcBlur.process(input,blur); funcDeriv.process(blur,blurDeriv,derivY); funcDeriv.process(input,deriv,derivY); funcBlur.process(deriv,derivBlur); printIntensity("Blur->Deriv",blurDeriv); printIntensity("Deriv->Blur",blurDeriv); } /** * Compare computing the image */ public void gaussianDerivToDirectDeriv() { T blur = GeneralizedImageOps.createSingleBand(imageType, width, height); T blurDeriv = GeneralizedImageOps.createSingleBand(imageType, width, height); T gaussDeriv = GeneralizedImageOps.createSingleBand(imageType, width, height); BlurStorageFilter<T> funcBlur = FactoryBlurFilter.gaussian(imageType,sigma,radius); ImageGradient<T,T> funcDeriv = FactoryDerivative.three(imageType,imageType); ImageGradient<T,T> funcGaussDeriv = FactoryDerivative.gaussian(sigma,radius,imageType,imageType); funcBlur.process(input,blur); funcDeriv.process(blur,blurDeriv,derivY); funcGaussDeriv.process(input,gaussDeriv,derivY); printIntensity("Blur->Deriv",blurDeriv); printIntensity("Gauss Deriv",gaussDeriv); } public void derivByGaussDeriv() { System.out.println("DxG*I"); T blurDeriv = GeneralizedImageOps.createSingleBand(imageType, width, height); for( int level = 1; level <= 3; level++ ) { ImageGradient<T,T> funcGaussDeriv = FactoryDerivative.gaussian(level,-1,imageType,imageType); funcGaussDeriv.process(input,blurDeriv,derivY); printIntensity("Sigma "+level,blurDeriv); } } public void derivByBlurThenDeriv() { System.out.println("Dx*(G*I)"); ImageGradient<T,T> funcDeriv = FactoryDerivative.three(imageType,imageType); T blur = GeneralizedImageOps.createSingleBand(imageType, width, height); T blurDeriv = GeneralizedImageOps.createSingleBand(imageType, width, height); for( int sigma = 1; sigma <= 3; sigma++ ) { BlurStorageFilter<T> funcBlur = FactoryBlurFilter.gaussian(imageType,sigma,-1); funcBlur.process(input,blur); funcDeriv.process(blur,blurDeriv,derivY); printIntensity("Sigma "+sigma,blurDeriv); } } public void derivByDerivThenBlur() { System.out.println("G*(Dx*I)"); ImageGradient<T,T> funcDeriv = FactoryDerivative.three(imageType,imageType); T blur = GeneralizedImageOps.createSingleBand(imageType, width, height); T deriv = GeneralizedImageOps.createSingleBand(imageType, width, height); for( int sigma = 1; sigma <= 3; sigma++ ) { BlurStorageFilter<T> funcBlur = FactoryBlurFilter.gaussian(imageType,sigma,-1); funcDeriv.process(input,deriv,derivY); funcBlur.process(deriv,blur); printIntensity("Sigma "+sigma,blur); } } public void derivByDerivOfBlur() { System.out.println("(Dx*G)*I"); T blur = GeneralizedImageOps.createSingleBand(imageType, width, height); for( int sigma = 1; sigma <= 3; sigma++ ) { Kernel1D g = FactoryKernelGaussian.gaussian1D(GrayF32.class,sigma,-1); Kernel1D d = GradientThree.getKernelX(false); Kernel1D god = GKernelMath.convolve1D(d,g); ConvolveInterface<T,T> f = FactoryConvolve.convolve(god,imageType,imageType, BorderType.EXTENDED,true); f.process(input,blur); printIntensity("Sigma "+sigma,blur); } } public void derivByGaussThenGausDeriv() { System.out.println("DxG*(G*I)"); T blur = GeneralizedImageOps.createSingleBand(imageType, width, height); T blurDeriv = GeneralizedImageOps.createSingleBand(imageType, width, height); for( int sigma = 1; sigma <= 3; sigma++ ) { ImageGradient<T,T> funcGaussDeriv = FactoryDerivative.gaussian(sigma,-1,imageType,imageType); BlurStorageFilter<T> funcBlur = FactoryBlurFilter.gaussian(imageType,sigma,-1); funcBlur.process(input,blur); funcGaussDeriv.process(blur,blurDeriv,derivY); printIntensity("Sigma "+sigma,blurDeriv); } } public void derivByGaussGausThenDeriv() { System.out.println("Dx*(G*(G*I))"); ImageGradient<T,T> funcDeriv = FactoryDerivative.three(imageType,imageType); T blur = GeneralizedImageOps.createSingleBand(imageType, width, height); T blur2 = GeneralizedImageOps.createSingleBand(imageType, width, height); T blurDeriv = GeneralizedImageOps.createSingleBand(imageType, width, height); for( int sigma = 1; sigma <= 3; sigma++ ) { BlurStorageFilter<T> funcBlur = FactoryBlurFilter.gaussian(imageType,sigma,-1); funcBlur.process(input,blur); funcBlur.process(blur,blur2); funcDeriv.process(blur2,blurDeriv,derivY); printIntensity("Sigma "+sigma,blurDeriv); } } public static void main( String args[] ) { EdgeIntensitiesApp app = new EdgeIntensitiesApp(GrayF32.class); app.init(); // see how similar the result is if the order in which the operations is done is swapped // app.convolveDerivOrder(); // app.gaussianDerivToDirectDeriv(); // The derivative's magnitude should be proportional to 1/sigma app.derivByBlurThenDeriv(); System.out.println("-----"); app.derivByDerivThenBlur(); System.out.println("-----"); app.derivByDerivOfBlur(); System.out.println("-----"); app.derivByGaussDeriv(); System.out.println("-----"); app.derivByGaussThenGausDeriv(); System.out.println("-----"); app.derivByGaussGausThenDeriv(); } }