Error I'm getting with MagickCore but not MagickWand

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.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

I'm learning to use the MagickWand and MagickCore APIs and have a problem with the Core API.

This is a very simple win32 program compiled under cygwin on Windows 7. It has two functions, test_wand() and test_core() which are supposed to read in a bitmap and write the image as a jpg. Here is the function code, essentially lifted from the tutorials:

Code: Select all

int test_wand()
{
        MagickWand *mw = NULL;

        MagickWandGenesis();

        mw = NewMagickWand();
        if( mw == MagickFalse ) ThrowWandException(mw);

        if( MagickReadImage(mw,"input_test_WAND.bmp") == MagickFalse ) ThrowWandException(mw);
        if( MagickWriteImage(mw,"output_test_WAND.jpg") == MagickFalse ) ThrowWandException(mw);

        if(mw) mw = DestroyMagickWand(mw);

        MagickWandTerminus();

        return 0;
}


int test_core()
{
        Image *image,*imagew;
        ImageInfo *read_info;
        ImageInfo *write_info;
        ExceptionInfo *exception;
        // MagickBooleanType status;

        MagickCoreGenesis((char *) NULL,MagickFalse);

        // Get and Initialize an exception info
        exception = AcquireExceptionInfo();
        GetExceptionInfo(exception);

        // Get and initialize a read_info
        read_info=CloneImageInfo(NULL);

        CopyMagickString(read_info->filename,"input_test_CORE.bmp",MaxTextExtent);

        // Read the image
        image = ReadImage(read_info,exception);
        imagew = CloneImage(image,0,0,MagickTrue,exception);

        // Set up the output info
        write_info=CloneImageInfo(read_info);
        CopyMagickString(write_info->filename,"output_test_CORE.jpg",MaxTextExtent);

        // MagickWriteImage does this so I do it too.
        write_info->adjoin=MagickTrue;

        // write the image
        WriteImage(write_info,imagew);

        DestroyImage(image);
        DestroyImageInfo(read_info);
        DestroyExceptionInfo(exception);
        MagickCoreTerminus();

        return 0;
}

And here's the result:

Code: Select all

$ ls -l
total 96
drwxr-xr-x+ 1 pgg None     0 Jan 24 16:57 _images
drwxr-xr-x+ 1 pgg None     0 Jan 24 15:27 include
-rwxr-xr-x  1 pgg None 10006 Jan 24 17:04 input_test_CORE.bmp
-rwxr-xr-x  1 pgg None 10006 Jan 24 17:04 input_test_WAND.bmp
-rwxr-xr-x  1 pgg None   935 Jan 22 12:28 Makefile
drwxr-xr-x+ 1 pgg None     0 Jan 24 17:05 obj
drwxr-xr-x+ 1 pgg None     0 Jan 24 15:43 res
drwxr-xr-x+ 1 pgg None     0 Jan 24 17:05 src
-rwxr-xr-x  1 pgg None 10006 Jan 24 16:55 test.bmp
-rwxr-xr-x  1 pgg None 38400 Jan 24 17:05 testprogram.exe

$ ./testprogram.exe

$ ls -l
total 100
drwxr-xr-x+ 1 pgg None     0 Jan 24 16:57 _images
drwxr-xr-x+ 1 pgg None     0 Jan 24 15:27 include
-rwxr-xr-x  1 pgg None 10090 Jan 24 17:07 input_test_CORE.bmp
-rwxr-xr-x  1 pgg None 10006 Jan 24 17:04 input_test_WAND.bmp
-rwxr-xr-x  1 pgg None   935 Jan 22 12:28 Makefile
drwxr-xr-x+ 1 pgg None     0 Jan 24 17:05 obj
-rw-r--r--  1 pgg None  2420 Jan 24 17:07 output_test_WAND.jpg
drwxr-xr-x+ 1 pgg None     0 Jan 24 15:43 res
drwxr-xr-x+ 1 pgg None     0 Jan 24 17:05 src
-rwxr-xr-x  1 pgg None 10006 Jan 24 16:55 test.bmp
-rwxr-xr-x  1 pgg None 38400 Jan 24 17:05 testprogram.exe
The test_wand() function works as expected, reading input_test_WAND.bmp in and writing output_test_WAND.jpg. Hooray.

The test_core() function doesn't work. Not only does it modify the original file (why?):

