redo im_tone_build*() as classes
start vips_hist_percent() as well
This commit is contained in:
parent
04701ad7d5
commit
d029461bc0
@ -5,7 +5,7 @@
|
||||
- rewrite im_buildlut(), im_identity*(), im_maplut(), im_falsecolour(),
|
||||
im_gammacorrect(), im_histgr(), im_histcum(), im_histnorm(), im_heq(),
|
||||
im_histnD(), im_histindexed(), im_histspec(), im_invertlut(), im_lhisteq(),
|
||||
im_stdif(), im_project() as classes
|
||||
im_stdif(), im_project(), im_tone_build*() as classes
|
||||
- vips_hist_local(), vips_stdif() do any number of bands
|
||||
- thin vips8 wrapper for im_histplot()
|
||||
- added vips_error_freeze() / vips_error_thaw()
|
||||
|
2
TODO
2
TODO
@ -1,3 +1,5 @@
|
||||
- need to do im_profile() before we can finish hist_percent()
|
||||
|
||||
- try:
|
||||
|
||||
$ vips extract_band 50310.svs x.tif[pyramid,tile,compression=jpeg,tile-width=256,tile-height=256] 0 --n 3
|
||||
|
@ -5,6 +5,7 @@ libcreate_la_SOURCES = \
|
||||
pcreate.h \
|
||||
buildlut.c \
|
||||
invertlut.c \
|
||||
tonelut.c \
|
||||
identity.c \
|
||||
point.c \
|
||||
point.h \
|
||||
|
@ -122,6 +122,7 @@ vips_create_operation_init( void )
|
||||
extern GType vips_sines_get_type( void );
|
||||
extern GType vips_buildlut_get_type( void );
|
||||
extern GType vips_invertlut_get_type( void );
|
||||
extern GType vips_tonelut_get_type( void );
|
||||
extern GType vips_identity_get_type( void );
|
||||
|
||||
vips_black_get_type();
|
||||
@ -136,6 +137,7 @@ vips_create_operation_init( void )
|
||||
vips_sines_get_type();
|
||||
vips_buildlut_get_type();
|
||||
vips_invertlut_get_type();
|
||||
vips_tonelut_get_type();
|
||||
vips_identity_get_type();
|
||||
}
|
||||
|
||||
|
356
libvips/create/tonelut.c
Normal file
356
libvips/create/tonelut.c
Normal file
@ -0,0 +1,356 @@
|
||||
/* Build a tone curve.
|
||||
*
|
||||
* Author: John Cupitt
|
||||
* Written on: 18/7/1995
|
||||
* 17/9/96 JC
|
||||
* - restrictions on Ps, Pm, Ph relaxed
|
||||
* - restrictions on S, M, H relaxed
|
||||
* 25/7/01 JC
|
||||
* - patched for im_extract_band() change
|
||||
* 11/7/04
|
||||
* - generalised to im_tone_build_range() ... so you can use it for any
|
||||
* image, not just LabS
|
||||
* 26/3/10
|
||||
* - cleanups
|
||||
* - gtkdoc
|
||||
* 20/9/13
|
||||
* - redo as a class
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 <math.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#include "pcreate.h"
|
||||
|
||||
typedef struct _VipsTonelut {
|
||||
VipsCreate parent_instance;
|
||||
|
||||
/* Parameters for tone curve formation.
|
||||
*/
|
||||
double Lb, Lw;
|
||||
double Ps, Pm, Ph;
|
||||
double S, M, H;
|
||||
|
||||
/* Range we process.
|
||||
*/
|
||||
int in_max;
|
||||
int out_max;
|
||||
|
||||
/* Derived values.
|
||||
*/
|
||||
double Ls, Lm, Lh;
|
||||
} VipsTonelut;
|
||||
|
||||
typedef VipsCreateClass VipsTonelutClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsTonelut, vips_tonelut, VIPS_TYPE_CREATE );
|
||||
|
||||
/* Calculate shadow curve.
|
||||
*/
|
||||
static double
|
||||
shad( VipsTonelut *lut, double x )
|
||||
{
|
||||
double x1 = (x - lut->Lb) / (lut->Ls - lut->Lb);
|
||||
double x2 = (x - lut->Ls) / (lut->Lm - lut->Ls);
|
||||
|
||||
double out;
|
||||
|
||||
if( x < lut->Lb )
|
||||
out = 0;
|
||||
else if( x < lut->Ls )
|
||||
out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1;
|
||||
else if( x < lut->Lm )
|
||||
out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2;
|
||||
else
|
||||
out = 0;
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/* Calculate mid-tone curve.
|
||||
*/
|
||||
static double
|
||||
mid( VipsTonelut *lut, double x )
|
||||
{
|
||||
double x1 = (x - lut->Ls) / (lut->Lm - lut->Ls);
|
||||
double x2 = (x - lut->Lm) / (lut->Lh - lut->Lm);
|
||||
|
||||
double out;
|
||||
|
||||
if( x < lut->Ls )
|
||||
out = 0;
|
||||
else if( x < lut->Lm )
|
||||
out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1;
|
||||
else if( x < lut->Lh )
|
||||
out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2;
|
||||
else
|
||||
out = 0;
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/* Calculate highlight curve.
|
||||
*/
|
||||
static double
|
||||
high( VipsTonelut *lut, double x )
|
||||
{
|
||||
double x1 = (x - lut->Lm) / (lut->Lh - lut->Lm);
|
||||
double x2 = (x - lut->Lh) / (lut->Lw - lut->Lh);
|
||||
|
||||
double out;
|
||||
|
||||
if( x < lut->Lm )
|
||||
out = 0;
|
||||
else if( x < lut->Lh )
|
||||
out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1;
|
||||
else if( x < lut->Lw )
|
||||
out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2;
|
||||
else
|
||||
out = 0;
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/* Generate a point on the tone curve. Everything is 0-100.
|
||||
*/
|
||||
static double
|
||||
tone_curve( VipsTonelut *lut, double x )
|
||||
{
|
||||
double out;
|
||||
|
||||
out = x +
|
||||
lut->S * shad( lut, x ) +
|
||||
lut->M * mid( lut, x ) +
|
||||
lut->H * high( lut, x );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_tonelut_build( VipsObject *object )
|
||||
{
|
||||
VipsCreate *create = VIPS_CREATE( object );
|
||||
VipsTonelut *lut = (VipsTonelut *) object;
|
||||
|
||||
int i;
|
||||
unsigned short buf[65536];
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_tonelut_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
g_assert( lut->in_max > 0 && lut->in_max < 65536 );
|
||||
g_assert( lut->out_max > 0 && lut->out_max < 65536 );
|
||||
|
||||
/* Note derived params.
|
||||
*/
|
||||
lut->Ls = lut->Lb + lut->Ps * (lut->Lw - lut->Lb);
|
||||
lut->Lm = lut->Lb + lut->Pm * (lut->Lw - lut->Lb);
|
||||
lut->Lh = lut->Lb + lut->Ph * (lut->Lw - lut->Lb);
|
||||
|
||||
/* Generate curve.
|
||||
*/
|
||||
for( i = 0; i <= lut->in_max; i++ ) {
|
||||
int v = (lut->out_max / 100.0) *
|
||||
tone_curve( lut, 100.0 * i / lut->in_max );
|
||||
|
||||
if( v < 0 )
|
||||
v = 0;
|
||||
else if( v > lut->out_max )
|
||||
v = lut->out_max;
|
||||
|
||||
buf[i] = v;
|
||||
}
|
||||
|
||||
/* Make the output image.
|
||||
*/
|
||||
vips_image_init_fields( create->out,
|
||||
lut->in_max + 1, 1, 1,
|
||||
VIPS_FORMAT_USHORT, VIPS_CODING_NONE,
|
||||
VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0 );
|
||||
if( vips_image_write_line( create->out, 0, (VipsPel *) buf ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_tonelut_class_init( VipsTonelutClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
vobject_class->nickname = "tonelut";
|
||||
vobject_class->description = _( "build a look-up table" );
|
||||
vobject_class->build = vips_tonelut_build;
|
||||
|
||||
VIPS_ARG_INT( class, "in_max", 4,
|
||||
_( "In-max" ),
|
||||
_( "Size of LUT to build" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, in_max ),
|
||||
1, 65535, 32767 );
|
||||
|
||||
VIPS_ARG_INT( class, "out_max", 5,
|
||||
_( "Out-max" ),
|
||||
_( "Maximum value in output LUT" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, out_max ),
|
||||
1, 65535, 32767 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "Lb", 6,
|
||||
_( "Black point" ),
|
||||
_( "Lowest value in output" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, Lb ),
|
||||
0, 100, 0 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "Lw", 7,
|
||||
_( "White point" ),
|
||||
_( "Highest value in output" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, Lw ),
|
||||
0, 100, 100 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "Ps", 8,
|
||||
_( "Shadow point" ),
|
||||
_( "Position of shadow" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, Ps ),
|
||||
0, 1, 0.2 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "Pm", 9,
|
||||
_( "Mid-tone point" ),
|
||||
_( "Position of mid-tones" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, Pm ),
|
||||
0, 1, 0.5 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "Ph", 10,
|
||||
_( "Highlight point" ),
|
||||
_( "Position of highlights" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, Ph ),
|
||||
0, 1, 0.8 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "S", 11,
|
||||
_( "Shadow adjust" ),
|
||||
_( "Adjust shadows by this much" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, S ),
|
||||
-30, 30, 0 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "M", 12,
|
||||
_( "Mid-tone adjust" ),
|
||||
_( "Adjust mid-tones by this much" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, M ),
|
||||
-30, 30, 0 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "H", 13,
|
||||
_( "Highlight adjust" ),
|
||||
_( "Adjust highlights by this much" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsTonelut, H ),
|
||||
-30, 30, 0 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_tonelut_init( VipsTonelut *lut )
|
||||
{
|
||||
lut->in_max = 32767;
|
||||
lut->out_max = 32767;
|
||||
lut->Lb = 0.0;
|
||||
lut->Lw = 100.0;
|
||||
lut->Ps = 0.2;
|
||||
lut->Pm = 0.5;
|
||||
lut->Ph = 0.8;
|
||||
lut->S = 0.0;
|
||||
lut->M = 0.0;
|
||||
lut->H = 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_tonelut:
|
||||
* @out: output image
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* @in_max: input range
|
||||
* @out_max: output range
|
||||
* @Lb: black-point [0-100]
|
||||
* @Lw: white-point [0-100]
|
||||
* @Ps: shadow point (eg. 0.2)
|
||||
* @Pm: mid-tone point (eg. 0.5)
|
||||
* @Ph: highlight point (eg. 0.8)
|
||||
* @S: shadow adjustment (+/- 30)
|
||||
* @M: mid-tone adjustment (+/- 30)
|
||||
* @H: highlight adjustment (+/- 30)
|
||||
*
|
||||
* vips_tonelut() generates a tone curve for the adjustment of image
|
||||
* levels. It is mostly designed for adjusting the L* part of a LAB image in
|
||||
* way suitable for print work, but you can use it for other things too.
|
||||
*
|
||||
* The curve is an unsigned 16-bit image with (@in_max + 1) entries,
|
||||
* each in the range [0, @out_max].
|
||||
*
|
||||
* @Lb, @Lw are expressed as 0-100, as in LAB colour space. You
|
||||
* specify the scaling for the input and output images with the @in_max and
|
||||
* @out_max parameters.
|
||||
*
|
||||
* See also: vips_tone_map(), vips_tone_analyse().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_tonelut( VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "tonelut", ap, out );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
@ -2575,6 +2575,54 @@ im_invertlut( DOUBLEMASK *input, VipsImage *out, int size )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_tone_build_range( IMAGE *out,
|
||||
int in_max, int out_max,
|
||||
double Lb, double Lw,
|
||||
double Ps, double Pm, double Ph,
|
||||
double S, double M, double H )
|
||||
{
|
||||
VipsImage *t;
|
||||
|
||||
if( vips_tonelut( &t,
|
||||
"in_max", in_max,
|
||||
"out_max", out_max,
|
||||
"Lb", Lb,
|
||||
"Lw", Lw,
|
||||
"Ps", Ps,
|
||||
"Pm", Pm,
|
||||
"Ph", Ph,
|
||||
"S", S,
|
||||
"M", M,
|
||||
"H", H,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_tone_build( IMAGE *out,
|
||||
double Lb, double Lw,
|
||||
double Ps, double Pm, double Ph,
|
||||
double S, double M, double H )
|
||||
{
|
||||
IMAGE *t1;
|
||||
|
||||
if( !(t1 = im_open_local( out, "im_tone_build", "p" )) ||
|
||||
im_tone_build_range( t1, 32767, 32767,
|
||||
Lb, Lw, Ps, Pm, Ph, S, M, H ) ||
|
||||
im_clip2fmt( t1, out, IM_BANDFMT_SHORT ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_rightshift_size( IMAGE *in, IMAGE *out,
|
||||
int xshift, int yshift, int band_fmt )
|
||||
|
@ -66,8 +66,6 @@ vips_foreign_load_webp_get_flags( VipsForeignLoad *load )
|
||||
static int
|
||||
vips_foreign_load_webp_build( VipsObject *object )
|
||||
{
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) object;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_foreign_load_webp_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
@ -127,7 +125,6 @@ vips_foreign_load_webp_file_is_a( const char *filename )
|
||||
static int
|
||||
vips_foreign_load_webp_file_header( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
|
||||
VipsForeignLoadWebpFile *file = (VipsForeignLoadWebpFile *) load;
|
||||
|
||||
if( vips__webp_read_file_header( file->filename, load->out ) )
|
||||
@ -139,7 +136,6 @@ vips_foreign_load_webp_file_header( VipsForeignLoad *load )
|
||||
static int
|
||||
vips_foreign_load_webp_file_load( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
|
||||
VipsForeignLoadWebpFile *file = (VipsForeignLoadWebpFile *) load;
|
||||
|
||||
if( vips__webp_read_file( file->filename, load->real ) )
|
||||
@ -202,7 +198,6 @@ G_DEFINE_TYPE( VipsForeignLoadWebpBuffer, vips_foreign_load_webp_buffer,
|
||||
static int
|
||||
vips_foreign_load_webp_buffer_header( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
|
||||
VipsForeignLoadWebpBuffer *buffer = (VipsForeignLoadWebpBuffer *) load;
|
||||
|
||||
if( vips__webp_read_buffer_header( buffer->buf->data,
|
||||
@ -215,7 +210,6 @@ vips_foreign_load_webp_buffer_header( VipsForeignLoad *load )
|
||||
static int
|
||||
vips_foreign_load_webp_buffer_load( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load;
|
||||
VipsForeignLoadWebpBuffer *buffer = (VipsForeignLoadWebpBuffer *) load;
|
||||
|
||||
if( vips__webp_read_buffer( buffer->buf->data, buffer->buf->length,
|
||||
|
@ -159,6 +159,7 @@ vips_hist_cum_init( VipsHistCum *hist_cum )
|
||||
* vips_hist_cum:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Form cumulative histogram.
|
||||
*
|
||||
|
@ -134,6 +134,7 @@ vips_hist_equal_init( VipsHistEqual *equal )
|
||||
* vips_hist_equal:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
|
@ -159,7 +159,8 @@ vips_hist_norm_init( VipsHistNorm *hist_norm )
|
||||
* vips_hist_norm:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
*
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Normalise histogram ... normalise range to make it square (ie. max ==
|
||||
* number of elements). Normalise each band separately.
|
||||
*
|
||||
|
166
libvips/histogram/hist_percent.c
Normal file
166
libvips/histogram/hist_percent.c
Normal file
@ -0,0 +1,166 @@
|
||||
/* find percent of pixels
|
||||
*
|
||||
* Copyright: 1990, N. Dessipris
|
||||
*
|
||||
* Author: N. Dessipris
|
||||
* Written on: 02/08/1990
|
||||
* Modified on : 29/4/93 K.Martinez for Sys5
|
||||
* 20/2/95 JC
|
||||
* - now returns result through parameter
|
||||
* - ANSIfied a little
|
||||
* 19/1/07
|
||||
* - redone with the vips hist operators
|
||||
* 25/3/10
|
||||
* - gtkdoc
|
||||
* 20/9/13
|
||||
* - wrap as a class
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
typedef struct _VipsHistPercent {
|
||||
VipsOperation parent_instance;
|
||||
|
||||
VipsImage *in;
|
||||
double percent;
|
||||
int threshold;
|
||||
|
||||
} VipsHistPercent;
|
||||
|
||||
typedef VipsOperationClass VipsHistPercentClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsHistPercent, vips_hist_percent, VIPS_TYPE_OPERATION );
|
||||
|
||||
static int
|
||||
vips_hist_percent_build( VipsObject *object )
|
||||
{
|
||||
VipsHistPercent *percent = (VipsHistPercent *) object;
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 6 );
|
||||
|
||||
double threshold;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_hist_percent_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_hist_find( percent->in, &t[0], NULL ) ||
|
||||
vips_hist_cum( t[0], &t[1], NULL ) ||
|
||||
vips_hist_norm( t[1], &t[2], NULL ) ||
|
||||
vips_less_const1( t[2], &t[3],
|
||||
percent->percent * t[2]->Xsize, NULL ) ||
|
||||
vips_flip( t[3], &t[4], VIPS_DIRECTION_HORIZONTAL, NULL ) ||
|
||||
im_profile( t[4], &t[5], 1 ) ||
|
||||
vips_avg( t[5], &threshold ) )
|
||||
return( -1 );
|
||||
|
||||
percent->threshold = threshold;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_hist_percent_class_init( VipsHistPercentClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "hist_percent";
|
||||
object_class->description = _( "find threshold for percent of pixels" );
|
||||
object_class->build = vips_hist_percent_build;
|
||||
|
||||
VIPS_ARG_IMAGE( class, "in", 1,
|
||||
_( "Input" ),
|
||||
_( "Input image" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsHistPercent, in ) );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "percent", 2,
|
||||
_( "Percent" ),
|
||||
_( "percent of pixels" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsHistPercent, percent ),
|
||||
0, 100, 50 );
|
||||
|
||||
VIPS_ARG_INT( class, "threshold", 2,
|
||||
_( "threshold" ),
|
||||
_( "threshold above which lie percent of pixels" ),
|
||||
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsHistPercent, threshold ),
|
||||
0, 65535, 0 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_hist_percent_init( VipsHistPercent *percent )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_percent:
|
||||
* @in: input image
|
||||
* @percent: threshold percentage
|
||||
* @threshold: output threshold value
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* vips_percent() returns (through the @threshold parameter) the threshold
|
||||
* above which there are @percent values of @in. If for example percent=.1, the
|
||||
* number of pels of the input image with values greater than @threshold
|
||||
* will correspond to 10% of all pels of the image.
|
||||
*
|
||||
* The function works for uchar and ushort images only. It can be used
|
||||
* to threshold the scaled result of a filtering operation.
|
||||
*
|
||||
* See also: vips_hist_find(), vips_profile().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_hist_percent( VipsImage *in, double percent, int *threshold, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, threshold );
|
||||
result = vips_call_split( "hist_percent", ap, in, percent, threshold );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
@ -360,6 +360,7 @@ vips_hist_plot_init( VipsHistPlot *hist_plot )
|
||||
* vips_hist_plot:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Plot a 1 by any or any by 1 image file as a max by any or
|
||||
* any by max image using these rules:
|
||||
|
@ -361,6 +361,7 @@ vips_stdif_init( VipsStdif *stdif )
|
||||
* @out: output image
|
||||
* @width: width of region
|
||||
* @height: height of region
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
|
@ -53,266 +53,6 @@
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
/* Parameters for tone curve formation.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Parameters.
|
||||
*/
|
||||
double Lb, Lw;
|
||||
double Ps, Pm, Ph;
|
||||
double S, M, H;
|
||||
|
||||
/* Derived values.
|
||||
*/
|
||||
double Ls, Lm, Lh;
|
||||
} ToneShape;
|
||||
|
||||
/* Calculate shadow curve.
|
||||
*/
|
||||
static double
|
||||
shad( ToneShape *ts, double x )
|
||||
{
|
||||
double x1 = (x - ts->Lb) / (ts->Ls - ts->Lb);
|
||||
double x2 = (x - ts->Ls) / (ts->Lm - ts->Ls);
|
||||
double out;
|
||||
|
||||
if( x < ts->Lb )
|
||||
out = 0;
|
||||
else if( x < ts->Ls )
|
||||
out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1;
|
||||
else if( x < ts->Lm )
|
||||
out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2;
|
||||
else
|
||||
out = 0;
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/* Calculate mid-tone curve.
|
||||
*/
|
||||
static double
|
||||
mid( ToneShape *ts, double x )
|
||||
{
|
||||
double x1 = (x - ts->Ls) / (ts->Lm - ts->Ls);
|
||||
double x2 = (x - ts->Lm) / (ts->Lh - ts->Lm);
|
||||
double out;
|
||||
|
||||
if( x < ts->Ls )
|
||||
out = 0;
|
||||
else if( x < ts->Lm )
|
||||
out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1;
|
||||
else if( x < ts->Lh )
|
||||
out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2;
|
||||
else
|
||||
out = 0;
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/* Calculate highlight curve.
|
||||
*/
|
||||
static double
|
||||
high( ToneShape *ts, double x )
|
||||
{
|
||||
double x1 = (x - ts->Lm) / (ts->Lh - ts->Lm);
|
||||
double x2 = (x - ts->Lh) / (ts->Lw - ts->Lh);
|
||||
double out;
|
||||
|
||||
if( x < ts->Lm )
|
||||
out = 0;
|
||||
else if( x < ts->Lh )
|
||||
out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1;
|
||||
else if( x < ts->Lw )
|
||||
out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2;
|
||||
else
|
||||
out = 0;
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/* Generate a point on the tone curve. Everything is 0-100.
|
||||
*/
|
||||
static double
|
||||
tone_curve( ToneShape *ts, double x )
|
||||
{
|
||||
double out;
|
||||
|
||||
out = x +
|
||||
ts->S * shad( ts, x ) + ts->M * mid( ts, x ) +
|
||||
ts->H * high( ts, x );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_tone_build_range:
|
||||
* @out: output image
|
||||
* @in_max: input range
|
||||
* @out_max: output range
|
||||
* @Lb: black-point [0-100]
|
||||
* @Lw: white-point [0-100]
|
||||
* @Ps: shadow point (eg. 0.2)
|
||||
* @Pm: mid-tone point (eg. 0.5)
|
||||
* @Ph: highlight point (eg. 0.8)
|
||||
* @S: shadow adjustment (+/- 30)
|
||||
* @M: mid-tone adjustment (+/- 30)
|
||||
* @H: highlight adjustment (+/- 30)
|
||||
*
|
||||
* im_tone_build_range() generates a tone curve for the adjustment of image
|
||||
* levels. It is mostly designed for adjusting the L* part of a LAB image in
|
||||
* way suitable for print work, but you can use it for other things too.
|
||||
*
|
||||
* The curve is an unsigned 16-bit image with (@in_max + 1) entries,
|
||||
* each in the range [0, @out_max].
|
||||
*
|
||||
* @Lb, @Lw are expressed as 0-100, as in LAB colour space. You
|
||||
* specify the scaling for the input and output images with the @in_max and
|
||||
* @out_max parameters.
|
||||
*
|
||||
* See also: im_ismonotonic(), im_tone_map(), im_tone_analyse().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_tone_build_range( IMAGE *out,
|
||||
int in_max, int out_max,
|
||||
double Lb, double Lw,
|
||||
double Ps, double Pm, double Ph,
|
||||
double S, double M, double H )
|
||||
{
|
||||
ToneShape *ts;
|
||||
unsigned short lut[65536];
|
||||
int i;
|
||||
|
||||
/* Check args.
|
||||
*/
|
||||
if( !(ts = IM_NEW( out, ToneShape )) ||
|
||||
im_outcheck( out ) )
|
||||
return( -1 );
|
||||
if( in_max < 0 || in_max > 65535 ||
|
||||
out_max < 0 || out_max > 65535 ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "bad in_max, out_max parameters" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( Lb < 0 || Lb > 100 || Lw < 0 || Lw > 100 || Lb > Lw ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "bad Lb, Lw parameters" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( Ps < 0.0 || Ps > 1.0 ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "Ps not in range [0.0,1.0]" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( Pm < 0.0 || Pm > 1.0 ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "Pm not in range [0.0,1.0]" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( Ph < 0.0 || Ph > 1.0 ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "Ph not in range [0.0,1.0]" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( S < -30 || S > 30 ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "S not in range [-30,+30]" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( M < -30 || M > 30 ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "M not in range [-30,+30]" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( H < -30 || H > 30 ) {
|
||||
im_error( "im_tone_build",
|
||||
"%s", _( "H not in range [-30,+30]" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Note params.
|
||||
*/
|
||||
ts->Lb = Lb;
|
||||
ts->Lw = Lw;
|
||||
ts->Ps = Ps;
|
||||
ts->Pm = Pm;
|
||||
ts->Ph = Ph;
|
||||
ts->S = S;
|
||||
ts->M = M;
|
||||
ts->H = H;
|
||||
|
||||
/* Note derived params.
|
||||
*/
|
||||
ts->Ls = Lb + Ps * (Lw - Lb);
|
||||
ts->Lm = Lb + Pm * (Lw - Lb);
|
||||
ts->Lh = Lb + Ph * (Lw - Lb);
|
||||
|
||||
/* Generate curve.
|
||||
*/
|
||||
for( i = 0; i <= in_max; i++ ) {
|
||||
int v = (out_max / 100.0) *
|
||||
tone_curve( ts, 100.0 * i / in_max );
|
||||
|
||||
if( v < 0 )
|
||||
v = 0;
|
||||
else if( v > out_max )
|
||||
v = out_max;
|
||||
|
||||
lut[i] = v;
|
||||
}
|
||||
|
||||
/* Make the output image.
|
||||
*/
|
||||
im_initdesc( out,
|
||||
in_max + 1, 1, 1, IM_BBITS_SHORT, IM_BANDFMT_USHORT,
|
||||
IM_CODING_NONE, IM_TYPE_HISTOGRAM, 1.0, 1.0, 0, 0 );
|
||||
if( im_setupout( out ) )
|
||||
return( -1 );
|
||||
|
||||
if( im_writeline( 0, out, (VipsPel *) lut ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_tone_build:
|
||||
* @out: output image
|
||||
* @Lb: black-point [0-100]
|
||||
* @Lw: white-point [0-100]
|
||||
* @Ps: shadow point (eg. 0.2)
|
||||
* @Pm: mid-tone point (eg. 0.5)
|
||||
* @Ph: highlight point (eg. 0.8)
|
||||
* @S: shadow adjustment (+/- 30)
|
||||
* @M: mid-tone adjustment (+/- 30)
|
||||
* @H: highlight adjustment (+/- 30)
|
||||
*
|
||||
* As im_tone_build_range(), but set 32767 and 32767 as values for @in_max
|
||||
* and @out_max. This makes a curve suitable for correcting LABS
|
||||
* images, the most common case.
|
||||
*
|
||||
* See also: im_tone_build_range().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_tone_build( IMAGE *out,
|
||||
double Lb, double Lw,
|
||||
double Ps, double Pm, double Ph,
|
||||
double S, double M, double H )
|
||||
{
|
||||
IMAGE *t1;
|
||||
|
||||
if( !(t1 = im_open_local( out, "im_tone_build", "p" )) ||
|
||||
im_tone_build_range( t1, 32767, 32767,
|
||||
Lb, Lw, Ps, Pm, Ph, S, M, H ) ||
|
||||
im_clip2fmt( t1, out, IM_BANDFMT_SHORT ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_ismonotonic:
|
||||
* @lut: lookup-table to test
|
||||
|
@ -66,6 +66,8 @@ int vips_buildlut( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_invertlut( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_tonelut( VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
int im_benchmarkn( VipsImage *in, VipsImage *out, int n );
|
||||
int im_benchmark2( VipsImage *in, double *out );
|
||||
|
@ -61,13 +61,6 @@ int im_ismonotonic( VipsImage *lut, int *out );
|
||||
int im_mpercent( VipsImage *in, double percent, int *out );
|
||||
int im_mpercent_hist( VipsImage *hist, double percent, int *out );
|
||||
|
||||
int im_tone_build_range( VipsImage *out,
|
||||
int in_max, int out_max,
|
||||
double Lb, double Lw, double Ps, double Pm, double Ph,
|
||||
double S, double M, double H );
|
||||
int im_tone_build( VipsImage *out,
|
||||
double Lb, double Lw, double Ps, double Pm, double Ph,
|
||||
double S, double M, double H );
|
||||
int im_tone_analyse( VipsImage *in, VipsImage *out,
|
||||
double Ps, double Pm, double Ph, double S, double M, double H );
|
||||
int im_tone_map( VipsImage *in, VipsImage *out, VipsImage *lut );
|
||||
|
@ -739,6 +739,14 @@ int im_invertlut( DOUBLEMASK *input, VipsImage *output, int lut_size );
|
||||
int im_identity( VipsImage *lut, int bands );
|
||||
int im_identity_ushort( VipsImage *lut, int bands, int sz );
|
||||
|
||||
int im_tone_build_range( VipsImage *out,
|
||||
int in_max, int out_max,
|
||||
double Lb, double Lw, double Ps, double Pm, double Ph,
|
||||
double S, double M, double H );
|
||||
int im_tone_build( VipsImage *out,
|
||||
double Lb, double Lw, double Ps, double Pm, double Ph,
|
||||
double S, double M, double H );
|
||||
|
||||
int im_system( VipsImage *im, const char *cmd, char **out );
|
||||
VipsImage *im_system_image( VipsImage *im,
|
||||
const char *in_format, const char *out_format, const char *cmd_format,
|
||||
|
Loading…
Reference in New Issue
Block a user