Page 1 of 1

Layering with different geometry

Posted: 2013-04-18T09:17:11-07:00
by galv
I have: convert a.gif b.gif c.gif e.gif g.gif z.gif +append append.png

convert a.gif b.gif c.gif e.gif g.gif z.gif -geometry south +append append.png => will apply geometry south to all images
I want to apply different geometries on different images, how can I accomplish that?

I want a b c z with "south", but g with "north" geometry.

Re: Layering with different geometry

Posted: 2013-04-18T09:33:39-07:00
by fmw42
You will have to append them one at a time to build up the final image.

Or use
-page ... -mosaic

or
-gravity ... -compose over -composite

to composite them all at the correct locations.

see
http://www.imagemagick.org/Usage/layers/#convert
http://www.imagemagick.org/Usage/layers/#mosaic

Re: Layering with different geometry

Posted: 2013-04-18T09:37:26-07:00
by galv
Thanks Fred.
What's the fastest way out of these (in processing time)?

Re: Layering with different geometry

Posted: 2013-04-18T13:58:02-07:00
by fmw42
It is not really a question of speed, but convenience.

Doing multiple appends is not really helpful unless you can script a loop over all your images and save each append.

Using -mosaic, does not need to have a background image, but you have to use -page relative to the upper left corner of your desired output but you can specify all images with one -mosaic.

Using -compose over with -gravity and -geometry is the easiest, but you have to do the composite for each image and you must build your background image. However, you can build it as big as you want and then use -trim at the end to cut out excess.

If you are on Linux, Mac, you could use pipes to do the append in one command line.

convert image1 image2 -gravity ... +append miff:- | convert - image3 -gravity ... +append miff:- | ... | convert - imageN -gravity ... +append output

I do not know if Windows supports piping, but you can try if you are on Windows.

Re: Layering with different geometry

Posted: 2013-04-18T21:19:34-07:00
by anthony
First... it is gravity not geometry.

Second... Layering is the major alturnative allowing you to position images by seting the 'virtual canavs offset' (known for hisorically reasons as 'page').

For example... setting the location of 12 'rose' images (or however many you want!)

Code: Select all

convert  rose:  -duplicate 11 \
            -set page '+%[fx:100*cos((t/n)*2*pi)]+%[fx:100*sin((t/n)*2*pi)]' \
            -layers merge +repage rose_circle.png
Image

This uses the image index 't' divided by the number of images 'n' to calculate an angle in radians. that is used to then position the image in a circle using sin() and cos() and radius 100, setting the offset to the top-left corner of the image using -set page. The -layers merge then merges the images relative to each other regardless of if the offsets are positive or negative, and the +repage removes any resulting negative offset.

Hmmm.. that is probably one of the BEST examples of programmed positioning I have yet seen!
And I just thought it up on the spot.

I have to put a simular this in IM Examples, Layering. (to appear in a few hours)
http://www.imagemagick.org/Usage/layers/#layer_calc

This just proves that my effort to ensure that 't' image indexing works was a good idea and just how useful it is. The same goes for having a '-layers merge' operation that does not care whether offsets are positive or negative.

Warning, while the above example does not show it. the last image (just above the right-most image) will always be on top of all the rest, to make a true cyclic overlap you would probably have to generate the image twice so that you can set the last image over the second last, but under the first (zeroth) image. That would really be tricky!

Re: Layering with different geometry

Posted: 2013-04-18T21:52:27-07:00
by snibgo
Not too tricky. Windows script:

Code: Select all

"%IMG6846%convert" ^
  rose: ^
  -duplicate 11 ^
  -set page "+%%[fx:75*cos((t/n)*2*pi)]+%%[fx:75*sin((t/n)*2*pi)]" ^
  ( -clone 0 -set page +0+0 -crop 100%%x50%%+0+0 -set page +75+0 ) ^
  -layers merge +repage ^
  rose_circle.png

Re: Layering with different geometry

Posted: 2013-04-18T22:06:15-07:00
by anthony
With the power of IM doing the work behind it ... very simple!

Before the ability to use 't' in FX expressions (fixed in IM v6.6.8-10, 27 March 2011) you needed to use what I am now calling a two-staged, streaming images approach, so you can do position calculations outside IM

See IM Examples, Programmed Positioning of Images
http://www.imagemagick.org/Usage/layers/#layer_prog

It was quite complex, and probably very hard to translate to Windows.

The previous example of using 't' was
Animated Distorts - distorting multiple image based on image index
http://www.imagemagick.org/Usage/anim_mods/#distort

This new example is much better and far more dramatic.

Re: Layering with different geometry

Posted: 2013-04-18T23:29:47-07:00
by anthony
Note this 'calculated' method is not good for generating the equivelent of an Append, as in that case the position depends on the position and width of every other image before it.

However in fixing the 't' and 'n' FX Expressions, I also allowed FX expressions to be able to access 'image attributes' from any other images in the list, including the images before it. What attributes it has access to is currently limited, but it is posible to craete a DIY append...

