libvips/libvips/deprecated/im_vips2mask.c

248 lines
5.7 KiB
C

/* im_vips2mask
*
* Author: J.Cupitt
* Written on: 6/6/94
* Modified on:
*
* 16/10/06
* - allow 1xn-band images too
* 23/2/07
* - oop, broken for nx1 m-band images
* - now casts to double for you
* 1/2/10
* - gtkdoc
*/
/*
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 <glib/gi18n-lib.h>
#include <string.h>
#include <vips/vips.h>
#include <vips/vips7compat.h>
/**
* im_vips2mask:
* @in: input image
* @filename: name for output mask
*
* Make a mask from an image. All images are cast to %IM_BANDFMT_DOUBLE
* before processing. There are two cases for handling bands:
*
* If the image has a single band, im_vips2mask() will write a mask the same
* size as the image.
*
* If the image has more than one band, it must be one pixel high or wide. In
* this case the output mask uses that axis to represent band values.
*
* See also: im_mask2vips(), im_measure_area().
*
* Returns: a #DOUBLEMASK with @outname set as the name, or NULL on error
*/
DOUBLEMASK *
im_vips2mask( IMAGE *in, const char *filename )
{
int width, height;
DOUBLEMASK *out;
/* double* only: cast if necessary.
*/
if( in->BandFmt != IM_BANDFMT_DOUBLE ) {
IMAGE *t;
if( !(t = im_open( "im_vips2mask", "p" )) )
return( NULL );
if( im_clip2fmt( in, t, IM_BANDFMT_DOUBLE ) ||
!(out = im_vips2mask( t, filename )) ) {
im_close( t );
return( NULL );
}
im_close( t );
return( out );
}
/* Check the image.
*/
if( im_incheck( in ) ||
im_check_uncoded( "im_vips2mask", in ) )
return( NULL );
if( in->Bands == 1 ) {
width = in->Xsize;
height = in->Ysize;
}
else if( in->Xsize == 1 ) {
width = in->Bands;
height = in->Ysize;
}
else if( in->Ysize == 1 ) {
width = in->Xsize;
height = in->Bands;
}
else {
im_error( "im_vips2mask",
"%s", _( "one band, nx1, or 1xn images only" ) );
return( NULL );
}
if( !(out = im_create_dmask( filename, width, height )) )
return( NULL );
if( in->Bands > 1 && in->Ysize == 1 ) {
double *data = (double *) in->data;
int x, y;
/* Need to transpose: the image is RGBRGBRGB, we need RRRGGGBBB.
*/
for( y = 0; y < height; y++ )
for( x = 0; x < width; x++ )
out->coeff[x + y * width] =
data[x * height + y];
}
else
memcpy( out->coeff, in->data,
width * height * sizeof( double ) );
out->scale = vips_image_get_scale( in );
out->offset = vips_image_get_offset( in );
return( out );
}
INTMASK *
im_vips2imask( IMAGE *in, const char *filename )
{
int width, height;
INTMASK *out;
double *data;
int x, y;
double double_result;
int int_result;
/* double* only: cast if necessary.
*/
if( in->BandFmt != IM_BANDFMT_DOUBLE ) {
IMAGE *t;
if( !(t = im_open( "im_vips2imask", "p" )) )
return( NULL );
if( im_clip2fmt( in, t, IM_BANDFMT_DOUBLE ) ||
!(out = im_vips2imask( t, filename )) ) {
im_close( t );
return( NULL );
}
im_close( t );
return( out );
}
/* Check the image.
*/
if( im_incheck( in ) ||
im_check_uncoded( "im_vips2imask", in ) )
return( NULL );
if( in->Bands == 1 ) {
width = in->Xsize;
height = in->Ysize;
}
else if( in->Xsize == 1 ) {
width = in->Bands;
height = in->Ysize;
}
else if( in->Ysize == 1 ) {
width = in->Xsize;
height = in->Bands;
}
else {
im_error( "im_vips2imask",
"%s", _( "one band, nx1, or 1xn images only" ) );
return( NULL );
}
data = (double *) in->data;
if( !(out = im_create_imask( filename, width, height )) )
return( NULL );
/* We want to make an intmask which has the same input to output ratio
* as the double image.
*
* Imagine convolving with the double image, what's the ratio of
* brightness between input and output? We want the same ratio for the
* int version, if we can.
*
* Imagine an input image where every pixel is 1, what will the output
* be?
*/
double_result = 0;
for( y = 0; y < height; y++ )
for( x = 0; x < width; x++ )
double_result += data[x + width * y];
double_result /= vips_image_get_scale( in );
for( y = 0; y < height; y++ )
for( x = 0; x < width; x++ )
if( in->Bands > 1 && in->Ysize == 1 )
/* Need to transpose: the image is RGBRGBRGB,
* we need RRRGGGBBB.
*/
out->coeff[x + y * width] =
VIPS_RINT( data[x * height + y] );
else
out->coeff[x + y * width] =
VIPS_RINT( data[x + y * width] );
out->scale = VIPS_RINT( vips_image_get_scale( in ) );
if( out->scale == 0 )
out->scale = 1;
out->offset = VIPS_RINT( vips_image_get_offset( in ) );
/* Now convolve a 1 everywhere image with the int version we've made,
* what do we get?
*/
int_result = 0;
for( y = 0; y < height; y++ )
for( x = 0; x < width; x++ )
int_result += out->coeff[x + width * y];
int_result /= out->scale;
/* And adjust the scale to get as close to a match as we can.
*/
out->scale = VIPS_RINT( out->scale + (int_result - double_result) );
if( out->scale == 0 )
out->scale = 1;
return( out );
}