/*******************************************************************************
* Copyright 2014 Analog Devices, Inc.
*
* 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 com.analog.lyric.dimple.benchmarks.stereoVision;
import com.analog.lyric.benchmarking.utils.doublespace.DoubleSpace;
import com.analog.lyric.benchmarking.utils.doublespace.DoubleSpaceFactory;
import com.analog.lyric.dimple.factorfunctions.core.FactorFunction;
import com.analog.lyric.dimple.model.core.FactorGraph;
import com.analog.lyric.dimple.model.domains.DiscreteDomain;
import com.analog.lyric.dimple.model.values.Value;
import com.analog.lyric.dimple.model.variables.Discrete;
public class StereoVisionGraph
{
static final double ed = 0.01;
static final double ep = 0.05;
static final double sigmaD = 8;
static final double sigmaP = 0.6;
static final double sigmaF = 0.3;
private int _height;
private int _width;
private int _depthRange;
private Discrete[][] _variables;
public StereoVisionGraph(FactorGraph fg, int depthRange, DoubleSpace imageL, DoubleSpace imageR)
{
int[] dims = imageL.getDimensions();
_height = dims[0];
_width = dims[1];
_depthRange = depthRange;
// Create variables
DiscreteDomain depthDomain = DiscreteDomain.range(1, depthRange);
_variables = new Discrete[_height][_width];
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
Discrete variable = new Discrete(depthDomain);
variable.setPrior(rho_d(x, y, depthRange, imageL, imageR));
_variables[y][x] = variable;
}
}
// Create factors
rho_p factorFunction = new rho_p();
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width - 1; x++)
{
fg.addFactor(factorFunction, _variables[y][x], _variables[y][x + 1]);
}
}
for (int y = 0; y < _height - 1; y++)
{
for (int x = 0; x < _width; x++)
{
fg.addFactor(factorFunction, _variables[y][x], _variables[y + 1][x]);
}
}
}
public DoubleSpace getValueImage()
{
// The image includes a 10-pixel gray scale reference on the right.
DoubleSpace image = DoubleSpaceFactory.create(_height, _width + 10);
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
int value = (Integer) _variables[y][x].getValue();
image.put((double) value / _depthRange, y, x);
}
double depth = ((double) ((int) ((double) y / _height * _depthRange))) / _depthRange;
for (int x = 0; x < 10; x++)
{
image.put(depth, y, _width + x);
}
}
return image;
}
private static double[] rho_d(int x, int y, int depthRange, DoubleSpace imageL, DoubleSpace imageR)
{
double[] result = new double[depthRange];
double[] birchfieldTomasi = birchfieldTomasi(x, y, depthRange, imageL, imageR);
for (int depth = 0; depth < depthRange; depth++)
{
result[depth] = (1 - ed) * Math.exp(-birchfieldTomasi[depth] / sigmaD) + ed;
}
return result;
}
private static double[] birchfieldTomasi(int x, int y, int depthRange, DoubleSpace imageL, DoubleSpace imageR)
{
double[] result = new double[depthRange];
double il1 = imageL.get(y, x);
for (int depth = 0; depth < depthRange; depth++)
{
if (x - depth < 0)
{
result[depth] = 5000.0;
}
else
{
double ir1 = imageR.get(y, x - depth);
result[depth] = Math.abs(il1 - ir1) / sigmaF;
}
}
return result;
}
private static class rho_p extends FactorFunction
{
@Override
public final double evalEnergy(Value[] args)
{
int ds = args[0].getInt();
int dt = args[1].getInt();
return -Math.log( (1 - ep) * Math.exp(-Math.abs(ds - dt) / sigmaP) + ep );
}
}
}