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
Using LinearStretchImage(...)
-
- Posts: 48
- Joined: 2010-03-31T12:17:55-07:00
- Authentication code: 8675308
- fmw42
- Posts: 25562
- Joined: 2007-07-02T17:14:51-07:00
- Authentication code: 1152
- Location: Sunnyvale, California, USA
Re: Using LinearStretchImage(...)
see http://www.imagemagick.org/Usage/color_ ... ar-stretch
note you are clipping by pixels counts or percent counts and not graylevel values.
note you are clipping by pixels counts or percent counts and not graylevel values.
-
- Posts: 48
- Joined: 2010-03-31T12:17:55-07:00
- Authentication code: 8675308
Re: Using LinearStretchImage(...)
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
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
- anthony
- Posts: 8883
- Joined: 2004-05-31T19:27:03-07:00
- Authentication code: 8675308
- Location: Brisbane, Australia
Re: Using LinearStretchImage(...)
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.
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/
https://imagemagick.org/Usage/
- anthony
- Posts: 8883
- Joined: 2004-05-31T19:27:03-07:00
- Authentication code: 8675308
- Location: Brisbane, Australia
Re: Using LinearStretchImage(...)
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...
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.
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();
}
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/
https://imagemagick.org/Usage/