Using LinearStretchImage(...)

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
Post Reply
Alan Hadley
Posts: 48
Joined: 2010-03-31T12:17:55-07:00
Authentication code: 8675308

Using LinearStretchImage(...)

Post by Alan Hadley »

I am trying to include LinearStretchImage(...) in my MagickCore program but can not work out what the black_point and white_point values should be. So far I have tried 0.0 to 1.0, 0 to 100, 0 to QuantumRange. I thought the function would work like this assuming the range were 0.0 to 1.0, when black_point=0.2 and white_point=0.8 the darkest and lightest pixels would be replaced then everything would be stretched. I am assuming that the function works for colour Images, and each channel is processed seperately, or the image is converted to HSV the V channel adjusted and the image converted back.

Can anyone help?

Alan Hadley
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Using LinearStretchImage(...)

Post by fmw42 »

see http://www.imagemagick.org/Usage/color_ ... ar-stretch

note you are clipping by pixels counts or percent counts and not graylevel values.
Alan Hadley
Posts: 48
Joined: 2010-03-31T12:17:55-07:00
Authentication code: 8675308

Re: Using LinearStretchImage(...)

Post by Alan Hadley »

Thank's I get it now. Heres a C++ code snippet

double black=(double)GetPropertyN(o,1)*(double)(im->columns*im->rows);
double white=(double)GetPropertyN(o,2)*(double)(im->columns*im->rows);
if(status!=Status::STATUS_OK) goto quit;

MagickBooleanType ok;
WaitMessage(L"Stretching");
ok=LinearStretchImage(ci,black,white);
EndWaitMessage();
if(ok==MagickBooleanType::MagickFalse)
{
StatusMessage(Status::STATUS_ERROR,L"IM",L"Failed to Stretch");
goto quit;
}

I have normalized most things to the range 0.0 to 1.0 in my program. So multiplying my the number of pixels in the image does the trick.

YUou would expect that black_point+white_point should not add up to more than the number of pixels in the image. But you get an inverted result if the sum is greater.

P.S. Will IM version 7 be doing away with the 'ok' return value in several functions when all functions have an ExceptionInfo argument. I would like them to return a new image instead of altering the old one.

Alan Hadley
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Using LinearStretchImage(...)

Post by anthony »

Generally images that modify an old image, do so because they can!

The reason is to save memory for processing VERY large images! It is better NOT to generate a new images if not needed, though in many cases that would be convenient. Doing so takes away processing possibilities, rather than adds them.

But any operator that changes image size typically HAS to generate a new image, it has no choice. Crop, Border, frame, distort, resize are classic examples. Similarly images that need to randomly access image data , such as fx, blur, convolve, morphology.

A two pass operator like Resize, even has to generate another internal image (making three copies) as part of its processing. Which is why some LARGE image processing uses a slower distort to resize rather than resize even though they don't care about filter differences. (they could use interpolative-resize too in this case).

It would be nice to be able to tell resize to delete the original when it has completed its first pass! Simply because it has either already been cloned, or you definitely will be replacing the image (IE: CLI image processing style). But that is the oppisite of what you are requesting.

If this is not want is wanted, you are always free to clone the image before hand. Clone is very efficient with it only generating the new image data when the data actually changes by a command such as you describe.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Using LinearStretchImage(...)

Post by anthony »

As for the OK message. you can often ignore it, BUT you still much check for exceptions after every operation!

The new IMv7 CLI ("magick" command) does that, and aborts earlier when a higher level exception happens (level to abort at will be settable) It relies on exceptions far more than 'OKay' responses.

This is also reflected in 'example C usage' of the new CLI interface.
See MagickWand/tests/ of the source.



Also api_examples (though I am not certain if I added that to the SVN)...
this tries to implement a small CLI command in many different (and progressivally lower level) ways.

Here is one such example...

Code: Select all

/*
   Direct call to ProcessCommandOptions() to process an array of
   options minus the command argument.  This is the function that
   actually splits up the argument array into separate operation
   group calls.


   Compile with ImageMagick-devlop installed...

     gcc -lMagickWand -lMagickCore cli_process.c -o cli_process

   Compile and run directly in Source Directory...

     IM_PROG=examples/cli_process
     gcc -I`pwd` -LMagickWand/.libs -LMagickCore/.libs \
       -lMagickWand -lMagickCore  $IM_PROG.c -o $IM_PROG

     sh magick.sh    $IM_PROG

*/
#include <stdio.h>
#include "MagickCore/studio.h"
#include "MagickWand/MagickWand.h"

int main(int argc, char **argv)
{
  MagickCLI
    *cli_wand;

  int arg_count;
  char *args[] = { "-size", "100x100", "xc:red",
                   "(", "rose:", "-rotate", "-90", ")",
                   "+append", "show:", NULL };

  for(arg_count = 0; args[arg_count] != (char *)NULL; arg_count++);


  MagickCoreGenesis(argv[0],MagickFalse);
  cli_wand = AcquireMagickCLI((ImageInfo *)NULL,(ExceptionInfo *)NULL);

  ProcessCommandOptions(cli_wand, arg_count, args, 0, MagickCommandOptionFlags);

  /* Note use of 'True' to report all exceptions - including non-fatals */
  if ( CLICatchException(cli_wand,MagickTrue) != MagickFalse )
    fprintf(stderr, "Major Error Detected\n");


  cli_wand = DestroyMagickCLI(cli_wand);
  MagickCoreTerminus();
}
The CLI-Wand is new to IMv7 and represents an expanded 'wand' that is part of CLI process.

Basically this is a normal 'magick-wand' (which is a list of images and current global settings) plus extra info needed for CLI argument handling (draw/quantization info structures, processing flags, parenthesis image stack, where argument came from for error reporting etc.). Basically a collecting of what were ordinaly processing variables in IMv6 CLI process.

The MagickWand part of MagickCLI is the first element, so its point can technically be directly used for MagickWand API's, though currently doesn't make a lot of use of that feature.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Post Reply