Perspective distortion rendering - ImageMagick - imagemagick

whenever we apply some transformation using imagemagick convert command , it tries to ensure that the resulting image is of the same size as that of the original image . is there a way such that we get the whole rendered image with transparent/white background .
convert -verbose maanavulu_GIST-TLOTKrishna.tif \
-alpha set -matte -virtual-pixel transparent \
-distort perspective-projection '1.06,0,0.0,0,2.066,0.0,0.0,0.0' \
1.jpg

There's some tricks with fx & repage hinted at by the Distorting Usage documentation. I've found the easiest approach would be to set option:distort:viewport option to something large enough to capture the whole distortion, then -trim it to the finial size.
convert -verbose maanavulu_GIST-TLOTKrishna.tif \
-alpha set -matte -virtual-pixel transparent \
-set option:distort:viewport 1000x1000 \
-distort perspective-projection '1.06,0,0.0,0,2.066,0.0,0.0,0.0' \
-trim 1.jpg

Related

How to pass Imagemagick montage output and image properties to the convert command without using any temporary files?

I have a set of images, and I can use the Imagemagick montage command on them to produce a montage image file with transparent background (let's call this fgimg). Now I have another existing image (let's call this bgimg) that I'd like to use (after some special processing with the convert command) as the background for fgimg, which can be achieved within the same convert command. At this point it seems trivial to avoid writing the temporary fgimg to disk, simply by piping the standard output of montage to the standard input of convert.
My problem is that the special processing I'm applying to bgimg will require some knowledge of the image properties of fgimg (e.g., resizing bgimg to have the same size as fgimg), which I don't know in advance. How can this information be retrieved and used in the convert command?
Note: I'm using Imagemagick version 6.9.7-4 on Linux.
I'll include some commands below to further illustrate the problem in detail.
The following command produces the montage image fgimg from a set of input images. The output is in the 'special' miff format (which seems best for temporary output to be worked on later), and has transparent background so that the actual background can be applied later. Most of the other options here are not important, but the point is that the output size (dimensions) cannot be determined in advance.
montage input_*.jpg -tile 5x -border 2 -geometry '200x200>+20+20' \
-gravity center -set label '%f\n%G' -background none -fill white \
-title 'Sample Title' miff:fgimg
Next, I have another input image bgimg.jpg. I want to perform some processing on it before using it as background to fgimg. The processing can be quite complex in general, but in this example, I want to:
resize bgimg.jpg to fit inside the dimensions of fgimg without any cropping;
apply a fade-to-black effect around the edges;
make it the same size as fgimg, with a black background;
combine this with fgimg to produce the final output.
Notice that I need the size of fgimg in two places. I can first extract this into a shell variable:
size=$(identify -format '%G' miff:fgimg)
Then I can do all the steps above in one convert command (note that $size is used twice):
convert "bgimg.jpg[$size]" -gravity center \
\( +clone -fill white -colorize 100% -bordercolor black \
-shave 20 -border 20 -blur 0x20 \) -compose multiply -composite \
-background black -compose copy -extent $size \
miff:fgimg -compose over -composite final_out.jpg
Now here is the problem: I want to avoid writing the temporary file fgimg to disk.
I could replace miff:fgimg with miff:- in both the montage and convert commands and then just pipe one to the other: montage ... | convert .... But how do I deal with the $size?
I tried to use file descriptors (miff:fd:3) but this does not seem to work, which is confirmed by the comments to this question.
Is there a way to do this (in Imagemagick v6) without creating a temporary file?
This example command uses ImageMagick v6 on a bash shell. Instead of "montage" it starts by using "convert" to create a "logo:", one of IM's built-in sample images, then pipes it out as a MIFF and into the "convert" command that follows. You can pipe the output of "montage" just as easily. And it uses another IM built-in image "rose:" as your "bgimg.jpg"...
convert logo: miff:- | convert - rose: \
+distort SRT "%[fx:t?min(u.w/v.w,u.h/v.h):1] 0" \
-shave 1 +repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap -composite final_out.jpg
That reads the piped image "-" and the background image "rose:".
Then it uses "+distort" with an FX expression to scale "rose:" to the maximum dimensions that still fit within the original piped input image. That operation adds a pixel all around so we use "-shave 1" to get rid of that.
Next inside parentheses it clones that re-scaled background image, makes an edge blur mask, and composites them to make the fade-to-black edge on the background image. Right after the parentheses it deletes the non-edged background image.
In the next parentheses it clones the input image, makes it black, clones the modified background image, and composites it centered over the black one. Again the non-extended background image is discarded after the parentheses with "-delete 1".
Finally the modified background and the input image are put in the proper order with "+swap" and composited for the final output. Run this command without the last "-composite" to see the two images that result from the prior parts of the command.
Both the main input image and background image can be any size, any dimensions, and any aspect ratio. This works for me on v6.8.9 on a bash shell. It should work on any ImageMagick newer. It should work on Windows by removing all the backslashes that escape parentheses and changing the continued-line backslashes "\" to carets "^".
EDITED TO ADD:
You can use that FX expression to find the scaling amount, save it as a variable, then isolate the background image inside parentheses and use that variable to do the scaling and shaving there. That way it only affects the background image. There may be a rounding error with that, but the main image, which determines the exact final output dimensions, will be unaffected. Note the difference in the first few lines of this command...
convert logo: miff:- | convert - rose: \
-set option:v1 "%[fx:min(u.w/v.w,u.h/v.h)]" \
\( -clone 1 +distort SRT "%[v1] 0" -shave 1 \) -delete 1 \
+repage -gravity center -bordercolor black \
\( -clone 1 -fill white -colorize 100 -shave 6 -border 6 \
-blur 0x6 -clone 1 -compose multiply -composite \) -delete 1 \
\( -clone 0 -alpha off -fill black -colorize 100 \
-clone 1 -compose over -composite \) -delete 1 \
+swap final_out.jpg

