Page 1 of 2
Repeatedly Resizing by Half
Posted: 2010-07-20T20:35:42-07:00
by russkey
Hello All!
I was wondering if there was some filter or other technique that I should be using to repeatedly reduce a photograph by half? I have already made sure to pad out the image dimensions to ensure that there will always be integer dimensions when divided by two. I suppose I could make some sort of script which just runs through all the possible filters/resize functions, but I hope I don't have to. Any ideas?
Re: Repeatedly Resizing by Half
Posted: 2010-07-20T21:07:21-07:00
by fmw42
No specific function that I know, besides a script. But I am not sure you get any benefit from repeatedly resizing by half as opposed to resizing with a good IM filter, unless you need to save each half size image. I originally thought there was some anti-aliasing benefit to repeatedly resizing, but now I am not sure after some discussions with Anthony. A few tests I made did not show much if any difference, at least visually.
Re: Repeatedly Resizing by Half
Posted: 2010-07-20T22:42:49-07:00
by anthony
Code: Select all
convert input_image.png \
\( +clone -resize 50% \) \
\( +clone -resize 50% \) \
\( +clone -resize 50% \) \
\( +clone -resize 50% \) \
\( +clone -resize 50% \) \
\( +clone -resize 50% \) \
\( +clone -resize 50% \) \
-layers RemoveDups \
output_image_%02d.png
Just repeat the clone/resize enough times to generate all the image 'halves' wanted. For example do it 9 times for a 1024 wide image. (log base 2 of width minus 1).
You can do the resize many more times than nessary as once an image reaches 1 pixel in size the later clone resizes will do nothing. The
-layers RemoveDups will then remove the extra 1 pixel duplicate images that are not needed.
As such just do the clone/resize 16 or more times (equivelent to generating halves of image up to 65535 pixel in size) remove duplicates and save.
The
%02d sepecifys where to place a 2 digit number (starting at 00).
See
Writing a Multi-Image Sequence
ASIDE: the above halfing method was developed to generate a very fast 'Shepards Color Diffusion' technique
http://www.imagemagick.org/Usage/canvas/#sparse_blur
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T05:34:52-07:00
by russkey
Might it be better to tee the original image and resize it by half, quarter, eighth, sixteenth, etc? I've already got the number of iterations required figured out (the smallest image should be the first that is small enough to fit within a specific dimension). To that end, is there a way to tee an image pipeline so that I don't have to keep loading images into memory? Is there an improvement to resizing the original instead of resizing a resized version of a resized version (etc.) ?
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T09:05:26-07:00
by fmw42
Still not sure what you are after. You did not say whether you need to save each size?
If you want to resize by 50, 25, 12.5, etc, you can use clones similar to the way Anthony used above. Clones do not re-read the image from disk.
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T09:50:39-07:00
by russkey
I suppose that I really should give some more background information.
I am making square tiles out of an image at various zoom levels. To this end, I need some sort of representation of the original image at successively halved size until the script is finished. Since I need all of the tiles to be the same size, I pad each intermediate image out to a multiple of the tile width before cropping. If there is a way to have this run all through a single command, that would be perfect. But I need to do the padding math between the resizing and the cropping, so i doubt that would be possible (I could precalculate, but that would only make sense if there's a huge resource benefit).
At the moment I take my original image, pad it out to a size which can be halved the required number of times and still have all integer dimensions. I use the mpc format to speed up loading the image later on
This image is then padded out to the integer multiple of the tile size and cropped into the required tiles
After a bit of housekeeping, i halve the intermediate image and repeat the padding and cropping process.
This creates that firs level image (bash scripts):
Code: Select all
convert"$source" -strip +adjoin -background $background -gravity Center -extent "$padded_width"x"$padded_height" "$outputdir/tmp/level_0.mpc"
This crops the image
Code: Select all
convert "$current" +adjoin -background $background -gravity Center -extent "$padded_width"x"$padded_height" -crop "$tile_size"x"$tile_size" +repage "$leveldir/tile-%d.png"
And here is the code which halves the intermediate images
Code: Select all
convert "$outputdir/tmp/level_$previous_level.mpc" +adjoin -resize 50% +repage "$outputdir/tmp/level_$level.mpc"
So I guess i'm wondering if there's a more efficient way to do all of this? Can I string all of this into a single monster command so that I only have to load the source file once? The code is supposed to deal with fairly large images, so I would like to limit the amount of disk reading it has to do.
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T11:41:16-07:00
by fmw42
One possible solution is to convert to a tiled pyramidal tiff (PTIF:image.tif)
see
http://www.imagemagick.org/Usage/formats/#tiff and
viewtopic.php?f=3&t=12723&p=42377&hilit ... tif#p42377 (for tiling it)
I will look into a compound command line to demonstrate creating it from commands like yours using Anthony's technique above. You can write out the results from each level within the parentheses by using -write.
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T11:57:01-07:00
by fmw42
Try this. I padded an image 756x572 to 1024x1024 and then created tiles of size 256x256 at each 50% reduced level and even went one level too far. It still ran, but the last level is just a reduced version of the L2_0 (thus it is 128x128). You can precompute how many levels you want and just make enough in the command line if you want.
convert \( zelda.png -gravity center -background black -extent 1024x1024 \) \
\( -clone 0 -crop 256x256 +repage -write zelda_L0_%d.png \) \
\( -clone 0 -resize 50% -crop 256x256 +repage -write zelda_L1_%d.png \) \
\( -clone 0 -resize 25% -crop 256x256 +repage -write zelda_L2_%d.png \) \
\( -clone 0 -resize 12.5% -crop 256x256 +repage -write zelda_L3_%d.png \) \
-delete 0 null:
You can change it to write the files to different directories if you want. I just put them all into one but labeled the images with the level.
It was easier for me to resize by 50,25,12.5 rather than successive 50%, but I think it would be possible (but more complicated) to do it that way.
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T18:47:34-07:00
by russkey
Thank you ftmw42 and Anthony, I really appreciate your help!
i've been able to rewrite the script to spit out an argument list that I can then use with xargs:
Code: Select all
convert -monitor -define registry:temporary-path=/var/tmp/image -background #555555 -gravity center \
( bbp.jpeg -strip -extent 5184x3456 ) \
( -clone 0 -resize 5184x3456 -extent 5376x3584 -crop 256x256 +repage -write ./park/level0/tile-%d.png ) \
( -clone 0 -resize 2592x1728 -extent 2816x1792 -crop 256x256 +repage -write ./park/level1/tile-%d.png ) \
( -clone 0 -resize 1296x864 -extent 1536x1024 -crop 256x256 +repage -write ./park/level2/tile-%d.png ) \
( -clone 0 -resize 648x432 -extent 768x512 -crop 256x256 +repage -write ./park/level3/tile-%d.png ) \
( -clone 0 -resize 324x216 -extent 512x256 -crop 256x256 +repage -write ./park/level4/tile-%d.png ) \
-delete 0 null:
I'll post a link to the full script and the veiwer that goes with it as soon as its finalized within the next few days.
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T19:18:09-07:00
by anthony
russkey wrote:Might it be better to tee the original image
-clone does this.
For example resize always from the original image...
Code: Select all
convert input_image.png \
\( -clone 0 -resize 50% \) \
\( -clone 0 -resize 25% \) \
\( -clone 0 -resize 12.5% \) \
\( -clone 0 -resize 6.125% \) \
\( -clone 0 -resize 3.0625% \) \
\( -clone 0 -resize 1.53125% \) \
\( -clone 0 -resize 0.716625% \) \
-layers RemoveDups \
output_image_%02d.png
However if the image is already a power of 2 size. Then you can simply use the original '50%' previous image methdo using -scale instead of resize for a faster method.
Using -scale for power of 2 tiles probably works better with the original solution. As you are generating the tiles, you know how many '-scale 50%' lines you need.
However you final solution will work fine, though it is much slower.
Alturnative.. do the resize, then the tile, then the extent to 'fill out' the tiles. That may be faster or it may be slower.
EG:
Code: Select all
( -clone 0 -resize 324x216 -crop 256x256 +repage -extent 256x256 \
-write ./park/level4/tile-%d.png ) \
WARNING: resizing the original image may produce some minor inaccuracies, as resize is limited to integer size. That is the vertical scale and horizontal scale may be slightly different to roud to the nearest integer. You would not have that problem using -scale with power of 2 tiles.
Also other ways of breaking up images into tiles is posible. One method was in the forums recently where the user wanted to spread the 'short tiles' equally around the edge of the image, rather than only on the right and bottom edges.
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T19:36:33-07:00
by fmw42
Here is the equivalent to my example above, but just scaling by 50%
convert \( zelda.png -gravity center -background black -extent 1024x1024 \
-write mpr:tmp -crop 256x256 +repage -write zelda_L0_%d.png \) \
\( mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L1_%d.png \) \
\( mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L2_%d.png \) \
\( mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L3_%d.png \) \
-delete 0 null:
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T19:55:48-07:00
by anthony
Last time I looked svaing a second (or more) times to
mpr:label wull fail.
Unless things have changed. Hmmm testing....
Code: Select all
convert rose: -write mpr:rose \
-resize 50% -write mpr:rose \
+delete \
mpr:rose show:
Hey it how works!!!! mpr:label is now re-writable! WOW!!!
I would love to know when that was changed, as it makes it a lot more useful!
Re: Repeatedly Resizing by Half
Posted: 2010-07-21T20:06:18-07:00
by anthony
fmw42 wrote:Here is the equivalent to my example above, but just scaling by 50%
convert \( zelda.png -gravity center -background black -extent 1024x1024 \
-write mpr:tmp -crop 256x256 +repage -write zelda_L0_%d.png \) \
\( mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L1_%d.png \) \
\( mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L2_%d.png \) \
\( mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L3_%d.png \) \
-delete 0 null:
that would have a LOT of images in memory before the final null: (no write)
As mpr is now re-writable. the above can be simplified!
Code: Select all
convert zelda.png -gravity center -background black -extent 1024x1024 \
-write mpr:tmp -crop 256x256 +repage -write zelda_L0_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L1_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L2_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L3_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L4_%d.png -delete 0--1 \
null:
If %[fx:...] could access ANY label, you would so be posible to use a user setting to set you a 'level increment' too
http://www.imagemagick.org/Usage/files/#save_escapes
eg: -set filename:level 1
then increment -set filename:level '%[fx: var(filename:level) +1 ]'
and save -write zelda_L%[filename:level]_%d.png
However FX access to labels are not yet available
But then fx number formatting, and string manipulation isn't either. (FX really needs to incorporate something like a 'perl API' delegate for doing calculations

Re: Repeatedly Resizing by Half
Posted: 2010-07-21T20:20:32-07:00
by fmw42
Anthony wrote:As mpr is now re-writable. the above can be simplified!
convert zelda.png -gravity center -background black -extent 1024x1024 \
-write mpr:tmp -crop 256x256 +repage -write zelda_L0_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L1_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L1_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L1_%d.png -delete 0--1 \
mpr:tmp -scale 50% -write mpr:tmp -crop 256x256 +repage -write zelda_L1_%d.png -delete 0--1 \
null:
You are right! I forgot that all the cropped images at each level were still around even though I use -write and so need deleting. I got confused by using the mpr:tmp. That is a subtle point I need to remember. I was simply saved by the null:
Re: Repeatedly Resizing by Half
Posted: 2010-07-27T18:39:29-07:00
by fmw42
Just one other note about automating the method of resizing each level by 50% while keeping the result a multiple of the tile size.
This will automatically pad (like -gravity center) a given level so that the image before resizing by 50% is a multiple of twice the tile size (2*128=256 in this case). I start with an image, which has dimensions of 265x333. When I run the following the resulting image is 256x256 with black padding around the outside evenly on each opposite side. (Note 265/2=132.5 so the next multiple of 128 is 256 and 333/2=166.5 so the next multiple of 128 is 256). The trick is to use -distort SRT 0 (a no-op) with fx computations of the viewport to compute and pad the image
convert monet2.jpg -virtual-pixel black \
-set option:distort:viewport \
"%[fx:(w%256!=0)?ceil(w/256)*256:w]x%[fx:(h%256!=0)?ceil(h/256)*256:h]-%[fx:(w%256!=0)?((ceil(w/256)*256)-w)/2:w]-%[fx:(h%256!=0)?((ceil(h/256)*256)-h)/2:h]" \
-distort SRT 0 -resize 50% monet2_50pct.jpg
