4

So I have a situtation with ImageMagick and php where I need to processes each of the RGB channels separately and then merge them back together into the final image. So in the code I have below, $red, $green and $blue are the channels (as gray scale images). The following code is what I have tried (and a couple variations) but each time I end up with an image that only has Cyan, Magenta or Yellow showing through. In this case, the resulting image is Cyan.

$im->removeImage();
$im->addImage($red);
$im->addImage($green);
$im->addImage($blue);
$img = $im->combineImages(self::CHANNEL_ALL);

$im->removeImage();
$im->removeImage();
$im->removeImage();
$im->addImage($img);

I think part of my problem is that the PHP documentation doesn't say much about how to use combineImages and there are no samples so far as I can find. So it's very likely that I'm using that particular method incorrectly, and I suspect it has to do with how I am combining the images in the single Imagick object to begin with.

EDIT

This question ultimately boils down to this: How do I recreate the following script using only php?

convert tmp_r.png tmp_g.png tmp_b.png -combine tmp_rgb.png
gregghz
  • 3,925
  • 7
  • 40
  • 69
  • 1
    I have spent all evening trying to this to work and I always end up with a red or gray image. After a few hours I began to think addImage is wrong as this looks like it is for gif animations. I found a post on the Imagemagick forum suggesting compositing instead. I can not get my head around how Imagick works as the documentation is totaly useless and misleading. – Bonzo May 31 '12 at 21:18
  • 100% agree about the documentation .... – gregghz Jun 01 '12 at 13:57
  • where did you find that post? – gregghz Jun 04 '12 at 17:45
  • 1
    There is not very much info and it was in the rmagick section of the forum: http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=9003&hilit=combineImages I have spent all weekend trying to create an example of all the Imagick operators to put on my website but am stuck now with the ones without very good documentation! – Bonzo Jun 04 '12 at 17:50
  • Is there any particular reason you're forcing yourself to use the PHP Imagick extension rather than just using a shell command? – WWW Jun 04 '12 at 20:28
  • The idea here is that PHP is being used as the base implementation. This is going to be ported to a couple other ImageMagick libraries for other purposes on platforms that may not have access to shell commands (think mobile devices). – gregghz Jun 04 '12 at 20:36

3 Answers3

4

[EDIT] I have to admit, looking further into the documentation, Im not sure what the constant CHANNEL_ALL does. They do state that you can concatenate channels by logically ORing them together. You might try:

$im->combineImages(imagick::CHANNEL_RED | imagick::CHANNEL_GREEN | imagick::CHANNEL_BLUE);

[ORIGINAL] I've been looking into this API, and honestly what I think you are looking for is the convert function, NOT the combine function.

Look At the below provided link and click specifically on "Combining RGB Channel Images" http://www.imagemagick.org/Usage/color_basics/

Try that, leave a comment if you need further help :-)

trumpetlicks
  • 7,033
  • 2
  • 19
  • 33
  • convert is the program that image magick provides for use at the command line. -combine is the specific functionality of convert that I am attempting to replicate. – gregghz Jun 04 '12 at 19:10
  • Thats why I edited my post with the EDIT. try using the concatenation of the three color channel s rather than the CHANNEL_ALL in the call you are already making!!! – trumpetlicks Jun 04 '12 at 19:13
  • sorry, the flow of your answer got a little mangled, I got confused about what you were suggesting first. But yes, I did try that as well with the same results. – gregghz Jun 04 '12 at 19:24
  • btw, I believe self::CHANNEL_ALL sets the flag for all the channels listed at http://us2.php.net/manual/en/imagick.constants.php whereas ORing obviously only sets it for the RGB channels. The dec value of ALL is -1 (which is all 1's in binary) and ORing RGB gives 7 (which is 0b111). I think ORing is probably preferable since most of the channels have no representation in my case. Either way, it's exhibiting the same behavior. – gregghz Jun 04 '12 at 19:33
  • YES, but all might include CMYK which is why you are seeing CYAN. Have you just out of curiousity looked at the output of the getColorspace routine for the $red, $green, and $blue images are? Also are you sure of what "self" is pointing to at that moment (to know that self::CHANNEL_ALL is truly going to give you the in you want)? – trumpetlicks Jun 04 '12 at 19:45
  • yeah, you're right. It certainly does include CMYK, Alpha, Opacity and a couple others I believe. $this/self are in the context of a class that extends Imagick. Also, I believe I have found the solution. It appears that (self::CHANNEL_ALL) vs. (self::CHANNEL_RED|self::CHANNEL_GREEN|self::CHANNEL_BLUE) produce identical output. I'm going to post my findings as an answer shortly. – gregghz Jun 04 '12 at 20:08
  • Good for you, I hope some of the comments on here helped aid your path :-) Ill be looking forward to seeing your answer. – trumpetlicks Jun 04 '12 at 20:14
