| /* @(#) Function to perform lighting correction. |
| * @(#) One band IM_BANDFMT_UCHAR images only. Always writes UCHAR. |
| * @(#) |
| * @(#) Function im_litecor() assumes that imin |
| * @(#) is either memory mapped or in a buffer. |
| * @(#) |
| * @(#) int im_litecor(in, w, out, clip, factor) |
| * @(#) IMAGE *in, *w, *out; |
| * @(#) int clip; |
| * @(#) double factor; |
| * @(#) |
| * @(#) clip==1 |
| * @(#) - Compute max(white)*factor*(image/white), Clip to 255. |
| * @(#) clip==0 |
| * @(#) - Compute factor for you. |
| * @(#) |
| * @(#) |
| * @(#) |
| * @(#) |
| * @(#) Returns 0 on success and -1 on error |
| * |
| * Copyright: 1990, J. Cupitt, 1991 N. Dessipris |
| * |
| * Author: J. Cupitt, N. Dessipris |
| * Written on: 02/08/1990 |
| * Modified on : 6/11/1991, by ND to produce a UCHAR output |
| * 1/4/93 J.Cupitt |
| * - bugs if white is smaller than image fixed |
| * - im_warning() now called |
| * - clip==0 case not tested or changed! do not use! |
| */ |
| |
| /* |
| |
| 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <vips/vips.h> |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif /*WITH_DMALLOC*/ |
| |
| /* If maximum output is > 255 scale output between minout and maxout, |
| * by normalising maxout to 255. |
| * If maximum output is < 255 do the light correction without scaling |
| */ |
| static int |
| im_litecor0( in, white, out ) |
| IMAGE *in, *white, *out; |
| { PEL *p, *w; |
| PEL *q, *bu; |
| int c; |
| int x, y; |
| float xrat = (float) in->Xsize / white->Xsize; |
| float yrat = (float) in->Ysize / white->Ysize; |
| int xstep = (int) xrat; |
| int ystep = (int) yrat; |
| double max; |
| int wtmp, maxw, maxout, temp; |
| |
| /* Check white is some simple multiple of image. |
| */ |
| if( xrat < 1.0 || xrat != xstep || yrat < 1.0 || yrat != ystep ) { |
| im_error( "im_litecor", "white not simple scale of image" ); |
| return( -1 ); |
| } |
| |
| /* Find the maximum of the white. |
| */ |
| if( im_max( white, &max ) ) |
| return( -1 ); |
| maxw = (int)max; |
| |
| /* Set up the output header. |
| */ |
| if( im_cp_desc( out, in ) ) |
| return( -1 ); |
| if( im_setupout( out ) ) |
| return( -1 ); |
| |
| /* Make buffer for outputting to. |
| */ |
| if( !(bu = (PEL *) im_malloc( out, out->Xsize )) ) |
| return( -1 ); |
| |
| /* Find largest value we might generate if factor == 1.0 |
| */ |
| maxout = -1; |
| p = (PEL *) in->data; |
| for( y = 0; y < in->Ysize; y++ ) { |
| /* Point w to the start of the line in the white |
| * corresponding to the line we are about to correct. c counts |
| * up to xstep; each time it wraps, we should move w on one. |
| */ |
| w = (PEL *) (white->data + white->Xsize * (int)(y/ystep)); |
| c = 0; |
| |
| /* Scan along line. |
| */ |
| for( x = 0; x < out->Xsize; x++ ) { |
| wtmp = (int)*w; |
| temp = ( maxw * (int) *p++ + (wtmp>>1) ) / wtmp; |
| if (temp > maxout ) |
| maxout = temp; |
| |
| /* Move white pointer on if necessary. */ |
| c++; |
| if( c == xstep ) { |
| w++; |
| c = 0; |
| } |
| } |
| } |
| |
| /* Do exactly the same as above by scaling the result with respect to |
| * maxout |
| */ |
| p = (PEL *) in->data; |
| if (maxout <= 255 ) /* no need for rescaling output */ |
| { |
| for( y = 0; y < in->Ysize; y++ ) |
| { |
| q = bu; |
| w = (PEL *) (white->data + |
| white->Xsize * (int)(y/ystep)); |
| c = 0; |
| |
| /* Scan along line. */ |
| for( x = 0; x < in->Xsize; x++ ) |
| { |
| wtmp = (int)*w; |
| *q++ = (PEL) |
| ( ( maxw * (int) *p++ + (wtmp>>1) ) / wtmp ); |
| /* Move white pointer on if necessary. |
| */ |
| c++; |
| if( c == xstep ) { w++; c = 0; } |
| } |
| if( im_writeline( y, out, bu ) ) |
| { |
| im_error("im_litecor", "im_writeline failed"); |
| return( -1 ); |
| } |
| } |
| } |
| else /* rescale output wrt maxout */ |
| { |
| for( y = 0; y < in->Ysize; y++ ) |
| { |
| q = bu; |
| w = (PEL *) (white->data + |
| white->Xsize * (int)(y/ystep)); |
| c = 0; |
| |
| /* Scan along line. */ |
| for( x = 0; x < in->Xsize; x++ ) |
| { |
| wtmp = maxout * ((int)*w); |
| *q++ = (PEL) |
| ( ( maxw * (int) *p++ * 255 + (wtmp>>1)) / wtmp ); |
| /* Move white pointer on if necessary. |
| */ |
| c++; |
| if( c == xstep ) { w++; c = 0; } |
| } |
| if( im_writeline( y, out, bu ) ) |
| { |
| im_error("im_litecor", "im_writeline failed"); |
| return( -1 ); |
| } |
| } |
| } |
| |
| return( 0 ); |
| } |
| |
| /* Clip all corrected values above 255, if any. |
| */ |
| static int |
| im_litecor1( in, white, out, factor ) |
| IMAGE *in, *white, *out; |
| double factor; |
| { PEL *p, *w; |
| PEL *q, *bu; |
| int c; |
| int x, y; |
| float xrat = (float) in->Xsize / white->Xsize; |
| float yrat = (float) in->Ysize / white->Ysize; |
| int xstep = (int) xrat; |
| int ystep = (int) yrat; |
| double max; |
| double maxw, temp; |
| int nclipped = 0; |
| |
| /* Check white is some simple multiple of image. |
| */ |
| if( xrat < 1.0 || xrat != xstep || yrat < 1.0 || yrat != ystep ) { |
| im_error( "im_litecor", "white not simple scale of image" ); |
| return( -1 ); |
| } |
| |
| /* Find the maximum of the white. |
| */ |
| if( im_max( white, &max ) ) |
| return( -1 ); |
| maxw = max; |
| |
| /* Set up the output header. |
| */ |
| if( im_cp_desc( out, in ) ) |
| return( -1 ); |
| if( im_setupout( out ) ) |
| return( -1 ); |
| |
| /* Make buffer we write to. |
| */ |
| if( !(bu = (PEL *) im_malloc( out, out->Xsize )) ) |
| return( -1 ); |
| |
| /* Loop through sorting max output |
| */ |
| p = (PEL *) in->data; |
| for( y = 0; y < in->Ysize; y++ ) { |
| q = bu; |
| w = (PEL *) (white->data + white->Xsize * (int)(y / ystep)); |
| c = 0; |
| |
| for( x = 0; x < out->Xsize; x++ ) { |
| temp = ((factor * maxw * (int) *p++)/((int) *w)) + 0.5; |
| if( temp > 255.0 ) { |
| temp = 255; |
| nclipped++; |
| } |
| *q++ = temp; |
| |
| /* Move white pointer on if necessary. |
| */ |
| c++; |
| if( c == xstep ) { |
| w++; |
| c = 0; |
| } |
| } |
| |
| if( im_writeline( y, out, bu ) ) |
| return( -1 ); |
| } |
| |
| if( nclipped ) |
| im_warn( "im_litecor", "%d pels over 255 clipped", nclipped ); |
| |
| return( 0 ); |
| } |
| |
| /* Lighting correction. One band uchar images only. |
| * Assumes the white is some simple multiple of the image in size; ie. the |
| * white has been taken with some smaller or equal set of resolution |
| * parameters. |
| */ |
| int |
| im_litecor( in, white, out, clip, factor ) |
| IMAGE *in, *white, *out; |
| int clip; |
| double factor; |
| { /* Check our args. |
| */ |
| if( im_iocheck( in, out ) ) |
| return( -1 ); |
| if( in->Bands != 1 || |
| in->Coding != IM_CODING_NONE || in->BandFmt != IM_BANDFMT_UCHAR ) { |
| im_error( "im_litecor", "bad input format" ); |
| return( -1 ); |
| } |
| if( white->Bands != 1 || |
| white->Coding != IM_CODING_NONE || white->BandFmt != IM_BANDFMT_UCHAR ) { |
| im_error( "im_litecor", "bad white format" ); |
| return( -1 ); |
| } |
| |
| switch( clip ) { |
| case 1: |
| return( im_litecor1( in, white, out, factor ) ); |
| |
| case 0: |
| return( im_litecor0( in, white, out ) ); |
| |
| default: |
| im_error( "im_litecor", "unknown flag %d", clip ); |
| return( -1 ); |
| } |
| } |