From octave-sources-request at bevo dot che dot wisc dot edu Sun Jan 7 12:31:44 2001 Subject: a couple of image processing tools From: Fred Bacon To: octave-sources at bevo dot che dot wisc dot edu Date: Sun, 07 Jan 2001 13:34:06 -0500 This is a multi-part message in MIME format. --------------657BE88ECAA72CF68090AB80 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit These functions aren't particularly sophisticated, but they may be of more general use than my problem. I recently found myself in need of matching colors from a hyperspectral scene generator to imagery captured from a camera. After struggling with this for some time, I decided that I would have to calibrate the imagery using some sort of color chart. I settled on generating a Macbeth Color Chart with the hyperspectral image generation software. I bandpass filtered the image with the CIE tristimulus functions to produce three channel imagery. To convert these into RGB values, I required a transformation matrix from the three channel images to a device specific RGB representation of the color space. Okay, enough background. What am I providing? Attached are three functions: macbeth.m macbethchart.m colormatch.m What these functions do not do: They do not help you determine a gamma correction for converting one RGB image into another RGB image. They are intended to help you convert one colorspace representation into another. You must know the representation of a set of 4 or more colors (including white) in both color spaces. The function macbeth takes zero or one parameters (GAMMA), and returns a 24x3 matrix of rgb values of the 24 colors of the Macbeth Chart suitable for display on a device of with the specified GAMMA. GAMMA may either be a scalar value or a triplet of values. If a triplet is provided, then they represent independent gamma corrections for the Red, Green and Blue channels. A scalar value is applied to all three channels. If no GAMMA is specified, then a default value of 2.2 is used. (This is the average gamma for PC monitors.) The macbethchart function takes the same parameters as macbeth. However, it can return two matricies. The first is a simple index matrix suitable for displaying the 24 color panels of the Macbeth Color Chart. The second matrix is the same matrix as would be returned by calling macbeth with identical input parameters. This is a convenience function to help with displaying a Macbeth Chart on your screen. You would use it like this: [chart map] = macbethchart(); imshow( chart, map ); This will display the chart on your screen if you have xv installed. The final function is colormatch. This function takes two matricies of identical dimensions which represent the same color triplets in two different color spaces. The matricies should be passed in as 3xN matricies and not Nx3 matricies! The output from the function are the following: [A WP RGB] = colormatch( SRC, RGBSTD ); A : a matrix transform mapping the SRC colorspace into RGBSTD space WP : a white point correction for the final color space RGB : the white point corrected, transform of SRC In order for WP to be computed correctly, RGBSTD and SRC should both contain "white" as one color of their matricies. The columns of SRC and RGBSTD should contain representations of the same "color" in the two different color spaces. In order for this to work, you will want to be sure that SRC and RGBSTD have the same gamma correction. If they have different gammas, then the A matrix will not be very good. The quality of the fit can be appraised by plotting each row plot( RGBSTD(1,:), RGB(1,:), 'ro'), etc. These values should lie on the diagonal line between (0,0) and (1,1). You can make use of this function by computing, or photographing a Macbeth Color Chart. Find the values of the 24 colors in your color space. Gamma correct the color spaces. (In my problem, the computed colors are known to have a gamma of one, but the color space is not any of the standard colorspaces.) Once I have my 3x24 matrix, XYZ, I can match the colors to my screen display using mbmap = macbeth(); [A wp rgb] = colormatch( XYZ, mbmap' ); This is a very brief, and I'm afraid incomplete, introduction to what these functions do. I hope to expand on them in the future, but offer these as they stand for right now. Good Luck, -- Fred Bacon ======================================================================= Aerodyne Research, Inc. Phone: (978) 663-9500 ext. 273 45 Manning Rd. FAX: (978) 663-4918 Billerica, MA 01821-3976 http://www.aerodyne.com ======================================================================= --------------657BE88ECAA72CF68090AB80 Content-Type: text/plain; charset=us-ascii; name="macbeth.m" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="macbeth.m" ## -*- texinfo -*- ## at deftypefn {Function File} {@var{map} =} macbeth(@var{gamma}) ## Compute the rgb color map for a device with a gamma of ## at var{gamma} dot @var{gamma} may be either a single number ## or a vector of three values specifying separate gamma ## corrections for each of the three color channels. ## at end deftypefn ## Author: fwb function rgb = macbeth( gamma ) rgb = [ 0.235319977964449 0.123937580852935 0.0876186943854026; 0.651958468230155 0.397208955778512 0.302415317607466 ; 0.172441219798325 0.262385960116198 0.430087729619987 ; 0.143417890653033 0.206221583289454 0.0852851354843452; 0.308985229417733 0.293251781970817 0.543692785960707 ; 0.200705917742394 0.609354076368706 0.506248041103525 ; 0.784570790039988 0.288727632678733 0.0393668789370288; 0.109207508608371 0.154127170554764 0.482092424653572 ; 0.638047071658205 0.154127170554764 0.18088267630533 ; 0.155957314151995 0.0699062628472283 0.209989669328233 ; 0.448810349647681 0.602603985577371 0.0784900178955302; 0.864061117893016 0.464397645603466 0.0457016562300151; 0.0520919747054189 0.0720014233232445 0.397208955778512 ; 0.101443287512971 0.381303036712013 0.0998041632579907; 0.5263685269152 0.0618617198971271 0.0678448043588932; 0.922202230195435 0.679118621613514 0.0257526300866511; 0.59729259964524 0.144693224998851 0.391867579346266 ; 0.000000000000000 0.311732860648625 0.482092424653572 ; 1.000000000000000 1.000000000000000 1.000000000000000 ; 0.694676868756556 0.686322333819377 0.69356752608312 ; 0.448810349647681 0.44706316189448 0.452801366745046 ; 0.264330352307809 0.262385960116198 0.262385960116198 ; 0.131449477602962 0.132618383607392 0.132618383607392 ; 0.0520919747054189 0.0525551992318766 0.0525551992318766 ]; if ( nargin == 1 ) if ( length( gamma ) == 3 && ( rows(gamma) == 1 || columns( gamma ) == 1 ) ) rgb(:,1) = rgb(:,1).^(1/gamma(1)); rgb(:,2) = rgb(:,2).^(1/gamma(2)); rgb(:,3) = rgb(:,3).^(1/gamma(3)); else if ( length( gamma ) == 1 ) rgb(:,1) = rgb(:,1).^(1/gamma); rgb(:,2) = rgb(:,2).^(1/gamma); rgb(:,3) = rgb(:,3).^(1/gamma); endif endif else rgb(:,1) = rgb(:,1).^(1/2.2); rgb(:,2) = rgb(:,2).^(1/2.2); rgb(:,3) = rgb(:,3).^(1/2.2); endif --------------657BE88ECAA72CF68090AB80 Content-Type: text/plain; charset=us-ascii; name="colormatch.m" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="colormatch.m" ## -*- texinfo -*- ## at deftypefn {Function File} {[@var{A} @var{wp} @var{rgb}] =} colormatch(@var{xyz},@var{trgb}) ## Compute a transformation matrix at var{A} and white point @var{wp} ## which will generate a least squares approximation mapping a ## color matrix at var{xyz} to a target color matrix @var{trgb}. The ## two color matricies must be of the same dimensions. ## at end deftypefn ## Author: fwb function [A wp rgb] = colormatch( xyz, trgb ) #### # Check that the input parameters are sensible #### if ( nargin == 0 || nargin > 2 ) printf( "Input error.\n" ); exit; else if ( nargin == 1 ) trgb = macbeth(); endif endif #### # We need to do a lot more error checking in here. # We should make sure that the matricies are the # correct size and orientation, etc.. #### #### # Compute the A matrix. #### A = trgb * xyz' * inv( xyz * xyz' ); #### # In order to get the white point, we need to # compute the transformed xyz matrix. If white # is not one of the colors in the map, then the # user shouldn't use or request these values. #### if ( nargout > 1 ) mrgb = A * xyz; wp = max( mrgb' ); #### # If the user requested three output arguments, # then she wanted the new rgb map as well. This # has already had the A matrix and whitepoint # applied to it. #### if ( nargout == 3 ) r = mrgb(1,:)'; g = mrgb(2,:)'; b = mrgb(3,:)'; #### # Apply the white point normalization to the # the matrix elements of the new map; #### r = r / wp(1); g = g / wp(2); b = b / wp(3); #### # It is possible for the pseudoinverse to generate # slightly nonphysical values, We need to clamp # the lower range to zero. The white point # normalization clamps the upper value to 1.0. #### r = r .* (r >= 0); g = g .* (g >= 0); b = b .* (b >= 0); rgb = [ r g b ]; endif endif --------------657BE88ECAA72CF68090AB80 Content-Type: text/plain; charset=us-ascii; name="macbethchart.m" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="macbethchart.m" function [chart map] = macbethchart( gamma ) chart = reshape( 1:24, 6, 4 )'; if ( nargout == 2 ) if ( nargin == 0 ) map = macbeth( ); else map = macbeth( gamma ); endif endif --------------657BE88ECAA72CF68090AB80-- ------------------------------------------------------------- Octave is freely available under the terms of the GNU GPL. Octave's home on the web: http://www.octave.org How to fund new projects: http://www.octave.org/funding.html Subscription information: http://www.octave.org/archive.html -------------------------------------------------------------