/*
* 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.distort;
import boofcv.alg.interpolate.InterpolatePixelS;
import boofcv.alg.interpolate.InterpolationType;
import boofcv.alg.misc.GImageMiscOps;
import boofcv.core.image.border.BorderType;
import boofcv.factory.interpolate.FactoryInterpolation;
import boofcv.struct.image.GrayF32;
import georegression.struct.affine.Affine2D_F32;
import georegression.struct.affine.Affine2D_F64;
import georegression.struct.shapes.RectangleLength2D_F32;
import georegression.struct.shapes.RectangleLength2D_F64;
import georegression.struct.shapes.RectangleLength2D_I32;
import org.junit.Test;
import java.util.Random;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Peter Abeles
*/
@SuppressWarnings({"unchecked"})
public class TestDistortImageOps {
Random rand = new Random(234);
int width = 20;
int height = 30;
/**
* Checks to see if the two ways of specifying interpolation work
*/
@Test
public void scale_InterpTypeStyle() {
GrayF32 input = new GrayF32(width,height);
GrayF32 output = new GrayF32(width,height);
GImageMiscOps.fillUniform(input, rand, 0, 100);
DistortImageOps.scale(input,output, BorderType.ZERO, InterpolationType.BILINEAR);
InterpolatePixelS<GrayF32> interp = FactoryInterpolation.bilinearPixelS(input, BorderType.EXTENDED);
interp.setImage(input);
float scaleX = (float)input.width/(float)output.width;
float scaleY = (float)input.height/(float)output.height;
if( input.getDataType().isInteger() ) {
for( int i = 0; i < output.height; i++ ) {
for( int j = 0; j < output.width; j++ ) {
float val = interp.get(j*scaleX,i*scaleY);
assertEquals((int)val,output.get(j,i),1e-4);
}
}
} else {
for( int i = 0; i < output.height; i++ ) {
for( int j = 0; j < output.width; j++ ) {
float val = interp.get(j*scaleX,i*scaleY);
assertEquals(val,output.get(j,i),1e-4);
}
}
}
}
/**
* Very simple test for rotation accuracy.
*/
@Test
public void rotate_SanityCheck() {
GrayF32 input = new GrayF32(width,height);
GrayF32 output = new GrayF32(height,width);
GImageMiscOps.fillUniform(input, rand, 0, 100);
DistortImageOps.rotate(input, output,BorderType.ZERO, InterpolationType.BILINEAR, (float) Math.PI / 2f);
double error = 0;
// the outside pixels are ignored because numerical round off can cause those to be skipped
for( int y = 1; y < input.height-1; y++ ) {
for( int x = 1; x < input.width-1; x++ ) {
int xx = output.width-y;
int yy = x;
double e = input.get(x,y)-output.get(xx,yy);
error += Math.abs(e);
}
}
assertTrue(error / (width * height) < 0.1);
}
/**
* boundBox that checks to see if it is contained inside the output image.
*/
@Test
public void boundBox_check() {
// basic sanity check
Affine2D_F32 affine = new Affine2D_F32(1,0,0,1,2,3);
PixelTransformAffine_F32 transform = new PixelTransformAffine_F32(affine);
RectangleLength2D_I32 found = DistortImageOps.boundBox(10,20,30,40,transform);
assertEquals(2,found.x0);
assertEquals(3,found.y0);
assertEquals(10,found.width);
assertEquals(20,found.height);
// bottom right border
found = DistortImageOps.boundBox(10,20,8,18,transform);
assertEquals(2,found.x0);
assertEquals(3,found.y0);
assertEquals(6,found.width);
assertEquals(15,found.height);
// top right border
affine.set(new Affine2D_F32(1,0,0,1,-2,-3));
found = DistortImageOps.boundBox(10,20,8,18,transform);
assertEquals(0,found.x0);
assertEquals(0,found.y0);
assertEquals(8,found.width);
assertEquals(17,found.height);
}
@Test
public void boundBox() {
// basic sanity check
Affine2D_F32 affine = new Affine2D_F32(1,0,0,1,2,3);
PixelTransformAffine_F32 transform = new PixelTransformAffine_F32(affine);
RectangleLength2D_I32 found = DistortImageOps.boundBox(10,20,transform);
assertEquals(2,found.x0);
assertEquals(3,found.y0);
assertEquals(10,found.width);
assertEquals(20,found.height);
}
@Test
public void boundBox_F32() {
// basic sanity check
Affine2D_F32 affine = new Affine2D_F32(1,0,0,1,2,3);
PixelTransformAffine_F32 transform = new PixelTransformAffine_F32(affine);
RectangleLength2D_F32 found = DistortImageOps.boundBox_F32(10,20,transform);
assertEquals(2,found.x0,1e-4);
assertEquals(3,found.y0,1e-4);
assertEquals(10,found.width,1e-4);
assertEquals(20,found.height,1e-4);
}
@Test
public void boundBox_F64() {
// basic sanity check
Affine2D_F64 affine = new Affine2D_F64(1,0,0,1,2,3);
PixelTransformAffine_F64 transform = new PixelTransformAffine_F64(affine);
RectangleLength2D_F64 found = DistortImageOps.boundBox_F64(10, 20, transform);
assertEquals(2,found.x0,1e-8);
assertEquals(3,found.y0,1e-8);
assertEquals(10,found.width,1e-8);
assertEquals(20,found.height,1e-8);
}
}