package mpicbg.trakem2.align.concurrent;
import ij.ImagePlus;
import ij.process.FloatProcessor;
import ini.trakem2.Project;
import ini.trakem2.display.Layer;
import ini.trakem2.display.Patch;
import ini.trakem2.utils.Filter;
import java.awt.Color;
import java.awt.Image;
import java.awt.Rectangle;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import mpicbg.ij.blockmatching.BlockMatching;
import mpicbg.models.AbstractModel;
import mpicbg.models.ErrorStatistic;
import mpicbg.models.InvertibleCoordinateTransform;
import mpicbg.models.Point;
import mpicbg.models.PointMatch;
import mpicbg.trakem2.align.AlignmentUtils;
import mpicbg.trakem2.align.ElasticLayerAlignment;
import mpicbg.trakem2.align.Util;
import mpicbg.trakem2.util.Triple;
/**
*
*/
public class BlockMatchPairCallable implements
Callable<BlockMatchPairCallable.BlockMatchResults>, Serializable
{
public static class BlockMatchResults implements Serializable
{
public Collection<? extends Point> v1, v2;
public final Collection<PointMatch> pm12, pm21;
public final boolean layer1Fixed, layer2Fixed;
public final Triple<Integer, Integer, AbstractModel<?>> pair;
public BlockMatchResults(final Collection<? extends Point> v1,
final Collection<? extends Point> v2,
final Collection<PointMatch> pm12,
final Collection<PointMatch> pm21,
final boolean layer1Fixed,
final boolean layer2Fixed,
final Triple<Integer, Integer, AbstractModel<?>> pair)
{
this.v1 = v1;
this.v2 = v2;
this.pm12 = pm12;
this.pm21 = pm21;
this.layer1Fixed = layer1Fixed;
this.layer2Fixed = layer2Fixed;
this.pair = pair;
}
}
private final Layer layer1, layer2;
private final boolean layer1Fixed, layer2Fixed;
private final Filter<Patch> filter;
private final ElasticLayerAlignment.Param param;
private final Collection<? extends Point> v1, v2;
private final Rectangle box;
private final Triple<Integer, Integer, AbstractModel<?>> pair;
public BlockMatchPairCallable(final Triple<Integer, Integer, AbstractModel<?>> pair,
final List<Layer> layerRange,
final boolean layer1Fixed,
final boolean layer2Fixed,
final Filter<Patch> filter,
final ElasticLayerAlignment.Param param,
final Collection< ? extends Point > sourcePoints1,
final Collection< ? extends Point > sourcePoints2,
final Rectangle box)
{
this.pair = pair;
layer1 = layerRange.get(pair.a);
layer2 = layerRange.get(pair.b);
this.layer1Fixed = layer1Fixed;
this.layer2Fixed = layer2Fixed;
this.filter = filter;
this.param = param;
v1 = sourcePoints1;
v2 = sourcePoints2;
this.box = box;
}
@Override
public BlockMatchResults call() throws Exception
{
final ArrayList< PointMatch > pm12 = new ArrayList< PointMatch >();
final ArrayList< PointMatch > pm21 = new ArrayList< PointMatch >();
final Project project = layer1.getProject();
System.out.println("BMC rev 0: " + pair.a + " " + pair.b);
final Image img1 = project.getLoader().getFlatAWTImage(
layer1,
box,
param.layerScale,
0xffffffff,
ImagePlus.COLOR_RGB,
Patch.class,
AlignmentUtils.filterPatches(layer1, filter),
true,
new Color( 0x00ffffff, true ) );
final Image img2 = project.getLoader().getFlatAWTImage(
layer2,
box,
param.layerScale,
0xffffffff,
ImagePlus.COLOR_RGB,
Patch.class,
AlignmentUtils.filterPatches( layer2, filter ),
true,
new Color( 0x00ffffff, true ) );
final int width = img1.getWidth( null );
final int height = img1.getHeight( null );
final AbstractModel< ? > localSmoothnessFilterModel =
Util.createModel(param.localModelIndex);
final FloatProcessor ip1 = new FloatProcessor( width, height );
final FloatProcessor ip2 = new FloatProcessor( width, height );
final FloatProcessor ip1Mask = new FloatProcessor( width, height );
final FloatProcessor ip2Mask = new FloatProcessor( width, height );
final int blockRadius =
Math.max( 16, mpicbg.util.Util.roundPos( param.layerScale * param.blockRadius ) );
/* scale pixel distances */
final int searchRadius = ( int )Math.round( param.layerScale * param.searchRadius );
final double localRegionSigma = param.layerScale * param.localRegionSigma;
final double maxLocalEpsilon = param.layerScale * param.maxLocalEpsilon;
mpicbg.trakem2.align.Util.imageToFloatAndMask( img1, ip1, ip1Mask );
mpicbg.trakem2.align.Util.imageToFloatAndMask( img2, ip2, ip2Mask );
if (!layer1Fixed)
{
BlockMatching.matchByMaximalPMCC(
ip1,
ip2,
ip1Mask,
ip2Mask,
1.0,
((InvertibleCoordinateTransform) pair.c).createInverse(),
blockRadius,
blockRadius,
searchRadius,
searchRadius,
param.minR,
param.rodR,
param.maxCurvatureR,
v1,
pm12,
new ErrorStatistic(1));
if ( Thread.interrupted() )
{
throw new InterruptedException("Block matching interrupted.");
}
if ( param.useLocalSmoothnessFilter )
{
localSmoothnessFilterModel.localSmoothnessFilter( pm12, pm12, localRegionSigma,
maxLocalEpsilon, param.maxLocalTrust );
}
}
if (!layer2Fixed)
{
BlockMatching.matchByMaximalPMCC(
ip2,
ip1,
ip2Mask,
ip1Mask,
1.0f,
pair.c,
blockRadius,
blockRadius,
searchRadius,
searchRadius,
param.minR,
param.rodR,
param.maxCurvatureR,
v2,
pm21,
new ErrorStatistic( 1 ) );
if ( Thread.interrupted() )
{
throw new InterruptedException("Block matching interrupted.");
}
if ( param.useLocalSmoothnessFilter )
{
localSmoothnessFilterModel.localSmoothnessFilter( pm21, pm21, localRegionSigma, maxLocalEpsilon, param.maxLocalTrust );
}
}
// Utils.log( pair.a + " <> " + pair.b + " spring constant = " + springConstant );
return new BlockMatchResults(v1, v2, pm12, pm21, layer1Fixed, layer2Fixed, pair);
}
}