3

So I think I've figured out how to get this to work. The missing piece was a call to flattenImages(). I'm not exactly sure why this worked, but it seems to be what I was looking for. Here's the code (keep in mind that $this is in the context of a member method of a class that extends Imagick):

$this->removeImage(); // gets rid of the old, unprocessed image
$rgb = clone $this;

$rgb->addImage($red);
$rgb->addImage($green);
$rgb->addImage($blue);
$rgb->flattenImages(); // this is what was missing above

$rgb = $rgb->combineImages(self::CHANNEL_ALL);

$this->addImage($rgb);

Can anyone comment on why this might be? I expected flattenImages() to merge the three images into one and destroy some of the information, but it appears that it actually tells ImageMagick to process all of the contained images together whereas it was processing them independently previously.

gregghz
  • 3,925
  • 7
  • 40
  • 69
  • I think I have an IDEA. Have you tried displaying the $rgb WITHOUT running the combineImages routine? What I think is somehow going on is that all of the $red, $green, and $blue images are coming in as either a 24 or 32 bit images, where $red has the pixels going from 0x000000 to 0xFF0000, the green is from 0x000000 to 0x00FF00, and the blue is 0x000000 to 0x0000FF. Flatten image essentially adds the layers. So instead of true grayscale they are somehow coming in as RGB with the color aligned. Just a thought :-) – trumpetlicks Jun 04 '12 at 21:10
  • Interesting thought, unfortunately, the call to combineImages() is apparently very important. When I tried it without that call, I get a totally grayscale image. combineImages() is the secret sauce that turns grayscale into color. – gregghz Jun 04 '12 at 21:29
  • 1
    When I was trying to solve it, I found that the color of the resulting image (when just calling `addImage()` multiple times then `combineImages()`) changed between cyan, magenta, and yellow, so I was attacking it from a colorspace perspective. Having to "flatten" the images kind of makes sense in that I believe MagickWand treats `addImage()` as just adding an image to a list, not as actually combining images, and `combineImages()` was only doing anything to the last image added. Flatten told the MagickWand instance to operate on all added images at the same time. – WWW Jun 05 '12 at 13:35
-1

Try this:

$im->addImage($red);
$im->addImage($green);
$im->addImage($blue);
$im->combineImages(imagick::CHANNEL_RED | imagick::CHANNEL_GREEN | imagick::CHANNEL_BLUE);

btw combineImages doesn't return imagick object, but true/false indicating success or failure, so $im will contain your combined image.

Edit: Apparently combineImages sucks big time, so here's an alternative: imagick::compositeImage

$im->compositeImage($red, imagick::COMPOSITE_COPY, 0, 0, imagick::CHANNEL_RED);
$im->compositeImage($green, imagick::COMPOSITE_COPY, 0, 0, imagick::CHANNEL_GREEN);
$im->compositeImage($blue, imagick::COMPOSITE_COPY, 0, 0, imagick::CHANNEL_BLUE);
c2h5oh
  • 4,492
  • 2
  • 23
  • 30
  • according to http://us2.php.net/manual/en/imagick.combineimages.php, combineImages *does* return an Imagick object and not a bool. I tried this with both method though with no luck. Assuming it returns a bool, after the call to combineImages, I get a grayscale image (I assume the blue channel), and assuming it returns Imagick, I get a cyan shaded images. – gregghz Jun 04 '12 at 19:08
  • The very page you have linked has "Returns TRUE on success." under Return values label. Added another function that can be used. – c2h5oh Jun 04 '12 at 20:17
  • 1
    @c2h5oh greggory.hz is correct. 1) the docs are horrible for the Imagemagick extension (it's all copy/pasted from the MagickWand docs), 2) the *description* on that page states that the function returns an `Imagick` object, 3) you don't seem to have actually tried your own code. – WWW Jun 04 '12 at 20:25
  • will the compositeImage method convert the grayscale images into corresponding RGB channels the way -combine does? – gregghz Jun 04 '12 at 20:40
  • In general compositeImage is used for various types of blending. With imagick:COMPOSITE_COPY "blending" is actually copying over - each line should copy the grayscale image over one channel. – c2h5oh Jun 04 '12 at 21:07
  • 1
    So I tried it and it's still a totally grayscale image. I think this is because it's just copying the specified color channel and not using the grayscale image ($red/$green/$blue) as a magnitude of that color channel. That's what combineImages() does. Did you try any of your solutions with different results? – gregghz Jun 04 '12 at 21:33