Compose image with mask image using ImageMagick - image-processing

Suppose I have some image a.jpg and some other image b.jpg.
The desired output out.jpg should be obtained by copying all the pixels from b.jpg that are not black onto a.jpg, all other pixels shall remain untouched.
I tried using composite but had no success whatsoever.

EDITED TO ADD: A solution here can be quite simple and generic, but going forward, please remember to always include your version of ImageMagick and which OS or platform you're working on. There are some syntax differences that can make that important.
At the very simplest, using ImageMagick v6, you should be able to do something like this...
convert b.jpg -background none -transparent black a.jpg +swap -composite out.jpg
That reads in the B image, changes all the pure black pixels to transparent, then reads in the A image, swaps the images so they're in the right order, then composites the modified B image over the A image and writes the output.
You can add a fuzz value like "-fuzz 5%" ahead of the "-transparent" operation to expand the selection to include near-black pixels, also.
To use with IMv7 change "convert" to "magick".

Related

Blur part of an image only

I would like to blur only a part of an image. The part to blur is always rectangular, so that I can easily use the following command:
magick source.jpg -region 1000x1000+0+500 -blur 0x20 result.jpg
This works, but is pretty slow for large images. Since I have to process thousands of files again and again, this will simply take too long.
Therefore, I decided to do the blurring by downscaling and upscaling the image back to the original size. However, since this will blur the full image, I have tried to accomplish the task using the following steps:
take the original image as background
create a copy of the original image
blur the copy using down-/upscaling
crop the desired region from the blurred copy
compose the original and the blurred&cropped copy
I am already pretty close (I hope), but when composing the two images, the cropped image will always be positioned in the top-left corner of the original image - instead of the original position from the source image. This is my current command:
magick source.jpg ( -clone 0 -resize 5% -resize 2000% -crop 1000x1000+0+1000 ) -composite result.jpg
I have read in the documentation that the original canvas size will be retained when using the -crop operation, and that this size and position will be used when using -composite. However, this doesn't seem to work in my case. Does anyone have an idea why?
I have tried to use -repage, -extent and other options to define the size and position of the cropped image, but to no avail so far.
I would try -flatten in your command as that is used for layers.
You can do it with a mask image (of any shape) in ImageMagick. Though I am not sure if that will be faster than your scaling method.
Input:
Mask:
(note: blurring occurs where mask is black)
magick lena.jpg -write-mask mask.png -blur 0x3 +write-mask lena_blurred.png
Result:

Preserving PNG transparency during a simple transformation in imagemagick

