move im_maplut() to a class
This commit is contained in:
parent
b7d2f7e3e1
commit
226095c39d
@ -2,10 +2,10 @@
|
|||||||
- added vips_matrixload() and vips_matrixsave(), load and save vips mat format
|
- added vips_matrixload() and vips_matrixsave(), load and save vips mat format
|
||||||
- rename image arrays as image matrices ... INTERPRETATION_ARRAY ->
|
- rename image arrays as image matrices ... INTERPRETATION_ARRAY ->
|
||||||
INTERPRETATION_MATRIX etc.
|
INTERPRETATION_MATRIX etc.
|
||||||
- rewrite im_buildlut(), im_identity*() to classes
|
- rewrite im_buildlut(), im_identity*(), im_maplut() as classes
|
||||||
- added vips_error_freeze()/vips_error_thaw()
|
- added vips_error_freeze()/vips_error_thaw()
|
||||||
- used freeze()/thaw() to stop file format sniffers logging spurious errors
|
- used freeze()/thaw() to stop file format sniffers logging spurious errors
|
||||||
- vipsthumbnail uses embedded jpg thumbnails
|
- vipsthumbnail uses embedded jpg thumbnails if it can
|
||||||
|
|
||||||
3/7/13 started 7.34.2
|
3/7/13 started 7.34.2
|
||||||
- lower priority for Matlab load to reduce segvs from Mat_Open(), thanks
|
- lower priority for Matlab load to reduce segvs from Mat_Open(), thanks
|
||||||
|
12
TODO
12
TODO
@ -1,3 +1,11 @@
|
|||||||
|
- rename vips_diag() as vips_info(), make it work like a log thing ...
|
||||||
|
normally no output, can be turned on with a --vips-verbose flag
|
||||||
|
|
||||||
|
handy with vipsthumbnail
|
||||||
|
|
||||||
|
- what's the difference between buildlut and invertlut? can we make invertlut
|
||||||
|
by just swapping the channels before calling buildlut?
|
||||||
|
|
||||||
- do we always call copy_fields and demand_hint with ALL input images? what
|
- do we always call copy_fields and demand_hint with ALL input images? what
|
||||||
about the operators in conversion?
|
about the operators in conversion?
|
||||||
|
|
||||||
@ -22,10 +30,6 @@
|
|||||||
|
|
||||||
we've moved all the no-input ones of to create now, I think
|
we've moved all the no-input ones of to create now, I think
|
||||||
|
|
||||||
- move im_buildlut() to create package
|
|
||||||
|
|
||||||
others too? identity?
|
|
||||||
|
|
||||||
|
|
||||||
- object construction is threadsafe, but class construction is not
|
- object construction is threadsafe, but class construction is not
|
||||||
|
|
||||||
|
@ -3307,7 +3307,24 @@ im_cross_phase( IMAGE *in1, IMAGE *in2, IMAGE *out )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is used by vipsthumbnail and the carrierwave shrinker to cache the
|
int
|
||||||
|
im_maplut( IMAGE *in, IMAGE *out, IMAGE *lut )
|
||||||
|
{
|
||||||
|
VipsImage *x;
|
||||||
|
|
||||||
|
if( vips_maplut( in, &x, lut, NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( im_copy( x, out ) ) {
|
||||||
|
g_object_unref( x );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
g_object_unref( x );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is used by the carrierwave shrinker to cache the
|
||||||
* output of shrink before doing the final affine.
|
* output of shrink before doing the final affine.
|
||||||
*
|
*
|
||||||
* We use the vips8 threaded tilecache to avoid a deadlock: suppose thread1,
|
* We use the vips8 threaded tilecache to avoid a deadlock: suppose thread1,
|
||||||
@ -3317,10 +3334,10 @@ im_cross_phase( IMAGE *in1, IMAGE *in2, IMAGE *out )
|
|||||||
*
|
*
|
||||||
* With an unthreaded tilecache (as we had before), thread2 will get
|
* With an unthreaded tilecache (as we had before), thread2 will get
|
||||||
* the cache lock and start evaling the second block of the shrink. When it
|
* the cache lock and start evaling the second block of the shrink. When it
|
||||||
* reaches the png reader it will stall untilthe first block has been used ...
|
* reaches the png reader it will stall until the first block has been used ...
|
||||||
* but it never will, since thread1 will block on this cache lock.
|
* but it never will, since thread1 will block on this cache lock.
|
||||||
*
|
*
|
||||||
* This function is only used in those two places (I think), so it's OK to
|
* This function is only used in this place (I think), so it's OK to
|
||||||
* hard-wire this to be a sequential threaded cache.
|
* hard-wire this to be a sequential threaded cache.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
noinst_LTLIBRARIES = libhistogram.la
|
noinst_LTLIBRARIES = libhistogram.la
|
||||||
|
|
||||||
libhistogram_la_SOURCES = \
|
libhistogram_la_SOURCES = \
|
||||||
|
maplut.c \
|
||||||
histogram.c \
|
histogram.c \
|
||||||
phistogram.h \
|
phistogram.h \
|
||||||
hist_dispatch.c \
|
hist_dispatch.c \
|
||||||
@ -17,7 +18,6 @@ libhistogram_la_SOURCES = \
|
|||||||
im_mpercent.c \
|
im_mpercent.c \
|
||||||
im_invertlut.c \
|
im_invertlut.c \
|
||||||
im_lhisteq.c \
|
im_lhisteq.c \
|
||||||
im_maplut.c \
|
|
||||||
im_project.c \
|
im_project.c \
|
||||||
im_stdif.c \
|
im_stdif.c \
|
||||||
tone.c
|
tone.c
|
||||||
|
@ -136,7 +136,7 @@ vips_histogram_init( VipsHistogram *histogram )
|
|||||||
void
|
void
|
||||||
vips_histogram_operation_init( void )
|
vips_histogram_operation_init( void )
|
||||||
{
|
{
|
||||||
extern GType vips_xyz_get_type( void );
|
extern GType vips_maplut_get_type( void );
|
||||||
|
|
||||||
vips_xyz_get_type();
|
vips_maplut_get_type();
|
||||||
}
|
}
|
||||||
|
@ -1,627 +0,0 @@
|
|||||||
/* map though a LUT
|
|
||||||
*
|
|
||||||
* Modified:
|
|
||||||
* 18/6/93 JC
|
|
||||||
* - oops! im_incheck() added for LUT image
|
|
||||||
* - some ANSIfication
|
|
||||||
* 15/7/93 JC
|
|
||||||
* - adapted for partial v2
|
|
||||||
* - ANSIfied
|
|
||||||
* - now does complex LUTs too
|
|
||||||
* 10/3/94 JC
|
|
||||||
* - more helpful error messages, slight reformatting
|
|
||||||
* 24/8/94 JC
|
|
||||||
* - now allows non-uchar image input
|
|
||||||
* 7/10/94 JC
|
|
||||||
* - uses im_malloc(), IM_NEW() etc.
|
|
||||||
* 13/3/95 JC
|
|
||||||
* - now takes a private copy of LUT, so user can im_close() LUT image
|
|
||||||
* after im_maplut() without fear of coredumps
|
|
||||||
* 23/6/95 JC
|
|
||||||
* - lut may now have many bands if image has just one band
|
|
||||||
* 3/3/01 JC
|
|
||||||
* - small speed ups
|
|
||||||
* 30/6/04
|
|
||||||
* - heh, 1 band image + 3 band lut + >8bit output has been broken for 9
|
|
||||||
* years :-)
|
|
||||||
* 7/11/07
|
|
||||||
* - new eval start/end system
|
|
||||||
* 25/3/10
|
|
||||||
* - gtkdoc
|
|
||||||
* - small cleanups
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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 <config.h>
|
|
||||||
#endif /*HAVE_CONFIG_H*/
|
|
||||||
#include <vips/intl.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <vips/vips.h>
|
|
||||||
|
|
||||||
/* Struct we carry for LUT operations.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
int fmt; /* LUT image BandFmt */
|
|
||||||
int nb; /* Number of bands in lut */
|
|
||||||
int es; /* IM_IMAGE_SIZEOF_ELEMENT() for lut image */
|
|
||||||
int sz; /* Number of elements in minor dimension */
|
|
||||||
int clp; /* Value we clip against */
|
|
||||||
VipsPel **table; /* Lut converted to 2d array */
|
|
||||||
int overflow; /* Number of overflows for non-uchar lut */
|
|
||||||
} LutInfo;
|
|
||||||
|
|
||||||
static int
|
|
||||||
lut_start( LutInfo *st )
|
|
||||||
{
|
|
||||||
st->overflow = 0;
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print overflows, if any.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
lut_end( LutInfo *st )
|
|
||||||
{
|
|
||||||
if( st->overflow )
|
|
||||||
im_warn( "im_maplut", _( "%d overflows detected" ),
|
|
||||||
st->overflow );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build a lut table.
|
|
||||||
*/
|
|
||||||
static LutInfo *
|
|
||||||
build_luts( IMAGE *out, IMAGE *lut )
|
|
||||||
{
|
|
||||||
LutInfo *st;
|
|
||||||
int i, x;
|
|
||||||
VipsPel *q;
|
|
||||||
|
|
||||||
if( !(st = IM_NEW( out, LutInfo )) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
/* Make luts. We unpack the LUT image into a C 2D array to speed
|
|
||||||
* processing.
|
|
||||||
*/
|
|
||||||
st->fmt = lut->BandFmt;
|
|
||||||
st->es = IM_IMAGE_SIZEOF_ELEMENT( lut );
|
|
||||||
st->nb = lut->Bands;
|
|
||||||
st->sz = lut->Xsize * lut->Ysize;
|
|
||||||
st->clp = st->sz - 1;
|
|
||||||
st->overflow = 0;
|
|
||||||
st->table = NULL;
|
|
||||||
if( im_add_evalstart_callback( out,
|
|
||||||
(im_callback_fn) lut_start, st, NULL ) ||
|
|
||||||
im_add_evalend_callback( out,
|
|
||||||
(im_callback_fn) lut_end, st, NULL ) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
/* Attach tables.
|
|
||||||
*/
|
|
||||||
if( !(st->table = IM_ARRAY( out, lut->Bands, VipsPel * )) )
|
|
||||||
return( NULL );
|
|
||||||
for( i = 0; i < lut->Bands; i++ )
|
|
||||||
if( !(st->table[i] = IM_ARRAY( out, st->sz * st->es, VipsPel )) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
/* Scan LUT and fill table.
|
|
||||||
*/
|
|
||||||
q = (VipsPel *) lut->data;
|
|
||||||
for( x = 0; x < st->sz; x++ )
|
|
||||||
for( i = 0; i < st->nb; i++ ) {
|
|
||||||
memcpy( st->table[i] + x * st->es, q, st->es );
|
|
||||||
q += st->es;
|
|
||||||
}
|
|
||||||
|
|
||||||
return( st );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Our sequence value: the region this sequence is using, and local stats.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
REGION *ir; /* Input region */
|
|
||||||
int overflow; /* Number of overflows */
|
|
||||||
} Seq;
|
|
||||||
|
|
||||||
/* Destroy a sequence value.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
maplut_stop( void *vseq, void *a, void *b )
|
|
||||||
{
|
|
||||||
Seq *seq = (Seq *) vseq;
|
|
||||||
LutInfo *st = (LutInfo *) b;
|
|
||||||
|
|
||||||
/* Add to global stats.
|
|
||||||
*/
|
|
||||||
st->overflow += seq->overflow;
|
|
||||||
|
|
||||||
IM_FREEF( im_region_free, seq->ir );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Our start function.
|
|
||||||
*/
|
|
||||||
static void *
|
|
||||||
maplut_start( IMAGE *out, void *a, void *b )
|
|
||||||
{
|
|
||||||
IMAGE *in = (IMAGE *) a;
|
|
||||||
Seq *seq;
|
|
||||||
|
|
||||||
if( !(seq = IM_NEW( out, Seq )) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
/* Init!
|
|
||||||
*/
|
|
||||||
seq->ir = NULL;
|
|
||||||
seq->overflow = 0;
|
|
||||||
|
|
||||||
if( !(seq->ir = im_region_create( in )) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
return( seq );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map through n non-complex luts.
|
|
||||||
*/
|
|
||||||
#define loop(OUT) { \
|
|
||||||
int b = st->nb; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
for( z = 0; z < b; z++ ) { \
|
|
||||||
VipsPel *p = IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
OUT *tlut = (OUT *) st->table[z]; \
|
|
||||||
\
|
|
||||||
for( x = z; x < ne; x += b ) \
|
|
||||||
q[x] = tlut[p[x]]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map through n complex luts.
|
|
||||||
*/
|
|
||||||
#define loopc(OUT) { \
|
|
||||||
int b = in->Bands; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
for( z = 0; z < b; z++ ) { \
|
|
||||||
VipsPel *p = IM_REGION_ADDR( ir, le, y ) + z; \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ) + z * 2; \
|
|
||||||
OUT *tlut = (OUT *) st->table[z]; \
|
|
||||||
\
|
|
||||||
for( x = 0; x < ne; x += b ) { \
|
|
||||||
int n = p[x] * 2; \
|
|
||||||
\
|
|
||||||
q[0] = tlut[n]; \
|
|
||||||
q[1] = tlut[n + 1]; \
|
|
||||||
q += b * 2; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define loopg(IN,OUT) { \
|
|
||||||
int b = st->nb; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
for( z = 0; z < b; z++ ) { \
|
|
||||||
IN *p = (IN *) IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
OUT *tlut = (OUT *) st->table[z]; \
|
|
||||||
\
|
|
||||||
for( x = z; x < ne; x += b ) { \
|
|
||||||
int index = p[x]; \
|
|
||||||
\
|
|
||||||
if( index > st->clp ) { \
|
|
||||||
index = st->clp; \
|
|
||||||
seq->overflow++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
q[x] = tlut[index]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define loopcg(IN,OUT) { \
|
|
||||||
int b = in->Bands; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
for( z = 0; z < b; z++ ) { \
|
|
||||||
IN *p = (IN *) IM_REGION_ADDR( ir, le, y ) + z; \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ) + z * 2; \
|
|
||||||
OUT *tlut = (OUT *) st->table[z]; \
|
|
||||||
\
|
|
||||||
for( x = 0; x < ne; x += b ) { \
|
|
||||||
int index = p[x]; \
|
|
||||||
\
|
|
||||||
if( index > st->clp ) { \
|
|
||||||
index = st->clp; \
|
|
||||||
seq->overflow++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
q[0] = tlut[index * 2]; \
|
|
||||||
q[1] = tlut[index * 2 + 1]; \
|
|
||||||
\
|
|
||||||
q += b * 2; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map image through one non-complex lut.
|
|
||||||
*/
|
|
||||||
#define loop1(OUT) { \
|
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
VipsPel *p = IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
\
|
|
||||||
for( x = 0; x < ne; x++ ) \
|
|
||||||
q[x] = tlut[p[x]]; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map image through one complex lut.
|
|
||||||
*/
|
|
||||||
#define loop1c(OUT) { \
|
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
VipsPel *p = IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
\
|
|
||||||
for( x = 0; x < ne; x++ ) { \
|
|
||||||
int n = p[x] * 2; \
|
|
||||||
\
|
|
||||||
q[0] = tlut[n]; \
|
|
||||||
q[1] = tlut[n + 1]; \
|
|
||||||
q += 2; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* As above, but the input image may be any unsigned integer type. We have to
|
|
||||||
* index the lut carefully, and record the number of overflows we detect.
|
|
||||||
*/
|
|
||||||
#define loop1g(IN,OUT) { \
|
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
IN *p = (IN *) IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
\
|
|
||||||
for( x = 0; x < ne; x++ ) { \
|
|
||||||
int index = p[x]; \
|
|
||||||
\
|
|
||||||
if( index > st->clp ) { \
|
|
||||||
index = st->clp; \
|
|
||||||
seq->overflow++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
q[x] = tlut[index]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define loop1cg(IN,OUT) { \
|
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
IN *p = (IN *) IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
\
|
|
||||||
for( x = 0; x < ne; x++ ) { \
|
|
||||||
int index = p[x]; \
|
|
||||||
\
|
|
||||||
if( index > st->clp ) { \
|
|
||||||
index = st->clp; \
|
|
||||||
seq->overflow++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
q[0] = tlut[index * 2]; \
|
|
||||||
q[1] = tlut[index * 2 + 1]; \
|
|
||||||
q += 2; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map 1-band image through a many-band non-complex lut.
|
|
||||||
*/
|
|
||||||
#define loop1m(OUT) { \
|
|
||||||
OUT **tlut = (OUT **) st->table; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
VipsPel *p = IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
\
|
|
||||||
for( i = 0, x = 0; x < np; x++ ) { \
|
|
||||||
int n = p[x]; \
|
|
||||||
\
|
|
||||||
for( z = 0; z < st->nb; z++, i++ ) \
|
|
||||||
q[i] = tlut[z][n]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map 1-band image through many-band complex lut.
|
|
||||||
*/
|
|
||||||
#define loop1cm(OUT) { \
|
|
||||||
OUT **tlut = (OUT **) st->table; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
VipsPel *p = IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
\
|
|
||||||
for( x = 0; x < np; x++ ) { \
|
|
||||||
int n = p[x] * 2; \
|
|
||||||
\
|
|
||||||
for( z = 0; z < st->nb; z++ ) { \
|
|
||||||
q[0] = tlut[z][n]; \
|
|
||||||
q[1] = tlut[z][n+1]; \
|
|
||||||
q += 2; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map 1-band uint or ushort image through a many-band non-complex LUT.
|
|
||||||
*/
|
|
||||||
#define loop1gm(IN,OUT) { \
|
|
||||||
OUT **tlut = (OUT **) st->table; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
IN *p = (IN *) IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
\
|
|
||||||
for( i = 0, x = 0; x < np; x++ ) { \
|
|
||||||
int n = p[x]; \
|
|
||||||
\
|
|
||||||
if( n > st->clp ) { \
|
|
||||||
n = st->clp; \
|
|
||||||
seq->overflow++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
for( z = 0; z < st->nb; z++, i++ ) \
|
|
||||||
q[i] = tlut[z][n]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map 1-band uint or ushort image through a many-band complex LUT.
|
|
||||||
*/
|
|
||||||
#define loop1cgm(IN,OUT) { \
|
|
||||||
OUT **tlut = (OUT **) st->table; \
|
|
||||||
\
|
|
||||||
for( y = to; y < bo; y++ ) { \
|
|
||||||
IN *p = (IN *) IM_REGION_ADDR( ir, le, y ); \
|
|
||||||
OUT *q = (OUT *) IM_REGION_ADDR( or, le, y ); \
|
|
||||||
\
|
|
||||||
for( x = 0; x < np; x++ ) { \
|
|
||||||
int n = p[x]; \
|
|
||||||
\
|
|
||||||
if( n > st->clp ) { \
|
|
||||||
n = st->clp; \
|
|
||||||
seq->overflow++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
for( z = 0; z < st->nb; z++ ) { \
|
|
||||||
q[0] = tlut[z][n * 2]; \
|
|
||||||
q[1] = tlut[z][n * 2 + 1]; \
|
|
||||||
q += 2; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Switch for input types. Has to be uint type!
|
|
||||||
*/
|
|
||||||
#define inner_switch( UCHAR, GEN, OUT ) \
|
|
||||||
switch( ir->im->BandFmt ) { \
|
|
||||||
case IM_BANDFMT_UCHAR: UCHAR( OUT ); break; \
|
|
||||||
case IM_BANDFMT_USHORT: GEN( unsigned short, OUT ); break; \
|
|
||||||
case IM_BANDFMT_UINT: GEN( unsigned int, OUT ); break; \
|
|
||||||
default: \
|
|
||||||
g_assert( 0 ); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Switch for LUT types. One function for non-complex images, a
|
|
||||||
* variant for complex ones. Another pair as well, in case the input is not
|
|
||||||
* uchar.
|
|
||||||
*/
|
|
||||||
#define outer_switch( UCHAR_F, UCHAR_FC, GEN_F, GEN_FC ) \
|
|
||||||
switch( st->fmt ) { \
|
|
||||||
case IM_BANDFMT_UCHAR: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
unsigned char ); break; \
|
|
||||||
case IM_BANDFMT_CHAR: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
char ); break; \
|
|
||||||
case IM_BANDFMT_USHORT: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
unsigned short ); break; \
|
|
||||||
case IM_BANDFMT_SHORT: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
short ); break; \
|
|
||||||
case IM_BANDFMT_UINT: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
unsigned int ); break; \
|
|
||||||
case IM_BANDFMT_INT: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
int ); break; \
|
|
||||||
case IM_BANDFMT_FLOAT: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
float ); break; \
|
|
||||||
case IM_BANDFMT_DOUBLE: inner_switch( UCHAR_F, GEN_F, \
|
|
||||||
double ); break; \
|
|
||||||
case IM_BANDFMT_COMPLEX: inner_switch( UCHAR_FC, GEN_FC, \
|
|
||||||
float ); break; \
|
|
||||||
case IM_BANDFMT_DPCOMPLEX: inner_switch( UCHAR_FC, GEN_FC, \
|
|
||||||
double ); break; \
|
|
||||||
default: \
|
|
||||||
g_assert( 0 ); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do a map.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
maplut_gen( REGION *or, void *vseq, void *a, void *b )
|
|
||||||
{
|
|
||||||
Seq *seq = (Seq *) vseq;
|
|
||||||
IMAGE *in = (IMAGE *) a;
|
|
||||||
LutInfo *st = (LutInfo *) b;
|
|
||||||
REGION *ir = seq->ir;
|
|
||||||
Rect *r = &or->valid;
|
|
||||||
int le = r->left;
|
|
||||||
int to = r->top;
|
|
||||||
int bo = IM_RECT_BOTTOM(r);
|
|
||||||
int np = r->width; /* Pels across region */
|
|
||||||
int ne = IM_REGION_N_ELEMENTS( or ); /* Number of elements */
|
|
||||||
int x, y, z, i;
|
|
||||||
|
|
||||||
/* Get input ready.
|
|
||||||
*/
|
|
||||||
if( im_prepare( ir, r ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Process!
|
|
||||||
*/
|
|
||||||
if( st->nb == 1 )
|
|
||||||
/* One band lut.
|
|
||||||
*/
|
|
||||||
outer_switch( loop1, loop1c, loop1g, loop1cg )
|
|
||||||
else
|
|
||||||
/* Many band lut.
|
|
||||||
*/
|
|
||||||
if( ir->im->Bands == 1 )
|
|
||||||
/* ... but 1 band input.
|
|
||||||
*/
|
|
||||||
outer_switch( loop1m, loop1cm, loop1gm, loop1cgm )
|
|
||||||
else
|
|
||||||
outer_switch( loop, loopc, loopg, loopcg )
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save a bit of typing.
|
|
||||||
*/
|
|
||||||
#define UC IM_BANDFMT_UCHAR
|
|
||||||
#define US IM_BANDFMT_USHORT
|
|
||||||
#define UI IM_BANDFMT_UINT
|
|
||||||
|
|
||||||
/* Type mapping: go to uchar or ushort.
|
|
||||||
*/
|
|
||||||
static int bandfmt_maplut[10] = {
|
|
||||||
/* UC C US S UI I F X D DX */
|
|
||||||
UC, UC, US, US, UI, UI, UI, UI, UI, UI
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* im_maplut:
|
|
||||||
* @in: input image
|
|
||||||
* @out: output image
|
|
||||||
* @lut: look-up table
|
|
||||||
*
|
|
||||||
* Map an image through another image acting as a LUT (Look Up Table).
|
|
||||||
* The lut may have any type, and the output image will be that type.
|
|
||||||
*
|
|
||||||
* The input image will be cast to one of the unsigned integer types, that is,
|
|
||||||
* IM_BANDFMT_UCHAR, IM_BANDFMT_USHORT or IM_BANDFMT_UINT.
|
|
||||||
*
|
|
||||||
* If @lut is too small for the input type (for example, if @in is
|
|
||||||
* IM_BANDFMT_UCHAR but @lut only has 100 elements), the lut is padded out
|
|
||||||
* by copying the last element. Overflows are reported at the end of
|
|
||||||
* computation.
|
|
||||||
* If @lut is too large, extra values are ignored.
|
|
||||||
*
|
|
||||||
* If @lut has one band, then all bands of @in pass through it. If @lut
|
|
||||||
* has same number of bands as @in, then each band is mapped
|
|
||||||
* separately. If @in has one band, then @lut may have many bands and
|
|
||||||
* the output will have the same number of bands as @lut.
|
|
||||||
*
|
|
||||||
* See also: im_histgr(), im_identity().
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, -1 on error
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
im_maplut( IMAGE *in, IMAGE *out, IMAGE *lut )
|
|
||||||
{
|
|
||||||
IMAGE *t;
|
|
||||||
LutInfo *st;
|
|
||||||
|
|
||||||
/* Check input output. Old-style IO from lut, for simplicity.
|
|
||||||
*/
|
|
||||||
if( im_check_hist( "im_maplut", lut ) ||
|
|
||||||
im_check_uncoded( "im_maplut", lut ) ||
|
|
||||||
im_check_uncoded( "im_maplut", in ) ||
|
|
||||||
im_check_bands_1orn( "im_maplut", in, lut ) ||
|
|
||||||
im_piocheck( in, out ) ||
|
|
||||||
im_incheck( lut ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Cast in to u8/u16/u32.
|
|
||||||
*/
|
|
||||||
if( !(t = im_open_local( out, "im_maplut", "p" )) ||
|
|
||||||
im_clip2fmt( in, t, bandfmt_maplut[in->BandFmt] ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Prepare the output header.
|
|
||||||
*/
|
|
||||||
if( im_cp_descv( out, t, lut, NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Force output to be the same type as lut.
|
|
||||||
*/
|
|
||||||
out->BandFmt = lut->BandFmt;
|
|
||||||
|
|
||||||
/* Output has same number of bands as LUT, unless LUT has 1 band, in
|
|
||||||
* which case output has same number of bands as input.
|
|
||||||
*/
|
|
||||||
if( lut->Bands != 1 )
|
|
||||||
out->Bands = lut->Bands;
|
|
||||||
|
|
||||||
/* Make tables.
|
|
||||||
*/
|
|
||||||
if( !(st = build_luts( out, lut )) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Set demand hints.
|
|
||||||
*/
|
|
||||||
if( im_demand_hint( out, IM_THINSTRIP, t, NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Process!
|
|
||||||
*/
|
|
||||||
if( im_generate( out, maplut_start, maplut_gen, maplut_stop, t, st ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
|
@ -74,11 +74,11 @@
|
|||||||
#include "phistogram.h"
|
#include "phistogram.h"
|
||||||
|
|
||||||
typedef struct _VipsMaplut {
|
typedef struct _VipsMaplut {
|
||||||
VipsHistogram parent_instance;
|
VipsOperation parent_instance;
|
||||||
|
|
||||||
/* Process this image (@in is the LUT).
|
VipsImage *in;
|
||||||
*/
|
VipsImage *out;
|
||||||
VipsImage *process;
|
VipsImage *lut;
|
||||||
|
|
||||||
int fmt; /* LUT image BandFmt */
|
int fmt; /* LUT image BandFmt */
|
||||||
int nb; /* Number of bands in lut */
|
int nb; /* Number of bands in lut */
|
||||||
@ -90,9 +90,9 @@ typedef struct _VipsMaplut {
|
|||||||
|
|
||||||
} VipsMaplut;
|
} VipsMaplut;
|
||||||
|
|
||||||
typedef VipsHistogramClass VipsMaplutClass;
|
typedef VipsOperationClass VipsMaplutClass;
|
||||||
|
|
||||||
G_DEFINE_TYPE( VipsMaplut, vips_maplut, VIPS_TYPE_HISTOGRAM );
|
G_DEFINE_TYPE( VipsMaplut, vips_maplut, VIPS_TYPE_OPERATION );
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_maplut_preeval( VipsImage *image, VipsProgress *progress,
|
vips_maplut_preeval( VipsImage *image, VipsProgress *progress,
|
||||||
@ -143,7 +143,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map through n non-complex luts.
|
/* Map through n non-complex luts.
|
||||||
*/
|
*/
|
||||||
#define loop(OUT) { \
|
#define loop( OUT ) { \
|
||||||
int b = st->nb; \
|
int b = st->nb; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -160,7 +160,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map through n complex luts.
|
/* Map through n complex luts.
|
||||||
*/
|
*/
|
||||||
#define loopc(OUT) { \
|
#define loopc( OUT ) { \
|
||||||
int b = in->Bands; \
|
int b = in->Bands; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -180,7 +180,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define loopg(IN,OUT) { \
|
#define loopg( IN, OUT ) { \
|
||||||
int b = st->nb; \
|
int b = st->nb; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -203,7 +203,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define loopcg(IN,OUT) { \
|
#define loopcg( IN, OUT ) { \
|
||||||
int b = in->Bands; \
|
int b = in->Bands; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -231,7 +231,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map image through one non-complex lut.
|
/* Map image through one non-complex lut.
|
||||||
*/
|
*/
|
||||||
#define loop1(OUT) { \
|
#define loop1( OUT ) { \
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
OUT *tlut = (OUT *) st->table[0]; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -245,7 +245,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map image through one complex lut.
|
/* Map image through one complex lut.
|
||||||
*/
|
*/
|
||||||
#define loop1c(OUT) { \
|
#define loop1c( OUT ) { \
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
OUT *tlut = (OUT *) st->table[0]; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -265,7 +265,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
/* As above, but the input image may be any unsigned integer type. We have to
|
/* As above, but the input image may be any unsigned integer type. We have to
|
||||||
* index the lut carefully, and record the number of overflows we detect.
|
* index the lut carefully, and record the number of overflows we detect.
|
||||||
*/
|
*/
|
||||||
#define loop1g(IN,OUT) { \
|
#define loop1g( IN, OUT ) { \
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
OUT *tlut = (OUT *) st->table[0]; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -285,7 +285,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define loop1cg(IN,OUT) { \
|
#define loop1cg( IN, OUT ) { \
|
||||||
OUT *tlut = (OUT *) st->table[0]; \
|
OUT *tlut = (OUT *) st->table[0]; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -309,7 +309,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map 1-band image through a many-band non-complex lut.
|
/* Map 1-band image through a many-band non-complex lut.
|
||||||
*/
|
*/
|
||||||
#define loop1m(OUT) { \
|
#define loop1m( OUT ) { \
|
||||||
OUT **tlut = (OUT **) st->table; \
|
OUT **tlut = (OUT **) st->table; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -327,7 +327,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map 1-band image through many-band complex lut.
|
/* Map 1-band image through many-band complex lut.
|
||||||
*/
|
*/
|
||||||
#define loop1cm(OUT) { \
|
#define loop1cm( OUT ) { \
|
||||||
OUT **tlut = (OUT **) st->table; \
|
OUT **tlut = (OUT **) st->table; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -348,7 +348,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map 1-band uint or ushort image through a many-band non-complex LUT.
|
/* Map 1-band uint or ushort image through a many-band non-complex LUT.
|
||||||
*/
|
*/
|
||||||
#define loop1gm(IN,OUT) { \
|
#define loop1gm( IN, OUT ) { \
|
||||||
OUT **tlut = (OUT **) st->table; \
|
OUT **tlut = (OUT **) st->table; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -371,7 +371,7 @@ vips_maplut_start( VipsImage *out, void *a, void *b )
|
|||||||
|
|
||||||
/* Map 1-band uint or ushort image through a many-band complex LUT.
|
/* Map 1-band uint or ushort image through a many-band complex LUT.
|
||||||
*/
|
*/
|
||||||
#define loop1cgm(IN,OUT) { \
|
#define loop1cgm( IN, OUT ) { \
|
||||||
OUT **tlut = (OUT **) st->table; \
|
OUT **tlut = (OUT **) st->table; \
|
||||||
\
|
\
|
||||||
for( y = to; y < bo; y++ ) { \
|
for( y = to; y < bo; y++ ) { \
|
||||||
@ -446,17 +446,18 @@ vips_maplut_gen( VipsRegion *or, void *vseq, void *a, void *b,
|
|||||||
VipsImage *in = (VipsImage *) a;
|
VipsImage *in = (VipsImage *) a;
|
||||||
VipsMaplut *st = (VipsMaplut *) b;
|
VipsMaplut *st = (VipsMaplut *) b;
|
||||||
VipsRegion *ir = seq->ir;
|
VipsRegion *ir = seq->ir;
|
||||||
Rect *r = &or->valid;
|
VipsRect *r = &or->valid;
|
||||||
int le = r->left;
|
int le = r->left;
|
||||||
int to = r->top;
|
int to = r->top;
|
||||||
int bo = VIPS_RECT_BOTTOM(r);
|
int bo = VIPS_RECT_BOTTOM(r);
|
||||||
int np = r->width; /* Pels across region */
|
int np = r->width; /* Pels across region */
|
||||||
int ne = VIPS_REGION_N_ELEMENTS( or ); /* Number of elements */
|
int ne = VIPS_REGION_N_ELEMENTS( or ); /* Number of elements */
|
||||||
|
|
||||||
int x, y, z, i;
|
int x, y, z, i;
|
||||||
|
|
||||||
/* Get input ready.
|
/* Get input ready.
|
||||||
*/
|
*/
|
||||||
if( im_prepare( ir, r ) )
|
if( vips_region_prepare( ir, r ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Process!
|
/* Process!
|
||||||
@ -512,73 +513,76 @@ static int
|
|||||||
vips_maplut_build( VipsObject *object )
|
vips_maplut_build( VipsObject *object )
|
||||||
{
|
{
|
||||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||||
VipsHistogram *histogram = VIPS_HISTOGRAM( object );
|
|
||||||
VipsMaplut *maplut = (VipsMaplut *) object;
|
VipsMaplut *maplut = (VipsMaplut *) object;
|
||||||
|
VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 );
|
||||||
|
|
||||||
|
VipsImage *in;
|
||||||
|
VipsImage *lut;
|
||||||
int i, x;
|
int i, x;
|
||||||
VipsPel *q;
|
VipsPel *q;
|
||||||
|
|
||||||
|
g_object_set( maplut, "out", vips_image_new(), NULL );
|
||||||
|
|
||||||
if( VIPS_OBJECT_CLASS( vips_maplut_parent_class )->build( object ) )
|
if( VIPS_OBJECT_CLASS( vips_maplut_parent_class )->build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* @in is the LUT.
|
in = maplut->in;
|
||||||
|
lut = maplut->lut;
|
||||||
|
|
||||||
|
if( vips_check_hist( class->nickname, lut ) ||
|
||||||
|
vips_check_uncoded( class->nickname, lut ) ||
|
||||||
|
vips_image_wio_input( lut ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
/* Cast @in to u8/u16/u32 to make the index image.
|
||||||
*/
|
*/
|
||||||
if( vips_check_uncoded( class->nickname, histogram->in ) ||
|
if( vips_cast( in, &t[0], bandfmt_maplut[in->BandFmt], NULL ) )
|
||||||
vips_image_wio_input( histogram->in ) )
|
return( -1 );
|
||||||
|
in = t[0];
|
||||||
|
|
||||||
|
if( vips_check_uncoded( class->nickname, in ) ||
|
||||||
|
vips_check_bands_1orn( class->nickname, in, lut ) ||
|
||||||
|
vips_image_pio_input( in ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Cast @process to u8/u16/u32.
|
if( vips_image_copy_fieldsv( maplut->out, in, lut, NULL ) )
|
||||||
*/
|
|
||||||
if( !(t = im_open_local( out, "im_maplut", "p" )) ||
|
|
||||||
im_clip2fmt( in, t, bandfmt_maplut[in->BandFmt] ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
vips_demand_hint( maplut->out, VIPS_DEMAND_STYLE_THINSTRIP,
|
||||||
if( vips_check_uncoded( class->nickname, maplut->process ) ||
|
in, lut, NULL );
|
||||||
vips_check_bands_1orn( class->nickname,
|
maplut->out->BandFmt = lut->BandFmt;
|
||||||
maplut->process, histogram->in ) ||
|
|
||||||
vips_image_pio_input( maplut->process ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
if( vips_image_copy_fieldsv( histogram->out,
|
|
||||||
maplut->process, histogram->in, NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
vips_demand_hint( histogram->out, VIPS_DEMAND_STYLE_THINSTRIP,
|
|
||||||
maplut->process, histogram->in, NULL );
|
|
||||||
histogram->out->BandFmt = histogram->in->BandFmt;
|
|
||||||
|
|
||||||
/* Output has same number of bands as LUT, unless LUT has 1 band, in
|
/* Output has same number of bands as LUT, unless LUT has 1 band, in
|
||||||
* which case output has same number of bands as input.
|
* which case output has same number of bands as input.
|
||||||
*/
|
*/
|
||||||
if( histogram->in->Bands != 1 )
|
if( lut->Bands != 1 )
|
||||||
histogram->out->Bands = histogram->in->Bands;
|
maplut->out->Bands = lut->Bands;
|
||||||
|
|
||||||
g_signal_connect( maplut->in, "preeval",
|
g_signal_connect( in, "preeval",
|
||||||
G_CALLBACK( vips_maplut_preeval ), maplut );
|
G_CALLBACK( vips_maplut_preeval ), maplut );
|
||||||
g_signal_connect( maplut->in, "posteval",
|
g_signal_connect( in, "posteval",
|
||||||
G_CALLBACK( vips_maplut_posteval ), maplut );
|
G_CALLBACK( vips_maplut_posteval ), maplut );
|
||||||
|
|
||||||
/* Make luts. We unpack the LUT image into a C 2D array to speed
|
/* Make luts. We unpack the LUT image into a 2D C array to speed
|
||||||
* processing.
|
* processing.
|
||||||
*/
|
*/
|
||||||
maplut->fmt = histogram->in->BandFmt;
|
maplut->fmt = lut->BandFmt;
|
||||||
maplut->es = VIPS_IMAGE_SIZEOF_ELEMENT( histogram->in );
|
maplut->es = VIPS_IMAGE_SIZEOF_ELEMENT( lut );
|
||||||
maplut->nb = histogram->in->Bands;
|
maplut->nb = lut->Bands;
|
||||||
maplut->sz = histogram->in->Xsize * histogram->in->Ysize;
|
maplut->sz = lut->Xsize * lut->Ysize;
|
||||||
maplut->clp = maplut->sz - 1;
|
maplut->clp = maplut->sz - 1;
|
||||||
|
|
||||||
/* Attach tables.
|
/* Attach tables.
|
||||||
*/
|
*/
|
||||||
if( !(maplut->table = VIPS_ARRAY( maplut,
|
if( !(maplut->table = VIPS_ARRAY( maplut, lut->Bands, VipsPel * )) )
|
||||||
histogram->in->Bands, VipsPel * )) )
|
return( -1 );
|
||||||
return( NULL );
|
for( i = 0; i < lut->Bands; i++ )
|
||||||
for( i = 0; i < histogram->in->Bands; i++ )
|
|
||||||
if( !(maplut->table[i] = VIPS_ARRAY( maplut,
|
if( !(maplut->table[i] = VIPS_ARRAY( maplut,
|
||||||
maplut->sz * maplut->es, VipsPel )) )
|
maplut->sz * maplut->es, VipsPel )) )
|
||||||
return( NULL );
|
return( -1 );
|
||||||
|
|
||||||
/* Scan LUT and fill table.
|
/* Scan LUT and fill table.
|
||||||
*/
|
*/
|
||||||
q = (VipsPel *) histogram->in->data;
|
q = (VipsPel *) lut->data;
|
||||||
for( x = 0; x < maplut->sz; x++ )
|
for( x = 0; x < maplut->sz; x++ )
|
||||||
for( i = 0; i < maplut->nb; i++ ) {
|
for( i = 0; i < maplut->nb; i++ ) {
|
||||||
memcpy( maplut->table[i] + x * maplut->es, q,
|
memcpy( maplut->table[i] + x * maplut->es, q,
|
||||||
@ -586,23 +590,21 @@ vips_maplut_build( VipsObject *object )
|
|||||||
q += maplut->es;
|
q += maplut->es;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( vips_image_generate( histogram->out,
|
if( vips_image_generate( maplut->out,
|
||||||
vips_maplut_start, vips_maplut_gen, vips_maplut_stop,
|
vips_maplut_start, vips_maplut_gen, vips_maplut_stop,
|
||||||
maplut->process, maplut ) )
|
in, maplut ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_maplut_class_init( VipsCastClass *class )
|
vips_maplut_class_init( VipsMaplutClass *class )
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||||
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||||
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
|
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
|
||||||
|
|
||||||
VIPS_DEBUG_MSG( "vips_maplut_class_init\n" );
|
|
||||||
|
|
||||||
gobject_class->set_property = vips_object_set_property;
|
gobject_class->set_property = vips_object_set_property;
|
||||||
gobject_class->get_property = vips_object_get_property;
|
gobject_class->get_property = vips_object_get_property;
|
||||||
|
|
||||||
@ -612,27 +614,40 @@ vips_maplut_class_init( VipsCastClass *class )
|
|||||||
|
|
||||||
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
|
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
|
||||||
|
|
||||||
VIPS_ARG_IMAGE( class, "process", 2,
|
VIPS_ARG_IMAGE( class, "in", 0,
|
||||||
_( "Process" ),
|
_( "Input" ),
|
||||||
_( "Image to pass through LUT" ),
|
_( "Input image" ),
|
||||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsMaplut, process ) );
|
G_STRUCT_OFFSET( VipsHistogram, in ) );
|
||||||
|
|
||||||
|
VIPS_ARG_IMAGE( class, "out", 1,
|
||||||
|
_( "Output" ),
|
||||||
|
_( "Output image" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsHistogram, out ) );
|
||||||
|
|
||||||
|
VIPS_ARG_IMAGE( class, "lut", 2,
|
||||||
|
_( "LUT" ),
|
||||||
|
_( "Look-up table image" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsMaplut, lut ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vips_maplut_init( VipsCast *maplut )
|
vips_maplut_init( VipsMaplut *maplut )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* im_maplut:
|
* vips_maplut:
|
||||||
* @in: input image
|
* @in: input image
|
||||||
* @out: output image
|
* @out: output image
|
||||||
* @lut: look-up table
|
* @lut: look-up table
|
||||||
|
* @...: %NULL-terminated list of optional named arguments
|
||||||
*
|
*
|
||||||
* Map an image through another image acting as a LUT (Look Up Table).
|
* Map an image through another image acting as a LUT (Look Up Table).
|
||||||
* The lut may have any type, and the output image will be that type.
|
* The lut may have any type and the output image will be that type.
|
||||||
*
|
*
|
||||||
* The input image will be cast to one of the unsigned integer types, that is,
|
* The input image will be cast to one of the unsigned integer types, that is,
|
||||||
* VIPS_FORMAT_UCHAR, VIPS_FORMAT_USHORT or VIPS_FORMAT_UINT.
|
* VIPS_FORMAT_UCHAR, VIPS_FORMAT_USHORT or VIPS_FORMAT_UINT.
|
||||||
@ -648,61 +663,20 @@ vips_maplut_init( VipsCast *maplut )
|
|||||||
* separately. If @in has one band, then @lut may have many bands and
|
* separately. If @in has one band, then @lut may have many bands and
|
||||||
* the output will have the same number of bands as @lut.
|
* the output will have the same number of bands as @lut.
|
||||||
*
|
*
|
||||||
* See also: im_histgr(), im_identity().
|
* See also: im_histgr(), vips_identity().
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -1 on error
|
* Returns: 0 on success, -1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
im_maplut( VipsImage *in, VipsImage *out, VipsImage *lut )
|
vips_maplut( VipsImage *in, VipsImage **out, VipsImage *lut, ... )
|
||||||
{
|
{
|
||||||
VipsImage *t;
|
va_list ap;
|
||||||
VipsMaplut *st;
|
int result;
|
||||||
|
|
||||||
/* Check input output. Old-style IO from lut, for simplicity.
|
va_start( ap, lut );
|
||||||
*/
|
result = vips_call_split( "maplut", ap, in, out, lut );
|
||||||
if( im_check_hist( "im_maplut", lut ) ||
|
va_end( ap );
|
||||||
im_check_uncoded( "im_maplut", lut ) ||
|
|
||||||
im_check_uncoded( "im_maplut", in ) ||
|
|
||||||
im_check_bands_1orn( "im_maplut", in, lut ) ||
|
|
||||||
im_piocheck( in, out ) ||
|
|
||||||
im_incheck( lut ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Cast in to u8/u16/u32.
|
return( result );
|
||||||
*/
|
|
||||||
if( !(t = im_open_local( out, "im_maplut", "p" )) ||
|
|
||||||
im_clip2fmt( in, t, bandfmt_maplut[in->BandFmt] ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Prepare the output header.
|
|
||||||
*/
|
|
||||||
if( im_cp_descv( out, t, lut, NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Force output to be the same type as lut.
|
|
||||||
*/
|
|
||||||
out->BandFmt = lut->BandFmt;
|
|
||||||
|
|
||||||
/* Output has same number of bands as LUT, unless LUT has 1 band, in
|
|
||||||
* which case output has same number of bands as input.
|
|
||||||
*/
|
|
||||||
if( lut->Bands != 1 )
|
|
||||||
out->Bands = lut->Bands;
|
|
||||||
|
|
||||||
/* Make tables.
|
|
||||||
*/
|
|
||||||
if( !(st = build_luts( out, lut )) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Set demand hints.
|
|
||||||
*/
|
|
||||||
if( im_demand_hint( out, VIPS_THINSTRIP, t, NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Process!
|
|
||||||
*/
|
|
||||||
if( im_generate( out, maplut_start, maplut_gen, maplut_stop, t, st ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /*__cplusplus*/
|
#endif /*__cplusplus*/
|
||||||
|
|
||||||
|
int vips_maplut( VipsImage *in, VipsImage **out, VipsImage *lut, ... )
|
||||||
|
__attribute__((sentinel));
|
||||||
|
|
||||||
int im_histgr( VipsImage *in, VipsImage *out, int bandno );
|
int im_histgr( VipsImage *in, VipsImage *out, int bandno );
|
||||||
int im_histnD( VipsImage *in, VipsImage *out, int bins );
|
int im_histnD( VipsImage *in, VipsImage *out, int bins );
|
||||||
int im_hist_indexed( VipsImage *index, VipsImage *value, VipsImage *out );
|
int im_hist_indexed( VipsImage *index, VipsImage *value, VipsImage *out );
|
||||||
@ -52,8 +55,6 @@ int im_histspec( VipsImage *in, VipsImage *ref, VipsImage *out );
|
|||||||
int im_ismonotonic( VipsImage *lut, int *out );
|
int im_ismonotonic( VipsImage *lut, int *out );
|
||||||
int im_histplot( VipsImage *in, VipsImage *out );
|
int im_histplot( VipsImage *in, VipsImage *out );
|
||||||
|
|
||||||
int im_maplut( VipsImage *in, VipsImage *out, VipsImage *lut );
|
|
||||||
|
|
||||||
int im_hist( VipsImage *in, VipsImage *out, int bandno );
|
int im_hist( VipsImage *in, VipsImage *out, int bandno );
|
||||||
int im_hsp( VipsImage *in, VipsImage *ref, VipsImage *out );
|
int im_hsp( VipsImage *in, VipsImage *ref, VipsImage *out );
|
||||||
int im_gammacorrect( VipsImage *in, VipsImage *out, double exponent );
|
int im_gammacorrect( VipsImage *in, VipsImage *out, double exponent );
|
||||||
|
@ -280,6 +280,7 @@ void vips_conversion_operation_init( void );
|
|||||||
void vips_resample_operation_init( void );
|
void vips_resample_operation_init( void );
|
||||||
void vips_foreign_operation_init( void );
|
void vips_foreign_operation_init( void );
|
||||||
void vips_colour_operation_init( void );
|
void vips_colour_operation_init( void );
|
||||||
|
void vips_histogram_operation_init( void );
|
||||||
|
|
||||||
guint64 vips__parse_size( const char *size_string );
|
guint64 vips__parse_size( const char *size_string );
|
||||||
|
|
||||||
|
@ -846,6 +846,8 @@ int im_lab_morph( VipsImage *in, VipsImage *out,
|
|||||||
|
|
||||||
int im_quadratic( IMAGE *in, IMAGE *out, IMAGE *coeff );
|
int im_quadratic( IMAGE *in, IMAGE *out, IMAGE *coeff );
|
||||||
|
|
||||||
|
int im_maplut( VipsImage *in, VipsImage *out, VipsImage *lut );
|
||||||
|
|
||||||
/* ruby-vips uses this
|
/* ruby-vips uses this
|
||||||
*/
|
*/
|
||||||
#define vips_class_map_concrete_all vips_class_map_all
|
#define vips_class_map_concrete_all vips_class_map_all
|
||||||
|
@ -249,6 +249,7 @@ vips_init( const char *argv0 )
|
|||||||
vips_foreign_operation_init();
|
vips_foreign_operation_init();
|
||||||
vips_resample_operation_init();
|
vips_resample_operation_init();
|
||||||
vips_colour_operation_init();
|
vips_colour_operation_init();
|
||||||
|
vips_histogram_operation_init();
|
||||||
|
|
||||||
/* Load up any plugins in the vips libdir. We don't error on failure,
|
/* Load up any plugins in the vips libdir. We don't error on failure,
|
||||||
* it's too annoying to have VIPS refuse to start because of a broken
|
* it's too annoying to have VIPS refuse to start because of a broken
|
||||||
|
Loading…
Reference in New Issue
Block a user