/* -*- 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
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <memory>
#include <vector>
#include <tiffio.h>
#include <libmona/filter_plugin2d.hh>
#include <libmona/2DImageWrap.hh>
#include <libmona/3DImagePtr.hh>
#include <libmona/monaException.hh>
#include <libmona/monaHistory.hh>
#include <libmona/monaAlgorithms.hh>
#include <libmona/probmapio.hh>
using namespace mona;
using namespace std;
static const char *revision = "$Revision: 1.5 $";
typedef TIFF * PTIFF;
struct CTiffFile {
CTiffFile(const char *name, const char *flags):
handle(TIFFOpen(name, flags))
{
}
~CTiffFile()
{
if (handle)
TIFFClose(handle);
}
operator PTIFF() {
return handle;
}
private:
TIFF *handle;
};
extern "C" void MyErrorHandler(const char *module, const char *fmt, va_list ap)
{
char buf[16384];
snprintf(buf,16384, fmt, ap);
stringstream errmsg;
cvdebug() << module << ":" << buf << "\n";
errmsg << module << ":" << buf;
throw runtime_error(errmsg.str());
}
struct CErrorHandlerReplacer {
CErrorHandlerReplacer():
_M_old_handler(TIFFSetErrorHandler(MyErrorHandler))
{
}
~CErrorHandlerReplacer() {
TIFFSetErrorHandler(_M_old_handler);
}
private:
TIFFErrorHandler _M_old_handler;
};
template <typename InIterator>
bool compose(InIterator i1b, InIterator i1e, const CProbabilityVector& pv, const C2DBounds& size, const string& out_filename)
{
cvdebug() << "enter compose()\n";
typedef vector<unsigned char> outvector;
uint32 rows_per_strip = 64000 / (size.x * sizeof(unsigned char));
if (rows_per_strip < 4)
rows_per_strip = 4;
// copy data
outvector ov(size.x * size.y * 3);
typename outvector::iterator iout = ov.begin();
while (i1b != i1e) {
size_t val = (size_t)*i1b;
if (val < pv[0].size()){
*iout++ = (unsigned char)(255 * pv[0][val]);
*iout++ = (unsigned char)(255 * pv[1][val]);
*iout++ = (unsigned char)(255 * pv[2][val]);
}else {
*iout++ = 0;
*iout++ = 0;
*iout++ = 0;
}
++i1b;
}
cvdebug() << "created target vector\n";
// create the file
CTiffFile tif(out_filename.c_str(), "w");
if (!tif)
throw mona_runtime_error(string("Unable to open ") + out_filename + " for writing");
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, size.x);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, size.y);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8 * sizeof(unsigned char));
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_XRESOLUTION, 120.0);
TIFFSetField(tif, TIFFTAG_YRESOLUTION, 120.0);
TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
int nstrips = (size.y + rows_per_strip - 1) / rows_per_strip;
int start_index = 0;
for (int i = 0; i < nstrips; ++i) {
uint32 cur_rows = rows_per_strip;
// last strip might be shorter
if (i == nstrips - 1)
cur_rows = size.y - i * rows_per_strip;
uint32 samples_to_push = cur_rows * size.x * 3;
// write the stuff
TIFFWriteEncodedStrip(tif, i, &ov[start_index], samples_to_push * sizeof(unsigned char));
start_index += samples_to_push;
}
TIFFWriteDirectory(tif);
return true;
}
class CTiffComposer:public TUnaryImageFilter<bool> {
public:
CTiffComposer(const CProbabilityVector& pv, const string& out_filename):
_M_pv(pv),
_M_out_filename(out_filename)
{
}
template <class Image2D>
CTiffComposer::result_type operator () (const Image2D& image)
{
return compose(image.begin(), image.end(), _M_pv, image.get_size(), _M_out_filename);
}
private:
CProbabilityVector _M_pv;
string _M_out_filename;
};
bool compose_and_save_image(const C2DImageWrap& i1, const CProbabilityVector& pv, const string& out_filename)
{
return false;
}
int main(int argc, const char *argv[])
{
string in_filename;
string out_filename;
string map_filename;
popt::COptions options;
options.push_back(popt::option( in_filename, "in-file", 'i', "image set of different gray scale images", NULL ));
options.push_back(popt::option( map_filename, "map-file",'m', "probability map file name", NULL));
options.push_back(popt::option( out_filename, "out-file", 'o', "composed image", NULL ));
try {
vector<string> non_options;
popt::parse_options(argc, argv, options, non_options);
// what to do with unrecognized options
if ( non_options.size() > 0 )
throw invalid_argument("unknown options");
// required options (anything that has no default value)
if ( in_filename.empty() )
throw mona_runtime_error("'--in-file' ('i') option required\\n");
if ( out_filename.empty() )
throw mona_runtime_error("'--out-file' ('o') option required\\n");
C2DImageIOPluginHandler imageio;
// read data
auto_ptr<C2DImageList> inImage_list(imageio.load(in_filename));
if (!inImage_list.get() || !inImage_list->size() ) {
string not_found = string("No supported data found in ") + in_filename;
throw mona_runtime_error(not_found);
}
CProbabilityVector pv = load_probability_map(map_filename);
if (pv.empty())
throw invalid_argument(string("No probability map found in '") + map_filename + string("'"));
CHistory::instance().append(argv[0], revision, options);
CTiffComposer c(pv, out_filename);
return !wrap_filter(c, *inImage_list->begin());
}
catch (const mona_runtime_error& e){
cverr() << argv[0] << " error: " << e.what() << endl;
}
catch (const mona_fatal_error& e){
cverr() << argv[0] << " fatal: " << e.what() << endl;
}
catch (const mona_exception& e){
cverr() << argv[0] << " error: " << e.what() << endl;
}
catch (const invalid_argument &e){
cverr() << argv[0] << " error: " << e.what() << endl;
}
catch (const exception& e){
cverr() << argv[0] << " error: " << e.what() << endl;
}
catch (...){
cverr() << argv[0] << " unknown exception" << endl;
}
return EXIT_FAILURE;
}