/* * 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.alg.flow; import boofcv.alg.interpolate.InterpolatePixelS; import boofcv.alg.misc.ImageMiscOps; import boofcv.core.image.border.BorderType; import boofcv.factory.interpolate.FactoryInterpolation; import boofcv.struct.image.GrayF32; import boofcv.struct.pyramid.PyramidFloat; import org.junit.Test; import java.util.Random; import static org.junit.Assert.assertEquals; /** * @author Peter Abeles */ public class TestBroxWarpingSpacial { int width = 10; int height = 13; Random rand = new Random(234); double epsilon = 0.001; InterpolatePixelS<GrayF32> interpolate = FactoryInterpolation.bilinearPixelS(GrayF32.class, BorderType.EXTENDED); @Test public void process() { int width = 30; int height = 40; GrayF32 original1 = new GrayF32(width,height); GrayF32 original2 = new GrayF32(width,height); ImageMiscOps.fillRectangle(original1,40,10,0,10,height); ImageMiscOps.fillRectangle(original2,40,15,0,10,height); PyramidFloat<GrayF32> pyr1 = UtilDenseOpticalFlow.standardPyramid(width,height,0.7,0,5,12,GrayF32.class); PyramidFloat<GrayF32> pyr2 = UtilDenseOpticalFlow.standardPyramid(width,height,0.7,0,5,12,GrayF32.class); pyr1.process(original1); pyr2.process(original2); BroxWarpingSpacial<GrayF32> alg = new BroxWarpingSpacial<>(new ConfigBroxWarping(),interpolate); alg.process(pyr1,pyr2); for( int y = 0; y < height; y++ ) { for( int x = 10; x < 20; x++ ) { assertEquals(5,alg.getFlowX().get(x,y),1); assertEquals(0,alg.getFlowY().get(x,y),1); } } } @Test public void computePsiDataPsiGradient() { BroxWarpingSpacial<GrayF32> alg = new BroxWarpingSpacial<>(new ConfigBroxWarping(),interpolate); alg.resizeForLayer(width, height); GrayF32 image1 = new GrayF32(width,height); GrayF32 image2 = new GrayF32(width,height); GrayF32 deriv1x = new GrayF32(width,height); GrayF32 deriv1y = new GrayF32(width,height); GrayF32 deriv2x = new GrayF32(width,height); GrayF32 deriv2y = new GrayF32(width,height); GrayF32 deriv2xx = new GrayF32(width,height); GrayF32 deriv2yy = new GrayF32(width,height); GrayF32 deriv2xy = new GrayF32(width,height); GrayF32 du = new GrayF32(width,height); GrayF32 dv = new GrayF32(width,height); GrayF32 psiData = new GrayF32(width,height); GrayF32 psiGradient = new GrayF32(width,height); ImageMiscOps.fillUniform(image1,rand,-1,1); ImageMiscOps.fillUniform(image2,rand,-1,1); ImageMiscOps.fillUniform(deriv1x,rand,-1,1); ImageMiscOps.fillUniform(deriv1y,rand,-1,1); ImageMiscOps.fillUniform(deriv2x,rand,-1,1); ImageMiscOps.fillUniform(deriv2y,rand,-1,1); ImageMiscOps.fillUniform(deriv2xx,rand,-1,1); ImageMiscOps.fillUniform(deriv2yy,rand,-1,1); ImageMiscOps.fillUniform(deriv2xy,rand,-1,1); ImageMiscOps.fillUniform(du,rand,-1,1); ImageMiscOps.fillUniform(dv,rand,-1,1); alg.computePsiDataPsiGradient(image1,image2,deriv1x,deriv1y,deriv2x,deriv2y,deriv2xx,deriv2yy,deriv2xy,du,dv, psiData,psiGradient); float expectedPsiData = computePsiData(5,6,image1,image2,deriv2x,deriv2y,du,dv); float expectedPsiGradient = computePsiGradient(5,6,deriv1x,deriv1y,deriv2x,deriv2y,deriv2xx,deriv2yy,deriv2xy,du,dv); assertEquals(expectedPsiData,psiData.get(5,6),1e-4); assertEquals(expectedPsiGradient,psiGradient.get(5,6),1e-4); } private float computePsiData(int x, int y , GrayF32 image1, GrayF32 image2, GrayF32 deriv2x, GrayF32 deriv2y, GrayF32 du, GrayF32 dv ) { float taylor2 = image2.get(x,y) + deriv2x.get(x,y)*du.get(x,y) + deriv2y.get(x,y)*dv.get(x,y); float d = taylor2 - image1.get(x,y); return (float)(1.0/(2.0*Math.sqrt(d*d+epsilon*epsilon))); // in the paper it is 1/2 but not their code } private float computePsiGradient(int x, int y , GrayF32 deriv1x, GrayF32 deriv1y, GrayF32 deriv2x, GrayF32 deriv2y, GrayF32 deriv2xx, GrayF32 deriv2yy, GrayF32 deriv2xy, GrayF32 du, GrayF32 dv ) { float taylor2x = deriv2x.get(x,y) + deriv2xx.get(x,y)*du.get(x,y) + deriv2xy.get(x,y)*dv.get(x,y); float taylor2y = deriv2y.get(x,y) + deriv2xy.get(x,y)*du.get(x,y) + deriv2yy.get(x,y)*dv.get(x,y); float dx = taylor2x - deriv1x.get(x,y); float dy = taylor2y - deriv1y.get(x,y); return (float)(1.0/(2.0*Math.sqrt(dx*dx + dy*dy + epsilon*epsilon))); // in the paper it is 1/2 but not their code } @Test public void computeDivUVD_safe() { GrayF32 u = new GrayF32(width,height); GrayF32 v = new GrayF32(width,height); GrayF32 psi = new GrayF32(width,height); GrayF32 divU = new GrayF32(width,height); GrayF32 divV = new GrayF32(width,height); GrayF32 divD = new GrayF32(width,height); ImageMiscOps.fillUniform(u,rand,-1,1); ImageMiscOps.fillUniform(v,rand,-1,1); ImageMiscOps.fillUniform(psi,rand,-1,1); BroxWarpingSpacial<GrayF32> alg = new BroxWarpingSpacial<>(new ConfigBroxWarping(),interpolate); alg.resizeForLayer(width,height); alg.computeDivUVD_safe(5,6,u,v,psi,divU,divV,divD); float expectedDivU = computeDivU(5,6,u,psi); float expectedDivV = computeDivU(5, 6, v, psi); float expectedDivD = computeDivD(5, 6, psi); assertEquals(expectedDivU,divU.get(5,6),1e-4); assertEquals(expectedDivV,divV.get(5,6),1e-4); assertEquals(expectedDivD,divD.get(5,6),1e-4); } private float computeDivU(int x , int y , GrayF32 u , GrayF32 psi ) { float coef0 = 0.5f*(psi.get(x+1,y) + psi.get(x,y)); float coef1 = 0.5f*(psi.get(x-1,y) + psi.get(x,y)); float coef2 = 0.5f*(psi.get(x,y+1) + psi.get(x,y)); float coef3 = 0.5f*(psi.get(x,y-1) + psi.get(x,y)); float diff0 = u.get(x+1,y) - u.get(x,y); float diff1 = u.get(x-1,y) - u.get(x,y); float diff2 = u.get(x,y+1) - u.get(x,y); float diff3 = u.get(x,y-1) - u.get(x,y); return coef0*diff0 + coef1*diff1 + coef2*diff2 + coef3*diff3; } private float computeDivD( int x , int y , GrayF32 psi ) { float coef0 = 0.5f*(psi.get(x+1,y) + psi.get(x,y)); float coef1 = 0.5f*(psi.get(x-1,y) + psi.get(x,y)); float coef2 = 0.5f*(psi.get(x,y+1) + psi.get(x,y)); float coef3 = 0.5f*(psi.get(x,y-1) + psi.get(x,y)); return coef0 + coef1 + coef2 + coef3; } @Test public void s() { BroxWarpingSpacial<GrayF32> alg = new BroxWarpingSpacial<>(new ConfigBroxWarping(),interpolate); alg.resizeForLayer(10,13); GrayF32 a = alg.warpImage2; assertEquals(a.getIndex(0,0),alg.s(-1,0),1e-4f); assertEquals(a.getIndex(0,0),alg.s(0,-1),1e-4f); assertEquals(a.getIndex(5,0),alg.s(5,-1),1e-4f); assertEquals(a.getIndex(5,height-1),alg.s(5,height),1e-4f); assertEquals(a.getIndex(0,5),alg.s(-1,5),1e-4f); assertEquals(a.getIndex(width-1,5),alg.s(width,5),1e-4f); } }