/* Match two normalised, cumulative histograms. * * Copyright: 1991, N. Dessipris. * * Author: Nicos Dessipris * Written on: 19/07/1990 * Modified on: 26/03/1991 * * 1/3/01 JC * - bleurg! rewritten, now does 16 bits as well, bugs removed, faster, * smaller * 24/3/10 * - gtkdoc * - small cleanups * 12/8/13 * - redone im_histspec() as a class, vips_hist_match() * 19/12/13 * - oop, upcast input */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "phistogram.h" /* #define DEBUG */ typedef struct _VipsHistMatch { VipsHistogram parent_instance; VipsImage *in; VipsImage *ref; } VipsHistMatch; typedef VipsHistogramClass VipsHistMatchClass; G_DEFINE_TYPE( VipsHistMatch, vips_hist_match, VIPS_TYPE_HISTOGRAM ); static void vips_hist_match_process( VipsHistogram *histogram, VipsPel *out, VipsPel **in, int width ) { VipsHistMatch *match = (VipsHistMatch *) histogram; const int bands = match->in->Bands; const int max = width * bands; unsigned int *inbuf = (unsigned int *) in[0]; unsigned int *refbuf = (unsigned int *) in[1]; unsigned int *outbuf = (unsigned int *) out; int i, j; for( j = 0; j < bands; j++ ) { /* Track up refbuf[] with this. */ int ri = j; int limit = max - bands; for( i = j; i < max; i += bands ) { unsigned int inv = inbuf[i]; for( ; ri < limit; ri += bands ) if( inv <= refbuf[ri] ) break; if( ri < limit ) { /* Simple rounding. */ double mid = refbuf[ri] + refbuf[ri + bands] / 2.0; if( inv < mid ) outbuf[i] = ri / bands; else outbuf[i] = ri / bands + 1; } else outbuf[i] = refbuf[ri]; } } } static int vips_hist_match_build( VipsObject *object ) { VipsHistogram *histogram = VIPS_HISTOGRAM( object ); VipsHistMatch *match = (VipsHistMatch *) object; histogram->n = 2; histogram->in = (VipsImage **) vips_object_local_array( object, 2 ); histogram->in[0] = match->in; histogram->in[1] = match->ref; if( histogram->in[0] ) g_object_ref( histogram->in[0] ); if( histogram->in[1] ) g_object_ref( histogram->in[1] ); if( VIPS_OBJECT_CLASS( vips_hist_match_parent_class )->build( object ) ) return( -1 ); return( 0 ); } static void vips_hist_match_class_init( VipsHistMatchClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); VipsHistogramClass *hclass = VIPS_HISTOGRAM_CLASS( class ); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "hist_match"; vobject_class->description = _( "match two histograms" ); vobject_class->build = vips_hist_match_build; hclass->input_format = VIPS_FORMAT_UINT; hclass->process = vips_hist_match_process; VIPS_ARG_IMAGE( class, "in", 1, _( "Input" ), _( "Input histogram" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsHistMatch, in ) ); VIPS_ARG_IMAGE( class, "ref", 2, _( "Reference" ), _( "Reference histogram" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsHistMatch, ref ) ); } static void vips_hist_match_init( VipsHistMatch *match ) { } /** * vips_hist_match: (method) * @in: input histogram * @ref: reference histogram * @out: (out): output histogram * @...: %NULL-terminated list of optional named arguments * * Adjust @in to match @ref. If @in and @ref are normalised * cumulative histograms, @out will be a LUT that adjusts the PDF of the image * from which @in was made to match the PDF of @ref's image. * * See also: vips_maplut(), vips_hist_find(), vips_hist_norm(), * vips_hist_cum(). * * Returns: 0 on success, -1 on error */ int vips_hist_match( VipsImage *in, VipsImage *ref, VipsImage **out, ... ) { va_list ap; int result; va_start( ap, out ); result = vips_call_split( "hist_match", ap, in, ref, out ); va_end( ap ); return( result ); }