-rwxr-xr-x 1 pgg None 10006 Jan 24 17:04 input_test_CORE.bmp
-rwxr-xr-x 1 pgg None 10090 Jan 24 17:07 input_test_CORE.bmp

but it doesn't write the output_test_CORE.jpg file.

What error am I making?

Thank you.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

Hmmm, no ideas? :(


I spent the last few days reading through all the API documentation. Here's an even simpler complete program that doesn't work:

Code: Select all

#include <stdio.h>
#include <magick/MagickCore.h>

int main() {

  Image *im_image;
  ImageInfo *im_image_info;
  ExceptionInfo *im_exception;

  MagickCoreGenesis( NULL, MagickTrue );

  im_exception = AcquireExceptionInfo();
  GetExceptionInfo( im_exception );

  im_image_info = CloneImageInfo(NULL);

  strcpy( im_image_info->filename, "input_test_CORE.bmp" );

  im_image = ReadImage( im_image_info, im_exception );

  strcpy( im_image_info->filename, "output_test_CORE.bmp" );


  WriteImage( im_image_info, im_image );

  DestroyImage( im_image );
  DestroyImageInfo( im_image_info );
  DestroyExceptionInfo( im_exception );
  MagickCoreTerminus();

  return 0;
}
Should simply read in a file, and write it to another file. Instead it does the same thing.

Before running, the file input_test_CORE.bmp is 10006 bytes. After running input_test_CORE.bmp is 10090 bytes, and there's no output_test_CORE.bmp.

Doesn't matter if I try reading a jpg and writing it to another file. It just alters the original file.
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Error I'm getting with MagickCore but not MagickWand

Post by el_supremo »

You need to clone a separate ImageInfo for writing. See my example code
http://members.shaw.ca/el.supremo/Magic ... ckCore.htm

Pete
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

el_supremo wrote:You need to clone a separate ImageInfo for writing. See my example code
http://members.shaw.ca/el.supremo/Magic ... ckCore.htm

Pete
Thanks for posting and pointing out that error.


But please see my first post in this thread - I used your code, from your example. Substituting just the filenames.


In fact, this program, 100% cut & pasted from your example:

Code: Select all

#include <stdio.h>
#include <magick/MagickCore.h>

int main()
{
        Image *image,*imagew;
        ImageInfo *read_info;
        ImageInfo *write_info;
        ExceptionInfo *exception;
        MagickBooleanType status;

        MagickCoreGenesis((char *) NULL,MagickFalse);

        // Get and Initialize an exception info
        exception = AcquireExceptionInfo();
        GetExceptionInfo(exception);

        // Get and initialize a read_info
        read_info=CloneImageInfo(NULL);

        CopyMagickString(read_info->filename,"logo:",MaxTextExtent);

        // Read the image
        image = ReadImage(read_info,exception);
        imagew = CloneImage(image,0,0,MagickTrue,exception);
        // Set up the output info
        write_info=CloneImageInfo(read_info);
        CopyMagickString(write_info->filename,"logo.jpg",MaxTextExtent);
        // MagickWriteImage does this so I do it too.
        write_info->adjoin=MagickTrue;
        // write the image
        WriteImage(write_info,imagew);

        DestroyImage(image);
        DestroyImageInfo(read_info);
        DestroyExceptionInfo(exception);
        MagickCoreTerminus();
}
only sort of works. It doesn't write a file called "logo.jpg" ... it writes a file called "LOGO". It is actually the logo in jpg format, but I'm at a loss to explain why it doesn't write the file with the specified filename "logo.jpg" ...

Thanks.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

This is exactly what I have and exactly what happens:

Code: Select all

pgg@g550 ~/test
$ cat test.c

#include <stdio.h>
#include <string.h>
#include <magick/MagickCore.h>


int main() {

  Image *im_image, *im_image_w;
  ImageInfo *im_image_info, *im_image_info_w;
  ExceptionInfo *im_exception;

  MagickCoreGenesis( NULL, MagickTrue );

  im_exception = AcquireExceptionInfo();
  GetExceptionInfo( im_exception );

  im_image_info = CloneImageInfo(NULL);

  strcpy( im_image_info->filename, "input.bmp" );

  im_image = ReadImage( im_image_info, im_exception );

  im_image_w = CloneImage( im_image, 0, 0, MagickTrue, im_exception );
  im_image_info_w = CloneImageInfo( im_image_info );
  strcpy( im_image_info_w->filename, "output.bmp" );

  WriteImage( im_image_info_w, im_image_w );

  DestroyImage( im_image );
  DestroyImageInfo( im_image_info );
  DestroyExceptionInfo( im_exception );
  MagickCoreTerminus();

  return 0;
}

pgg@g550 ~/test
$ gcc test.c -o test -lMagickCore-Q16 -L/home/pgg/ImageMagick-6.8.1/lib -I/home/pgg/ImageMagick-6.8.1/include/ImageMagick
In file included from /home/pgg/ImageMagick-6.8.1/include/ImageMagick/magick/MagickCore.h:29:0,
                 from test.c:5:
/home/pgg/ImageMagick-6.8.1/include/ImageMagick/magick/magick-config.h:29:3: warning: #warning "you should set MAGICKCORE_QUANTUM_DEPTH to sensible default set it to configure time default"
/home/pgg/ImageMagick-6.8.1/include/ImageMagick/magick/magick-config.h:30:3: warning: #warning "this is an obsolete behavior please fix your makefile"
/home/pgg/ImageMagick-6.8.1/include/ImageMagick/magick/magick-config.h:52:3: warning: #warning "you should set MAGICKCORE_HDRI_ENABLE to sensible default set it to configure time default"
/home/pgg/ImageMagick-6.8.1/include/ImageMagick/magick/magick-config.h:53:3: warning: #warning "this is an obsolete behavior please fix yours makefile"

pgg@g550 ~/test
$ ls -l
total 68
drwxr-xr-x+ 1 pgg None     0 Jan 30 22:41 include
-rwxr-xr-x  1 pgg None 10006 Jan 30 22:42 input.bmp
-rwxr-xr-x  1 pgg None  1010 Jan 30 22:42 test.c
-rwxr-xr-x  1 pgg None 53036 Jan 30 22:43 test.exe

pgg@g550 ~/test
$ ./test.exe

pgg@g550 ~/test
$ ls -l
total 68
drwxr-xr-x+ 1 pgg None     0 Jan 30 22:41 include
-rwxr-xr-x  1 pgg None 10090 Jan 30 22:43 input.bmp
-rwxr-xr-x  1 pgg None  1010 Jan 30 22:42 test.c
-rwxr-xr-x  1 pgg None 53036 Jan 30 22:43 test.exe
It doesn't write to output.bmp
It modifies input.bmp
It makes no sense to me.

I appreciate your help very much.
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Error I'm getting with MagickCore but not MagickWand

Post by el_supremo »

I'm using 6.7.5 Q16 and it doesn't work for me either.
I can't figure out what is wrong. There don't seem to be any changes to the IM code that would have affected it.

Pete
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

Good to know that I'm not insane. :)


Are the transforms available through the MagickWand API a subset of what's in MagickCore? From the examples and docs I've read, it looks like MagickWand doesn't do everything MagickCore can do.

For example, if I wanted to embed a command line function like
convert test.jpg -virtual-pixel black -distort Perspective '0,0,0,0 250,0,250,0 0,200,50,200 250,200,200,200' test-distorted.jpg

in a program, must I use the more complex MagickCore API, or is there a MagickWand shortcut?
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Error I'm getting with MagickCore but not MagickWand

Post by el_supremo »

Most core operations are available in MagickWand.
This code should emulate your convert command.

Pete

Code: Select all

#include <windows.h>
#include <wand/magick_wand.h>

void test_wand(LPTSTR lpCmdLine)
{
	MagickWand *mw = NULL;

	double cpoints[16] = {
		0,0,0,0, 250,0,250,0, 0,200,50,200, 250,200,200,200
	};

	MagickWandGenesis();

	mw = NewMagickWand();

	MagickReadImage(mw,"logo:");

/*
	For a list of valid virtual pixel methods in your version of IM
	use the command:
	convert -list virtualpixel
*/
	MagickSetImageVirtualPixelMethod(mw,BlackVirtualPixelMethod);

	// distort the image
	// Note that for +distort set the last argument MagickTrue
	// -distort will be MagickFalse
	MagickDistortImage(mw,PerspectiveDistortion,
							16,(const double *)&cpoints,MagickFalse);

	MagickWriteImage(mw,"test_distorted.jpg");
	/* Clean up */
	if(mw)mw = DestroyMagickWand(mw);

	MagickWandTerminus();
}
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

el_supremo wrote:Most core operations are available in MagickWand.
This code should emulate your convert command.

[...]
Thank you again. I'll read through the rest of the docs to see if I can get everything done in MagickWand. Quick "is it possible" question before I invest too much time searching: :)



One of the primary image manipulation tasks I want to do is compare two images and locate the area that is most different. Using the command line tools,

Code: Select all

compare -fuzz 5000 -highlight-color blue im1.jpg im2.jpg im-difference.jpg
does this task and will highlight the different area in blue. For example, comparing these two MS-Paint-generated scribbles
Image
and
Image
gets a "difference" image of
Image

Is there a simple/elegant mechanism to return the location (column,row ... or maybe a rectangle) of that maximally different blue smudge area? Perhaps using MagickSimilarityImage (though it's not clear what it means by offset and what 'computed similarity' refers to)?

Thank you again, you've been very helpful and I appreciate it.
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Error I'm getting with MagickCore but not MagickWand

Post by el_supremo »

I have more or less replicated the compare command (code below) but it doesn't output exactly the difference image that you show. It has some extra blue speckles around the main blob.

Pete

Code: Select all

#include <windows.h>
#include <wand/magick_wand.h>

void test_wand(LPTSTR lpCmdLine)
{
	MagickWand *img1 = NULL,*img2 = NULL,*m_wand = NULL;
	double distortion = 0.0;

	MagickWandGenesis();
	img1 = NewMagickWand();
	img2 = NewMagickWand();

	MagickReadImage(img1, "im1.jpg");
	MagickSetImageArtifact(img1,"highlight-color","blue");
	MagickSetOption(img1,"fuzz","500");

	MagickReadImage(img2,"im2.jpg");
	MagickSetImageArtifact(img2,"highlight-color","blue");
	MagickSetOption(img2,"fuzz","5000");

	// the command line didn't specify a metric
	m_wand = MagickCompareImages(img1,img2,UndefinedMetric,&distortion);

	MagickWriteImage( m_wand, "im-difference_a.jpg" );
	/* Tidy up */
	m_wand = DestroyMagickWand(m_wand);
	img1 = DestroyMagickWand(img1);
	img2 = DestroyMagickWand(img2);
	MagickWandTerminus();
}
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

el_supremo wrote:I have more or less replicated the compare command (code below) but it doesn't output exactly the difference image that you show. It has some extra blue speckles around the main blob.

Pete

Code: Select all

#include <windows.h>
#include <wand/magick_wand.h>

void test_wand(LPTSTR lpCmdLine)
{
	MagickWand *img1 = NULL,*img2 = NULL,*m_wand = NULL;
	double distortion = 0.0;

	MagickWandGenesis();
	img1 = NewMagickWand();
	img2 = NewMagickWand();

	MagickReadImage(img1, "im1.jpg");
	MagickSetImageArtifact(img1,"highlight-color","blue");
	MagickSetOption(img1,"fuzz","500");

	MagickReadImage(img2,"im2.jpg");
	MagickSetImageArtifact(img2,"highlight-color","blue");
	MagickSetOption(img2,"fuzz","5000");

	// the command line didn't specify a metric
	m_wand = MagickCompareImages(img1,img2,UndefinedMetric,&distortion);

	MagickWriteImage( m_wand, "im-difference_a.jpg" );
	/* Tidy up */
	m_wand = DestroyMagickWand(m_wand);
	img1 = DestroyMagickWand(img1);
	img2 = DestroyMagickWand(img2);
	MagickWandTerminus();
}
Thanks - this essentially works, as far as creating a 3rd image with the different area marked. I've only got the problem 1/2way solved though.

Is there an elegant way (using the ImageMagick API) to get the coordinates of the area that is maximally different between two images?

Failing that, how might I approach manually examining an image (m_wand in this example) pixel by pixel, looking for the blue? Perhaps something like

Code: Select all


unsigned char *image_data;
size_t image_length;

MagickSetImageFormat( m_wand, _____ );   // a simple noncompressed format with each pixel in sequential order
image_data = MagickGetImageBlob( m_wand, &image_length );

/* pick through image_data, byte by byte, looking for blue pixels, and determining where their 'center of mass' is */

MagickRelinquishMemory( image_data );
Although that looks inefficient and kludgy, and I'd rather not reinvent the wheel if there's an existing solution.


Also, I'm a little unclear on the set format function. The docs just list it as the following but give scant detail on the format parameter:

MagickBooleanType MagickSetImageFormat(MagickWand *wand, const char *format)

Where is there a list of valid strings for the format parameter. I haven't figured out via casual trial and error if it wants "JPEG" for jpg format, "BITMAP" for bmp format, etc.



Thanks again.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Error I'm getting with MagickCore but not MagickWand

Post by snibgo »

I know nothing about MagickCore or MagickWand. From the command line, if you arrange the difference image so the blob is white and the rest is black, then "-morphology distance" will create shades of gray within the blob, with the lightest pixel being the one that is furthest from the edges. If there was more than one blob, the lightest pixel would also identify the largest blob (for an appropriate definition of "largest"). See http://www.imagemagick.org/Usage/morphology/

For formats, perhaps the first column of the listing "convert -list format" is what you want.
snibgo's IM pages: im.snibgo.com
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Error I'm getting with MagickCore but not MagickWand

Post by el_supremo »

There are probably more efficient ways to do this, but one way to determine the coordinates of the blue area would be to scan the rows/columns using MagickGetImagePixelColor(image,x,y,pw). It retrieves the pixel at (x,y) and puts its colour in the PixelWand pw.
The first blue pixel you find with this will be the top left corner of the rectangle. The last blue pixel you find will be the bottom right corner.

Pete
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

el_supremo wrote:There are probably more efficient ways to do this, but one way to determine the coordinates of the blue area would be to scan the rows/columns using MagickGetImagePixelColor(image,x,y,pw). It retrieves the pixel at (x,y) and puts its colour in the PixelWand pw.
The first blue pixel you find with this will be the top left corner of the rectangle. The last blue pixel you find will be the bottom right corner.
I ended up doing this more efficiently with

Code: Select all

size_t image_length;
unsigned char *image_data;

MagickSetImageFormat( compared_mw, "RGB" );
image_data = MagickGetImageBlob( compared_mw, &image_length );
Then going through that array looking at each 3-byte pixel for 00 00 FF was fast and easy.
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: Error I'm getting with MagickCore but not MagickWand

Post by 168gr »

The problem I'm having now though goes back to an earlier task:
168gr wrote:One of the primary image manipulation tasks I want to do is compare two images and locate the area that is most different. Using the command line tools,

Code: Select all

compare -fuzz 5000 -highlight-color blue im1.jpg im2.jpg im-difference.jpg
does this task and will highlight the different area in blue. For example, comparing these two MS-Paint-generated scribbles
Image
and
Image
gets a "difference" image of
Image
When I implement this with MagickWand, it works very nicely.

Code: Select all

  MagickSetImageArtifact( mw1, "highlight-color", "blue" );
  MagickSetImageArtifact( mw1, "highlight-color", "blue" );
  MagickSetOption( mw1, "fuzz", "5000" );
  MagickSetOption( mw2, "fuzz", "5000" );

  mw3 = MagickCompareImages( mw1, mw2, UndefinedMetric, &distortion );

  MagickWriteImage( mw3, "im-difference2.jpg" );
Results in creating this image, which is totally adequate for my subsequent needs:
Image


Here's where everything gets wacky. When I use actual real-world images that have been pre-processed a little, I get some bizarre artifacts.

The actual project is an automated scoring system for rifle targets. Short version, camera is pointed at target, program waits for a new hole to appear, figures out where it is, and scores it accordingly.

Since putting the camera directly in front of the target would bode ill for camera longevity, of necessity the camera is off to one side. This requires 'squaring' the resulting image into something more pleasing to the eye, so the raw image is cropped and put through a perspective transform. The next image comes from the (motionless) camera, same crop and transform, then the new data is compared to previously captured and transformed image looking for a difference.

Here are some test images from original to the transformed intermediates to the final difference:

Original picture of a square piece of paper with a ruler on it, as taken by the camera and resized to 640x480:
Image

Little test blob added with image editing program to simulate 2nd captured image:
Image

Both images after the cropping and perspective transform
Image
Image

The difference as determined by MagickWand in the program:
Image

And running the two intermediary images through the as-simple-as-possible standalone program produces this, which is similarly weird:
Image

Why might I be getting this weird artifact? Thanks.
Post Reply