/* -*- mona-c++ -*-
* Copyright (c) Leipzig, Madrid 2004 - 2008
* Max-Planck-Institute for Human Cognitive and Brain Science
* Max-Planck-Institute for Evolutionary Anthropology
* BIT, ETSI Telecomunicacion, UPM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// $Id: distance2d.cc,v 1.10 2006-08-30 14:43:03 wollny Exp $
/*! \brief eva-2dimagefilter
\sa 3va-2dimagefilter.cc
\file mask.cc
\author G. Wollny, wollny eva.mpg.de, 2005
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <iostream>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <libmona/filter_plugin2d.hh>
#include <libmona/2DImageWrap.hh>
#include <libmona/monaException.hh>
#include <libmona/monaHistory.hh>
using namespace std;
using namespace mona;
// scaling of the distance field
#define SCALE 256
/* Revision string */
const char revision[] = "not specified";
enum EOps {dist_avg, dist_max};
class CGetDistance: public TUnaryImageFilter<double> {
public:
CGetDistance(const C2DFImage& dist_field, int method):
_M_distance(dist_field),
_M_method(method)
{
}
template <typename T>
CGetDistance::result_type operator()(const T2DImage<T>& image) const
{
switch (_M_method) {
case dist_avg: {
int n = 0;
double result = 0.0;
C2DFImage::const_iterator d = _M_distance.begin();
typename T2DImage<T>::const_iterator i = image.begin();
typename T2DImage<T>::const_iterator e = image.end();
while (i != e) {
if (*i) {
result += *d;
++n;
}
++d;
++i;
}
return n == 0 ? 0 : result / n;
}
case dist_max: {
double result = 0.0;
C2DFImage::const_iterator d = _M_distance.begin();
typename T2DImage<T>::const_iterator i = image.begin();
typename T2DImage<T>::const_iterator e = image.end();
while (i != e) {
if (*i)
if (result < *d)
result = *d;
++d;
++i;
}
return result;
}
default:
throw runtime_error("unknown distance measure requested\n");
}
}
private:
const C2DFImage& _M_distance;
int _M_method;
};
int main( int argc, const char *argv[] )
{
string in_filename;
string dist_filename;
float scale;
int method;
C2DImageIOPluginHandler imageio;
string types = string("output file type ( ") + imageio.supported_formats() + ")";
const popt::option::Dictionary combine_option[] = {
{"avg", dist_avg},
{"max", dist_max},
{NULL, 0},
};
popt::COptions options;
options.push_back(popt::option( in_filename, "in-file", 'i', "input image", NULL));
options.push_back(popt::option( dist_filename, "distance-file", 'd', "distance field image", NULL));
options.push_back(popt::option( scale, "scale", 's', "distance scaling factor", "256.0"));
options.push_back(popt::option( method, combine_option, "method", 'm', "distance measuring method", "avg"));
try {
vector<string> unknown_args;
popt::parse_options(argc, argv, options, unknown_args);
cvdebug() << "IO supported types: " << imageio.plugin_names() << "\n";
if ( !unknown_args.empty() )
cvwarn() << "unknown arguments\n";
if ( in_filename.empty() )
throw mona_runtime_error("'--in-image' ('i') option required");
CHistory::instance().append(argv[0], revision, options);
// read image
auto_ptr<C2DImageList> in_image_list(imageio.load(in_filename));
auto_ptr<C2DImageList> dist_image_list(imageio.load(dist_filename));
if (!dist_image_list.get() || dist_image_list->empty()) {
throw invalid_argument(dist_filename + ": no distance field found");
}
C2DFImage dist_image(C2DBounds(0,0));
C2DImageList::const_iterator wdimage = dist_image_list->begin();
if (wdimage->get_type() == it_float) {
const C2DFImage *dimage = wdimage->getC2DFImage();
assert(dimage);
dist_image = *dimage;
cvmsg() << "got a float distance field and ignore the scale\n";
}else if (wdimage->get_type() == it_ushort) {
const C2DUSImage *dimage = wdimage->getC2DUSImage();
assert(dimage);
dist_image = C2DFImage(dimage->get_size());
transform(dimage->begin(), dimage->end(), dist_image.begin(), bind2nd(multiplies<double>(),1.0/scale));
}else
throw invalid_argument("only float and unsigned short images are supported as distance field images");
if (in_image_list.get() && in_image_list->size()) {
CGetDistance get_distance(dist_image, method);
cout << wrap_filter(get_distance, *in_image_list->begin())<<"\n";
}
return EXIT_SUCCESS;
}
catch (const mona_runtime_error& e){
cerr << argv[0] << " error: " << e.what() << endl;
}
catch (const mona_fatal_error& e){
cerr << argv[0] << " fatal: " << e.what() << endl;
}
catch (const mona_exception& e){
cerr << argv[0] << " error: " << e.what() << endl;
}
catch (const runtime_error &e){
cerr << argv[0] << " runtime: " << e.what() << endl;
}
catch (const invalid_argument &e){
cerr << argv[0] << " error: " << e.what() << endl;
}
catch (const exception& e){
cerr << argv[0] << " error: " << e.what() << endl;
}
catch (...){
cerr << argv[0] << " unknown exception" << endl;
}
return EXIT_FAILURE;
}