Task: i have an input png file (many actually, but i'll just loop the solution). It is 16x16 PNG, 32bit with partial transparency along edges.
It so happens that toolbar of a certain stupid platform requires 17x17 files. My problem is that imagemagick kills transparency when doing simple transformations.
So:
Sanity check:
convert add.png PNG32:add_COPIED.png
creates another 16x16#32bpp file. So far so good.
Transformation (gravity is fine):
convert add.png -extent 17x17 PNG32:add_17.png
creates a file with solid white background. That's not good.
What doesn't work:
I tried a serious number of combinations of transparent, transparent-color, background, alpha and flatten. Got nowhere.
What does work:
convert address_book.png -alpha Extract address_book_MASK.png
convert address_book.png -extent 17x17 PNG32:address_book_17.png
convert address_book_MASK.png -background black -extent 17x17 address_book_MASK17.png
composite -compose CopyOpacity address_book_MASK17.png address_book_17.png PNG32:address_book_FIN.png
While i have a working set of commands and I can get through the day, I honestly believe that this is the wrong way to do things - four commands that create 3 intermediate files that i need to delete later. Surely it can be done in a better way?
Set the background colour before changing the extent:
convert input.png -background none -extent WxH result.png

ImageMagick command-line gradient

I'm using an example for ImageMagick's gradient found here:
http://www.imagemagick.org/Usage/photos/#tilt_shift
The arguments are as follows:
magick convert beijing_contrast.jpg -sparse-color Barycentric "0,0 black 0,%h white"-function polynomial 4,-4,1 beijing_blurmap.jpg
It creates a perfect gradient image with white at the top and bottom:
But I can't figure out how to do the same thing for portrait image (make white at the left and right edges).
Please help.
In Imagmagick, just change the arguments to sparse-color. Use %w,0 rather than 0,%h. Note also that in Imagemagick 7, you should use just magick and not magick convert and not convert. Otherwise, you may get IM 6 behavior. For other tools such as identify and mogrify and montage, etc, you do need to preface those with magick. Note also you are missing a space before -function. Try
magick beijing_contrast.jpg -sparse-color Barycentric "0,0 black %w,0 white" -function polynomial 4,-4,1 beijing_blurmap.jpg
If needed, swap the black and white depending upon whether you want it white in the middle or black in the middle.
For IM 6.9.2.5 or higher, there are new convenience defines for creating various directional gradient. But you need to specify the image size. See https://www.imagemagick.org/script/gradient.php

Specify endpoints of lines by percentage of image size

I'm trying to draw the stretch bars on various sizes of ninepatch images. I'm doing this in a script, and I'd like to be able to specify a different master image or scale it to a different size without manually recalculating all the pixel coordinates of the lines I'm drawing on it. Is there a way to specify the endpoints of lines as a percentage of the image size? I tried this, which does not work:
convert -draw 'line 0,45% 0,55%' $myfile tmp~ && mv tmp~ $myfile
I had hoped this would draw a line along the middle 10% of the left side of the image. It does draw a line, but it ignores the percents and draws the line from 0,45 to 0,55 regardless of the image size.
If this is not possible with ImageMagick, is there another Linux command-line tool I could use?
I don't believe you can do that using percentages, but you can get it pretty succinct and avoid having to do any calculations using bash or bc or somesuch by using ImageMagick's built-in fx operator to calculate the line position as a function of the image height.
The best I can come up with is this:
linespec=$(convert image.jpg -format "0,%[fx:int(h*0.45)],0,%[fx:int(h*0.55)]" info:)
convert image.jpg -stroke red -strokewidth 32 -draw "line $linespec" image.jpg
Of course you can replace image.jpg with a variable, and you can also make it an (ugly) one-liner by putting the first command in the middle of the second if you really want to.
Note also, that there is no need to create a temporary image and rename like you do - you can just draw on your original like I have.

ImageMagick treating JPG and GIF differently in -alpha shape

I just encountered unexpected behavior in ImageMagick, which I'm hoping someone can explain to me.
Version numbers
$ convert --version
Version: ImageMagick 6.7.7-10 2013-02-25 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenMP
Running on Linux Mint 15 Olivia (based on Ubuntu 13.04 "Raring Ringtail").
Executive summary
Running the same operation with two images that should be quite similar, except that one is a GIF while the other is a JPEG, the resulting output is entirely different. The GIF comes out black, the JPEG comes out white.
To reproduce:
Go to http://karenswhimsy.com/public-domain-images/animal-silhouettes/animal-silhouettes-1.shtm and download the elephant silhouette as elephant.jpg
Download http://www.arthursclipart.org/silhouettes/animals/DUCK1.gif as DUCK1.gif
convert elephant.jpg -negate -alpha shape output-elephant.png
convert DUCK1.gif -negate -alpha shape output-duck.png
Compare the output-elephant.png and output-duck.png images
Can anyone explain why these two output images are different? Why the GIF duck ends up being black after conversion, while the JPEG elephant becomes white after conversion?
Long-winded explanation
The situation is this: I want to take some black-and-white images, turn the background transparent, and turn the foreground different colors. For example, starting with the elephant silhouette at http://karenswhimsy.com/public-domain-images/animal-silhouettes/images/animal-silhouettes-1.jpg (I saved the image as elephant.jpg), I want to produce a .png with a transparent background and an elephant that's green, red, yellow, or whatever color I want.
The command I'm using to do this is:
convert elephant.jpg -negate -alpha shape +level-colors ,green green-elephant.png
This does exactly what I want. First it inverts the image so that the background is black and the elephant is white, because -alpha shape expects an alpha mask where black = fully transparent and white = fully opaque. Then -alpha shape does its magic and produces a white elephant against a transparent background. Then +level-colors ,green kicks in, transforming black-and-white gradients into the two colors specified as parameters to +level-colors; here, the first color is omitted so it would remain black, and the second color is what white turns into. This produces a green elephant with smooth borders -- exactly the result I want -- and I'm quite happy with it.
Next, I tried running the same command against one of the images from http://www.arthursclipart.org/silhouettes/animals.htm (I used DUCK1.gif). The input source is the same -- a black silhouette against a white background -- so I expected the same result, a green duck against a transparent background. But it didn't work. A little research showed me that -alpha shape was behaving differently. Where with the JPEG elephant it was producing a white elephant against a transparent background, with the GIF duck the same command was producing a black duck against a transparent background. In other words, -alpha shape was inverting the result with a GIF image source, but not with a JPEG image source. So to color the animal properly, I needed to rewrite the +level-colors parameters to put "green" before the comma instead of after.
Tweaking my script is no problem at all, but I'd love to understand why this is happening, and so far I'm clueless. Can anyone explain to me why ImageMagick is treating GIFs and JPEGs so differently in the -alpha shape operation?
OK, I think here is the story. With GIF, a background color might be explicitly defined, and I think that is the case with DUCK1.GIF. Not so with JPEG; here the background is, I think, assumed to be "white".
Whatever the case is, converting the DUCK1.GIF to DUCK1.JPG results in a similar image to the elephant. Moreover, you can make sure that the same background color is used with the apropriate Imagemagick option. The two commands below produce similar output:
convert DUCK1.jpg -background Black -negate -alpha shape output-duck.png
convert elephant.jpg -background Black -negate -alpha shape output-elephant.png

Resources