/*
* 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.impl;
import boofcv.alg.distort.ImageDistort;
import boofcv.alg.interpolate.InterpolatePixel;
import boofcv.alg.interpolate.InterpolationType;
import boofcv.alg.misc.GImageMiscOps;
import boofcv.core.image.GeneralizedImageOps;
import boofcv.core.image.border.BorderType;
import boofcv.factory.interpolate.FactoryInterpolation;
import boofcv.struct.distort.PixelTransform2_F32;
import boofcv.struct.image.ImageBase;
import boofcv.struct.image.ImageType;
import org.junit.Test;
import java.util.Random;
import static org.junit.Assert.assertEquals;
/**
* @author Peter Abeles
*/
@SuppressWarnings({"unchecked"})
public abstract class GeneralImageDistortTests<T extends ImageBase> {
Random rand = new Random(123);
int width = 30;
int height = 20;
int offX = 2;
int offY = 1;
InterpolatePixel<T> interp;
ImageType<T> imageType;
public GeneralImageDistortTests( ImageType<T> imageType ) {
this.imageType = imageType;
interp = FactoryInterpolation.createPixel(0,255, InterpolationType.NEAREST_NEIGHBOR,BorderType.ZERO,imageType);
}
public abstract ImageDistort<T,T> createDistort(PixelTransform2_F32 dstToSrc, InterpolatePixel<T> interp );
/**
* Makes sure it renders all by default
*/
@Test
public void defaultRenderAllIsTrue() {
T src = imageType.createImage(width,height);
T dst = imageType.createImage(width, height);
GImageMiscOps.fillUniform(src, rand, 0, 10);
GImageMiscOps.fill(dst, 50);
ImageDistort<T,T> tran = createDistort(new BasicTransform(),interp);
tran.apply(src, dst);
for (int band = 0; band < imageType.getNumBands(); band++) {
double value = GeneralizedImageOps.get(dst, dst.getWidth() - 1, dst.getHeight() - 1, band);
assertEquals(0, value, 1e-8);
}
// sanity check
tran.setRenderAll(false);
GImageMiscOps.fill(dst, 50);
tran.apply(src, dst);
for (int band = 0; band < imageType.getNumBands(); band++) {
double value = GeneralizedImageOps.get(dst,dst.getWidth()-1,dst.getHeight()-1,band);
assertEquals(50, value, 1e-8);
}
}
@Test
public void checkRenderAll() {
testDefaultValue(true);
testDefaultValue(false);
}
public void testDefaultValue( boolean renderAll ) {
T src = imageType.createImage(width,height);
T dst = imageType.createImage(width, height);
GImageMiscOps.fillUniform(src, rand, 0, 10);
GImageMiscOps.fill(dst,50);
ImageDistort<T,T> tran = createDistort(new BasicTransform(),interp);
tran.setRenderAll(renderAll);
tran.apply(src, dst);
for( int dstY = 0; dstY < height; dstY++ ) {
for( int dstX = 0; dstX < width; dstX++ ) {
for (int band = 0; band < imageType.getNumBands(); band++) {
int srcX = dstX + offX;
int srcY = dstY + offY;
double dstVal = GeneralizedImageOps.get(dst, dstX, dstY, band);
if (src.isInBounds(srcX, srcY)) {
double srcVal = GeneralizedImageOps.get(src, srcX, srcY, band);
assertEquals(srcVal, dstVal, 1e-4);
} else if (renderAll) {
// background set it to 0
assertEquals(0.0, dstVal, 1e-4);
} else {
// original value of 50 wasn't modified
assertEquals(50.0, dstVal, 1e-4);
}
}
}
}
}
@Test
public void testCrop() {
testCrop(true);
testCrop(false);
}
public void testCrop( boolean renderAll ) {
// the crop region
int x0=12,y0=10,x1=17,y1=18;
T src = imageType.createImage(width,height);
T dst = imageType.createImage(width, height);
GImageMiscOps.fillUniform(src, rand, 0, 10);
GImageMiscOps.fill(dst, 50);
ImageDistort<T,T> tran = createDistort(new BasicTransform(),interp);
tran.setRenderAll(renderAll);
tran.apply(src,dst,x0,y0,x1,y1);
for( int dstY = 0; dstY < height; dstY++ ) {
for( int dstX = 0; dstX < width; dstX++ ) {
for (int band = 0; band < imageType.getNumBands(); band++) {
// should be 50 outside of the crop region
if( dstX < x0 || dstX >= x1 || dstY < y0 || dstY >= y1 )
assertEquals(50,GeneralizedImageOps.get(dst,dstX,dstY,band),1e-4);
else {
int srcX = dstX + offX;
int srcY = dstY + offY;
double dstVal = GeneralizedImageOps.get(dst,dstX,dstY,band);
if( src.isInBounds(srcX,srcY) ) {
double srcVal = GeneralizedImageOps.get(src,srcX,srcY,band);
assertEquals(srcVal,dstVal,1e-4);
} else if( renderAll ) {
assertEquals(0,dstVal,1e-4);
}
}
}
}
}
}
/**
* Request a pixel outside the image border
*/
@Test
public void testOutsideCrop() {
testOutsideCrop(true);
testOutsideCrop(false);
}
public void testOutsideCrop( boolean renderAll ) {
// the crop region
int x0=12,y0=10,x1=width,y1=height;
T src = imageType.createImage(width,height);
T dst = imageType.createImage(width, height);
GImageMiscOps.fillUniform(src, rand, 0, 10);
GImageMiscOps.fill(dst, 50);
ImageDistort<T,T> tran = createDistort(new BasicTransform(),interp);
tran.setRenderAll(renderAll);
tran.apply(src,dst,x0,y0,x1,y1);
for( int dstY = 0; dstY < height; dstY++ ) {
for( int dstX = 0; dstX < width; dstX++ ) {
for (int band = 0; band < imageType.getNumBands(); band++) {
// should be 50 outside of the crop region
if( dstX < x0 || dstX >= x1 || dstY < y0 || dstY >= y1 )
assertEquals(50,GeneralizedImageOps.get(dst,dstX,dstY,band),1e-4);
else {
int srcX = dstX + offX;
int srcY = dstY + offY;
double dstVal = GeneralizedImageOps.get(dst,dstX,dstY,band);
if( src.isInBounds(srcX,srcY) ) {
double srcVal = GeneralizedImageOps.get(src,srcX,srcY,band);
assertEquals(srcVal,dstVal,1e-4);
} else if( renderAll ) {
assertEquals(0,dstVal,1e-4);
}
}
}
}
}
}
public class BasicTransform extends PixelTransform2_F32 {
@Override
public void compute(int x, int y) {
this.distX = x+offX;
this.distY = y+offY;
}
}
}