Assembling an image from parts of others with ImageMagick (image crop syntax)

I have a set of source PNG images and I want to use parts of them to assemble a final PNG image. The parts are rectangular and never overlap on the destination but are of different sizes. Sometimes it is the whole of a source image and sometimes just a subsection. I want to edit the sources many times and re-assemble the final image each time, so I tried to write a script using sh and Imagemagick to do it.
I tried this
convert \
-size 512x512 null:\
-page +96+32 source_a.png\
-page +96+0 source_b.png[32x32+16+16] \
-background transparent\
-layers merge\
destination.png
(just with two source images for illustration)
I want all of source_a.png and a piece of source_b.png. The first is OK, but using the 'inline crop' syntax on source_b.png gives me an error:
convert: geometry does not contain image `source_b.png' # warning/transform.c/CropImage/666.
The image is big enough:
$ identify source_b.png
source_b.png PNG 64x48 64x48+0+0 8-bit sRGB 3.7KB 0.000u 0:00.000
What's the best way to do this? I am using ImageMagick 6.9.7-0 Q16 on MacOS 10.12
An alternative might be to use -geometry and -composte to achieve the same effect:
convert -size 512x512 xc:white \
source_a.png -geometry +96+32 -composite \
source_b.png[32x32+16+16] -geometry +96+0 -composite \
result.png
PNG's will preserve the paging from inline cropping, so the addition page will through the ROI out of bounds. I imaging it'll be simpler to -repage the inline crop then attempting to clear previous paging & setting new page.
convert -size 512x512 null: \
-page +96+32 source_a.png \
\( source_b.png[32x32+16+16] -repage +96+0 \) \
-background transparent\
-layers merge\
destination.png

Removing background using imagemagick, on a white product

Here's the original image I'm trying to remove background from:
I am trying to use imagemagick to remove the background from an image. When the image has a white product, my script doesn't work well. It removes the white from inside the product also. In brief I'm trying to do the following
create a mask image (replace background pixels with white with fuzz and threshold)
apply the mask over the original image to generate the output
If I use a fuzz factor of 0, like shown below, i get the background removed, but it creates a nasty halo around it. What can be done here?
I would take advantage of HSL colorspace, and create an alpha mask from the lightness channel.
convert tshirt.jpg \( \
+clone -colorspace HSL -separate \
-delete 0,1 -fx 'u>0.975?0:1' \) \
-compose CopyOpacity -composite \
out.png
I would go for a simple threshold to pick out the white and then some sort of filtration to remove the noise/ragged edges. So, for example
convert shirt.jpg -threshold 99.99% -negate result.jpg
which gives this:
Then apply some median filtering to smooth it:
convert shirt.jpg -threshold 99.99% -median 5 -negate result.jpg
or maybe a bigger filter:
convert shirt.jpg -threshold 99.99% -median 11 -negate result.jpg
which gives this
Alternatively, you may get on better with an erosion and a dilation...
convert shirt.jpg -threshold 99.99% -negate \
-morphology erode diamond:3 \
-morphology dilate diamond:3 result.jpg
You may like to use Anthony Thyssen's flicker_compare to flicker between the input and result image to see what you have got, see here.
./flickercompare -o flick.gif shirt.jpg result.jpg

RMagick torn edges

I'm trying to create a torn edge effect in RMagick. Is there a filter similar to photoshop's crystallize?
Also, I found this ImageMagick code that does it here http://www.imagemagick.org/Usage/thumbnails/#torn:
convert thumbnail.gif \
\( +clone -alpha extract -virtual-pixel black \
-spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \) \
-alpha off -compose Copy_Opacity -composite torn_paper.png
However, I don't understand any of it. Can anyone provide some advice?
This command does two main things: create a mask with that torn-paper effect, apply the mask to the image. It does them, fancily, in one line, by using +clone and the parentheses. It's less confusing to do it as two commmands though:
convert thumbnail.gif \
-alpha extract \
-virtual-pixel black \
-spread 10 \
-blur 0x3 \
-threshold 50% \
-spread 1 \
-blur 0x.7 \
mask.png
convert thumbnail.gif mask.png \
-alpha off \
-compose Copy_Opacity \
-composite torn_paper.png
The first command is fairly complex. But you can find decent explanations of each of the component commands in the ImageMagick docs:
http://www.imagemagick.org/Usage/masking/#alpha_extract
http://www.imagemagick.org/Usage/misc/#virtual_examples
http://www.imagemagick.org/script/command-line-options.php#blur
Also, by splitting the command into these two pieces, you can see what the mask looks like on its own. It's basically the inverse of the paper effect. White throughout the middle of the images, fading to black around the "torn edges".
The second command is a lot more straightforward. Copy_Opacity, as described in the ImageMagick docs, is a way of making parts of an image transparent or not. Anything that's black in the mask will be made transparent in the resulting image. In effect, the second command uses the mask to "erase" the edges of the original thumbnail in a stylistically interesting way.

Combining multiple images in ImageMagick with relative (not absolute) offsets

I'm looking for the most efficient way to stitch multiple images together in ImageMagick, on top of a background image, such that the spacing / padding between the overlaid images is consistent?
I've investigated use of +append, convert -composite, and convert with -page and -layers merge.
The following command (convert -composite) works, but requires precalculation of image dimensions in order to specify absolute offsets. Really, I want a 10 pixel gap between the end of the FIRST layered image and the start of the second layered image, but the only way I can see to achieve that is by specifying the absolute offset from the top-left corner of the canvas.
convert \
background.jpg \
first.jpg -gravity Northwest -geometry +10+10 -composite \
second.jpg -geometry +300+10 -composite \
third.jpg -geometry +590+10 -composite \
output.jpg
I am looking for some sort of operator so that the horizontal offset can be interpreted relative to the "last" image in the layering, so instead of specifying +300+10 for the second image and +590+10 for the third, I can somehow specify a +10+10 offset.
I thought gravity would allow me to achieve that (-gravity Northwest), in the same way that float: left; works in CSS positioning, but that is not the case.
I have also had some success with the following:
convert \
-page +10+10 first.jpg \
-page +300+10 second.jpg \
-page +590+10 third.jpg \
-background transparent \
-layers merge \
layered.png
convert background.jpg layered.png -gravity Center -composite output.jpg
Both the techniques described require pre-calculation of absolute offsets, which is a bit of a pain. Is there a better way to do this?
You've overlooked the montage command.
The most simple command to add the wanted spacing with it would be to set a -frame 5 option with -mattecolor none. This works with images of different width values and spaces them all apart with a distance of 10 pixels:
montage \
-alpha on \
-background none \
-mode concatenate \
-tile x1 \
-frame 5 \
-mattecolor none \
*.jpg \
output1.png
You'll easily notice however, that the resulting image's border is only 5 pixels wide on top, right, bottom and left. To remove these 5 pixels all around use:
convert output1.png -shave 5 output2.png
To overlay this result on your background.jpg, use:
convert \
background.jpg \
output2.png \
-gravity Northwest \
-geometry +10+10 \
-composite \
final.jpg
You can also use Kurt's transparent frame trick with append. Using append instead of montage has the advantage that you can use gravity settings to align your images top (north) bottom (south) or center.
Here's an example of how to append images horizontally with a 10 pixel gap between them, and with the images top aligned:
convert \
-frame 5 \
-mattecolor none \
-background none \
-gravity north \
first.jpg second.jpg third.jpg \
+append \
png:- | convert - -shave 5
output.png
To append images vertically use -append instead of +append. I've used a pipe | to shave off the outside frame in the same command.

Resources