/*
* 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.feature.orientation;
import boofcv.abst.feature.orientation.OrientationImage;
import boofcv.core.image.GeneralizedImageOps;
import boofcv.struct.image.ImageGray;
import georegression.metric.UtilAngle;
import static org.junit.Assert.assertTrue;
/**
* Generic tests for implementers of {@link boofcv.abst.feature.orientation.OrientationGradient}.
*
* @author Peter Abeles
*/
public class GenericOrientationImageTests<T extends ImageGray> {
int width = 30;
int height = 40;
int regionSize;
// how accurate angle estimates are
double angleTolerance;
// the algorithm being tested
OrientationImage<T> alg;
// integral image
T image;
public void setup(double angleTolerance, int regionSize ,
OrientationImage<T> alg , Class<T> imageType ) {
this.angleTolerance = angleTolerance;
this.regionSize = regionSize;
this.alg = alg;
image = GeneralizedImageOps.createSingleBand(imageType, width, height);
}
/**
* Performs all the tests, but the weighted test.
*/
public void performAll() {
performEasyTests();
setRadius();
checkSubImages();
}
/**
* Points all pixels in the surrounding region in same direction. Then sees if the found
* direction for the region is in the expected direction.
*/
public void performEasyTests() {
alg.setObjectRadius(5);
int N = 2*(int)(Math.PI/angleTolerance);
int x = width/2;
int y = height/2;
for( int i = 0; i < N; i++ ) {
double angle = UtilAngle.bound(i*angleTolerance);
createOrientedImage(angle);
alg.setImage(image);
double found = UtilAngle.bound(alg.compute(x,y));
assertTrue( angle+" "+found,UtilAngle.dist(angle,found) < angleTolerance );
}
}
/**
* Estimate the direction at a couple of different scales and see if it produces the expected results.
*/
public void setRadius() {
int x = width/2;
int y = height/2;
int N = 2*(int)(Math.PI/angleTolerance);
double angle = UtilAngle.bound((N/2)*angleTolerance);
createOrientedImage(angle);
alg.setImage(image);
alg.setObjectRadius(5);
double found = UtilAngle.bound(alg.compute(x,y));
assertTrue( UtilAngle.dist(angle,found) < angleTolerance );
alg.setObjectRadius(10);
found = UtilAngle.bound(alg.compute(x,y));
assertTrue( UtilAngle.dist(angle,found) < angleTolerance );
alg.setObjectRadius(2.5);
found = UtilAngle.bound(alg.compute(x,y));
assertTrue( UtilAngle.dist(angle,found) < angleTolerance );
}
/**
* See if it can handle sub-images correctly
*/
public void checkSubImages() {
double angle = 0.5;
createOrientedImage(angle);
// set the border of the image to zeros to screw up orientation estimation
for( int i = 0; i < height; i++ ) {
for( int j = 0; j < width; j++ ) {
if( j >= regionSize || i >= regionSize )
GeneralizedImageOps.set(image,j,i,0);
}
}
T sub = (T)image.subimage(0,0,regionSize,regionSize, null);
alg.setObjectRadius(regionSize/3.0);
alg.setImage(sub);
double found = UtilAngle.bound(alg.compute(sub.width/2,sub.height/2));
assertTrue( angle+" "+found,UtilAngle.dist(angle,found) < angleTolerance );
}
/**
* Creates an integral image where the whole image has a gradient in the specified direction.
* @param angle
*/
private void createOrientedImage( double angle ) {
double c = Math.cos(angle);
double s = Math.sin(angle);
for( int y = 0; y < height; y++ ) {
for( int x = 0; x < width; x++ ) {
double val = 125+2*(x*c + y*s);
if( val < 0 || val > 255) {
throw new RuntimeException("Value is out of bounds for U8");
}
GeneralizedImageOps.set(image,x,y,val);
}
}
}
}