Hmmm, First looking at using the attribuets of the previous image...

Code: Select all

   convert -size 20x10 xc:red   -size 50x10 xc:green  -size 30x10 xc:blue \
               +repage -set page ']+%[fx:s[-1].w]' \
               info:

xc:red[0] XC 20x10 0x0+20+0 16-bit sRGB 0.000u 0:00.219
xc:green[1] XC 50x10 0x0+20+0 16-bit sRGB 0.000u 0:00.080
xc:blue[2] XC 30x10 0x0+20+0 16-bit sRGB 0.000u 0:00.080
Well it worked, but the result is not right... the 'image' width is always 20! That is the first images 'w' value!

Oh okay a s[image_index] is not relative to the current image 's' but to the start of the list! okay.
Attempt two...

Code: Select all

  convert -size 20x10 xc:red   -size 50x10 xc:green  -size 30x10 xc:blue \
               +repage -set page '+%[fx:s[t-1].w]' \
               info:
xc:red[0] XC 20x10 0x0+20+0 16-bit sRGB 0.000u 0:00.009
xc:green[1] XC 50x10 0x0+20+0 16-bit sRGB 0.000u 0:00.009
xc:blue[2] XC 30x10 0x0+50+0 16-bit sRGB 0.000u 0:00.009
that worked! though the image -1 (from t-1 for the first (zero index) image above) should be the 'last' image (image index -1) still gets the value from the first image -- that is a bug!

So lets try setting the page to the previous images 'x' offset plus that images with, setting that images x offset

Code: Select all

  convert -size 20x10 xc:red   -size 50x10 xc:green  -size 30x10 xc:blue \
               +repage -set page '+%[fx:s[t-1]page.x+s[t-1].w]+0' \
               info:
xc:red[0] XC 20x10 0x0+20+0 16-bit sRGB 0.000u 0:00.010
xc:green[1] XC 50x10 0x0+40+0 16-bit sRGB 0.000u 0:00.000
xc:blue[2] XC 30x10 0x0+90+0 16-bit sRGB 0.000u 0:00.000
YES! replace info: with -layers merge and you have a DIY append
(using relative position, and not calculating the exact position due to first image handling)

Code: Select all

 convert rose: netscape: granite: \
               +repage -set page '+%[fx:u[t-1]page.x+u[t-1].w]+0' \
               -background DodgerBlue -layers merge +repage show:
Lesson: When using a image index, whether the image is u,v, or s does not matter! You much use 't' to specify a relative image index.

BUG: u[-1] is accessing the first image, not the last image as it is supposed to according to documentation.


Getting back to the OP. now that you have an programmed append, you can adjust the 'Y' offset, as you like. Of course finding the 'maximum height' of all the images in the one command is still a problem, but one that could be solved by generating a intermediate image that discovered the maximum height of all the images. Perhaps though more 'incremental' settings, and multiple setting runs.

Hmmmm get the maximum height!

Code: Select all

convert  rose: netscape: granite: \
       -set page '+0+%[fx:max(u[t-1].h,s.h)]' \
       -set option:my:max_height '%[fx:u[n-1].page.y]' \
       -format '%[my:max_height]\n' info:
So just set all image to that maximum offset, then reset all images but e.gif image ( image index 4, counting from zero) to 0, and set that image to the hight adjusted offset. You can then do the DIY append (preserving the vertical offset (using '%Y' instead of '%[fx:page.y]'

Code: Select all

convert a.gif b.gif c.gif d.gif.e.gif z.gif \
            -set page '+0+%[fx:max(u[t-1].h,s.h)]' \
            -set option:my:max_height '%[fx:u[n-1].page.y]' \
            -set page '+0+%[my:max_height]' \
            -set page '+0+%[fx:t==4?page.y-h:0]' \
            -set page '+%[fx:u[t-1]page.x+u[t-1].w]+%Y' \
            -background DodgerBlue -layers merge +repage show:
This works, and is VERY fast, except for the first (zero image) see below...

Note the last step could be combined with the second last.



PS: the above works, but seems to go wrong for image index 0. As

Code: Select all

-set page '+0+%[my:max_height]'
did not set the value into the first image. Again I don't know why.

In a similar way instead of using

Code: Select all

-set option:my:max_height '%[fx:u[n-1].page.y]' \
-set page '+0+%[my:max_height]'
I would have thought I could assign it directly using

Code: Select all

-set page '+0+%[fx:u[n-1].page.y]'
but all images except the last gets a value of zero!

This is all new territory and as such I am certain we are finding some new bugs.

Re: Layering with different geometry

Posted: 2013-04-19T00:13:22-07:00
by anthony
This ability to access attributes of other images, also includes the pixel data of other images.

That means you could position a list of images according to say values found in the first (or last) image in the list, though that 'mapping' image would also be re-positioned.

How useful 'mapped positions' would be is another matter. It is just another possibility :D