Is there a perl version of "SetPixels"?

PerlMagick is an object-oriented Perl interface to ImageMagick. Use this forum to discuss, make suggestions about, or report bugs concerning PerlMagick.
Post Reply
charg

Is there a perl version of "SetPixels"?

Post by charg »

Hi,
I am trying to initialize the pixels of an image from a PERL array.
Is there an equivalent of "SetPixels", or do I have to set every pixel individually?
Thanks!
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Post by magick »

The most efficient way to set image pixels is probably with BlobToImage(). Your blob can be a rectangular array of pixels. You of course can set individual pixels with
  • $image->Set("pixel[$x,$y]"=>'blue');
charg

Post by charg »

Thanks for the prompt reply.
Let me give a little bit more background information regarding the context of the question (my naive application of BlobToImage did not work :roll: )

I am using ImageMagick to
  • a) read 16 bit TIFF grayscale images (from confocal laser microscopes)

    b)extract the gray level intensities into a numerical matrix which is

    c) fed to a C function (loaded as a dynamic library at the beginning of the PERL script).
The processing routines return a processed numerical matrix of gray intensity values which represent a restored version of the original ("$origimage"). My problem is that I want to save these numerical values in an image format (16bit TIFF) rather than a HDF file.
What I have done so far is to:
  • a) call the Image:Magick->new constructor to create a new empty image object ,
    b) set the attributes of the new image (depth,colourspace, resolution,dimensions) using the information from the original
and I'm left with the problem of telling PERLMagick to set the pixel intensity values.
My C part of the code communicates with the PERL script via SWIG so I do have access to
a) both the pointer that stores the gray intensity values in a C array and
b) a PERL version of it.

I tried to call BlobToImage with the PERL list initialized with the intensity values from the C array but memory requirements did go sky high and the image was never actually written (I gave up after 20 minutes :P)
Is there something else I should do? I am not particularly looking forward to recoding my program in C (the C API to ImageMagick works great for me, but I do not want to write the "main" of my image restoration program in C; perl and perl/tk work much more smoothly when it comes to interacting with the user ).

Any ideas about setting the pixel intensity values from within PerlMagick or is it a no-no?
charg

Post by charg »

I finally found a fast solution to my problem and I thought it best to share.
(BTW does the PERL version of GetPixels automatically rescale the channel values to a 16-bit integer? It seems to do it for me, so the solution addresses this issue as well)

In any case, the workaround if the following:

Getting the unscaled pixel intensity values of the original image
The first thing to do, is to change the internal format of the original image ($original) to RGB with the following command:

$original->Set(magick=>'RGB');

Then a call to ImageToBlob will return the RGB values of the pixels in triples of a basic C data type depending on the image depth:

$blob=$original->ImageToBlob();

The blob of a RGB image contains only the channel intensity values for each color and nothing else, without any (obvious) rescaling to 16 bits.
We now have to get these pixel values, from the blob; depending on the image depth we can do either:

@rgbvals = unpack "C*",$blob; (8-bits)
@rgbvals = unpack "n*",$blob; (16-bits)

Now the (R,G,B) values for the first two pixels will be available in $rgbvals[0],$rgbvals[1],$rgbvals[2], and $rgbvals[3],$rgbvals[4],$rgbvals[5] respectively and do on, so forth.

(when the pixel intensities cannot fit in integer multiples of a byte e.g. 12-bit images, it is best to use the first version of unpack and then start splitting bytes left and right to get the raw data).

The @rgbvals list can then be processed outside PerlMagick (in my case I initialize a regular C array and channel it to a C library through SWIG).

In order to generate the new image it suffices to retrace one's steps i.e.
$blob=pack "C*",@rgbvals; (8-bits)
$blob=pack "n*",@rgbvals; (16-bits)

call BlobToImage on a PERLMAGICK object of type 'RGB', reset the image type to whatever and save to the disk.
gnembon

Re: Is there a perl version of "SetPixels"?

Post by gnembon »

I would like to refresh the topic. I was trying to resample the image using my custom algorithm and for this purpose I needed direct access to image data. I tried first get/setpixel method but it was really slow. I was missing a method like get/setscanline from perl Imager.pm module.

I tried the method proposed here, but I found several problems.

First of all: 'Endian'nity. Although there is no problem with 8 bits images, 16 bits images require reverse 'Endian'nity then perl is operating, to setting RGB values with vec($img_data,$index,16)=$value; doesn't work. It requires additional swapping of even and odd bytes. This problem I detected and solved.

Second: I cannot overwrite image data with BlobToImage.
So What I am doing is open input image, get it's data with ImageToBlob and crop it to desired size in order to preserve image EXIF metadata. When I finally calculate my new data for the image on a side and try to do BlobToImage on the same image, it actually creates second image - with all metadata lost. When I'm saving it I got two images - the cropped one with Exif and the resized one - with clean exif.

Is there any way to substitute existing and loaded image data with other using BlobToImage? Dear Magick, you should know the answer (Yes, then how/No, then why/Dunno)
Post Reply