Imagemagick arbitrary size/ratio gradient - image-processing

Is it possible to apply a smooth diagonal gradient overlay from left bottom corner to right upper corner preserving original colors as below?
Might sound as a simple task but the actual image size is not known in prior.

Perhaps this is what you want. Using Imagemagick 6, I create a diagonal gradient with blue in the lower left corner and red in upper right corner and then blend 20%/80% with the original with the gradient.
Imagemagick automatically gets the dimensions of the (cloned/copied) image from %w and %h using the -sparse-color barycentric syntax for creating a gradient. See https://imagemagick.org/Usage/canvas/#diagonal_gradients
input:
convert input.jpg \
\( +clone -sparse-color barycentric '0,%h blue %w,0 red' +write gradient.jpg \) \
-define compose:args=20,80 -compose blend -composite \
result.jpg
In the above, I saved the gradient image just to show it has been created properly:
Alternately, you can set the alpha channel of the gradient to 20% and use compose over.
convert input.jpg \
\( +clone -sparse-color barycentric '0,%h blue %w,0 red' -alpha set -channel alpha -evaluate set 20% +channel \) \
-compose over -composite \
result2.jpg

Related

Gradient over transparent png image with sparse-color has background color

I have this face source image. I'm tyring to add a gradient to the bottom of the picture so it fades out alpha transparent.
Problem is that the transparent source image is not transparent anymore after sparse-color transformation - the transparent area is now black.
This is my cmd so far:
magick convert face.png -alpha set -background none -channel A -sparse-color barycentric "0,%[fx:h*0.90] white 0,%[h] none" +channel face-gradient.png
Here is how you have to do that in Imagemagick. Your image already has an alpha channel. So you have to create a new grayscale gradient image as a mask and combine that with the existing alpha channel. (The -sparse-color is going to write over your existing alpha channel.)
magick face.png \
\( -clone 0 -alpha extract \) \
\( -clone 0 -sparse-color barycentric "0,%[fx:h*0.90] white 0,%[h] black" \) \
\( -clone 1,2 -compose multiply -composite \) \
-delete 1,2 \
-alpha off -compose copy_opacity -composite face-gradient.png

Is there a way to darken an image except for a rounded rectangle in ImageMagick?

To demonstrate.
Original:
After ImageMagick:
I have some ideas:
Duplicate the image, crop the duplicate, then flatten the images together
Reverse mask?
Does anyone have any suggestions?
Although this has been successfully answered, I'll offer another simple approach using IMv6...
convert pasta.jpg -fill white \
\( +clone -evaluate set 25% -draw "roundrectangle 20,20 80,80 15,15" \) \
-compose multiply -composite result.png
After reading in the input image, in parentheses it clones the input and uses -evaluate to set the entire clone to 25% gray. A white "roundrectangle" is drawn on that gray image in the area you want to preserve. The mask looks like this...
Then after the parentheses, that mask and the input image are composited with -compose multiply. That leaves the white rectangle area as it was in the original input, and the rest of the image is multiplied by 0.25, leaving it darkened. The result...
This command should work just the same in IMv7 by changing "convert" to "magick". And it should work as well on Windows CLI by changing the continued-line backslashes "\" to carets "^", and removing any backslashes before the parentheses, so this "\(...\)" to this "(...)".
You can do that in Imagemagick by darkening the whole image, creating a round rectangle mask image, then composite the original with the darkened using the mask image.
Input:
convert pasta.jpg \
\( -clone 0 -brightness-contrast -75,0 \) \
\( -clone 0 -fill white -colorize 100 -fill black -draw "roundrectangle 20,20 80,80 15,15" -alpha off \) \
-compose over -composite \
pasta_rect.jpg
Result:

ImageMagick gradient ratio

How do I adjust the color ratio of a gradient?
I currently use the following to create my gradient.
convert -size 200x600 gradient:none-black output.png
Although at least one acceptable solution has been provided, here are a couple other ideas...
Example 1: This command creates a red-blue gradient of the finished dimensions, crops it into a top and bottom half, resizes them to 40 and 60 percent of the input height, and appends them back to make a single image. What started as the color at the exact vertical center is now at 40% down from the top with clean gradients going up and down from there.
convert -size 200x600 gradient:red-blue -crop 1x2# \
\( -clone 0 -resize 100x40% \) \( -clone 1 -resize 100x60% \) \
-delete 0,1 -append result.png
That splits the gradient image into a top and bottom half, then inside parentheses it resizes each to the required proportion. After that it deletes the 50/50 crops from before the parentheses, appends the two resized remaining images, and writes the output.
Example 2: This next example starts by creating the red-blue gradient in the final dimensions, then sets variables to hold the top color, the exact middle color, and the bottom color.
Then inside the first parentheses it clones and crops the image to 60% its original height. It uses "-sparse-color" to fill that with a gradient from "color1" to "color2".
Inside the second parentheses it clones and crops the image to 40% its original height, and using "-sparse-color" again it fills it with a gradient from "color2" to "color3".
After creating those two gradients, delete the original, append the other two together, and write the output.
convert -size 200x600 gradient:red-blue \
-set option:color1 "%[pixel:p{0,0}]" \
-set option:color2 "%[pixel:p{0,h/2}]" \
-set option:color3 "%[pixel:p{0,h}]" \
\( -clone 0 -extent 100x60% \
-sparse-color barycentric "0,0 %[color1] 0,%[h] %[color2]" \) \
\( -clone 0 -extent 100x40% \
-sparse-color barycentric "0,0 %[color2] 0,%[h] %[color3]" \) \
-delete 0 -append result.png
Maybe you want this, where you get to the half-red/half-blue colour just 20% of the way down the height of the image. It is done by creating two gradients of different lengths and putting them back-to-back:
midcolour="rgb(127,0,127)"
convert -size 100x20 gradient:red-"$midcolour" \
-size 100x80 gradient:"$midcolour"-blue \
-append result.png
Another way is to put 3 single pixels together in a row and then resize that up to what you want. I know you want the middle to be 40% red and 60% blue, but, for ease of viewing, I'll make it lime green:
convert -size 1x1 xc:red xc:lime xc:blue -append -resize 100x100\! result.png
You would change lime to something like "rgb(100,0,155)".
I am not quite sure I understand. But if you want to start with 90% transparent (10% opaque black) and end with black. You can do:
convert -size 200x600 gradient:"graya(0,0.1)-black" output.png
graya means gray with alpha. So graya(0,0.1) is gray(0) or black with 0.1 fraction opacity, so 90% transparent.
Perhaps this is what you want:
Normal 50-50:
convert -size 200x600 gradient:red-blue red_blue1.png
60-40:
rr=`convert xc: -format "%[fx:0.6*255]" info:`
bb=`convert xc: -format "%[fx:0.4*255]" info:`
convert -size 200x600 gradient:"rgb($rr,0,$bb)-rgb(0,0,255)" red_blue2.png
Or perhaps this is what you want:
bb=`convert xc: -format "%[fx:0.1*255]" info:`
convert -size 200x600 gradient:"rgb(255,0,$bb)-rgb(0,0,255)" red_blue3.png
I have an Imagemagick bash shell script called, multigradient, which may do what you want. It allows you to create gradients of many colors each with stops to set where they start. For example:
multigradient -w 200 -h 600 -s "blue 0 red 80" -d to-top result.png
The first color must start at 0, but the direction can be many options. Here I go from bottom to top with pure blue at the bottom and pure red starting at 80 up from the bottom going to the top
(See)

Replace/repaint all pixels with one color in image with interpolated from neighboring pixels

I have a GIF image generated by a program where each output value is represented by its color via attached color palette. I need to replace one value, i.e. color from image with interpolated from neighboring pixels. Since I don't have possibility to alter programs output, I need to modify the output image. The resulting image will be saved in the PNG or GIF format.
I can easily extract (mask) all pixels that need repainting, since they have fixed color, but I was unable to find solution on how to replace a color of one/all pixels in imagemagick with interpolated color from neighboring pixels.
Is there a way to do this in imagemagick?
The raw values of the pixels are proportional to the physical value, so it would be great if the interpolation could be done on raw values that are then later transformed to the color via supplied color palette.
Attached image shows the original (left) and processed manually in GIMP (right).
One technique is to replace the offending color with the background, and then use a combination of erode & dilate morphology to remove the paths.
Given...
convert input.png \
-fill white -fuzz 10% -opaque black \
-morphology Erode Diamond \
-morphology Dilate Diamond \
output.png
It's not a true interpolate from nearest neighbors, but close. Also note the rounding errors across edges.
Updated
Or as Fred pointed out in the comments, just use -morphology Smooth Diamond instead of Erode + Dilate
convert input.png \
-fill white -fuzz 10% -opaque black \
-morphology Smooth Diamond \
output.png
Adding a bit to xenoid's suggestion, you want to create a mask image and use that to composite the median filter with the original, so that only the region about the line is changed. Using emcconville's image and ImageMagick:
convert img.png \
\( -clone 0 -statistic median 3x3 \) \
\( -clone 0 -fuzz 10% -fill white +opaque black -fill black +opaque white -negate \) \
-compose over -composite \
result.png
An alternate, but slightly longer approach, is to put the mask into the alpha channel of the filtered image and then composite it over the original, which produces exactly the same result:
convert img.png \
\( -clone 0 -statistic median 3x3 \) \
\( -clone 0 -fuzz 10% -fill white +opaque black -fill black +opaque white -negate \) \
\( -clone 1 -clone 2 -alpha off -compose copy_opacity -composite \) \
-delete 1,2 \
-compose over -composite \
result.png
Unfortunately, there is a slight dark residual to the upper left between the red and green. I tried increasing both the fuzz value and the filter size, but that did not seem to help. I am not sure why.

Rounding corners of pictures with ImageMagick

in my Rails app I want to have a similar profile section like Facebook where uploaded images are automatically thumbnailed and corner-rounded. I'm using the convert utility to downsize images into thumbnails, but is there an option to round their corners too? Thanks.
Universal solution
This solution works with transparent and non-transparent pictures. To add 15 pixels radius rounded corners to original_picture.png which is a 100x100 picture:
convert -size 100x100 xc:none -draw "roundrectangle 0,0,100,100,15,15" mask.png
convert original_picture.png -matte mask.png \
-compose DstIn -composite picture_with_rounded_corners.png
This solution was given by PM here: https://stackoverflow.com/a/1916256/499917
Elegant solution, does not work with transparent pictures
This solution works without any intermediate picture. How nice! But it will disrupt your original picture's transparency. So use only when you are sure that your picture is not transparent.
Suppose you want rounded corners with 15px radius:
convert original_picture.png \
\( +clone -alpha extract \
-draw 'fill black polygon 0,0 0,15 15,0 fill white circle 15,15 15,0' \
\( +clone -flip \) -compose Multiply -composite \
\( +clone -flop \) -compose Multiply -composite \
\) -alpha off -compose CopyOpacity -composite picture_with_rounded_corners.png
For convenience, here is what you will typically do in Ruby or some other languages:
in_pic = "original_picture.png"
out_pic = "picture_with_rounded_corners.png"
radius = 15
cmd = "convert #{in_pic} \\( +clone -alpha extract " +
"-draw 'fill black polygon 0,0 0,#{radius} #{radius},0 fill white circle #{radius},#{radius} #{radius},0' " +
"\\( +clone -flip \\) -compose Multiply -composite " +
"\\( +clone -flop \\) -compose Multiply -composite " +
"\\) -alpha off -compose CopyOpacity -composite #{out_pic}"
`#{cmd}`
Source: http://www.imagemagick.org/Usage/thumbnails/#rounded
Facebook doesn't modify pictures to have rounded corners. Instead, they use HTML and CSS to apply this image over each user picture: http://www.facebook.com/images/ui/UIRoundedImage.png
If you inspect UIRoundedImage.png, you'll find that each "square" consists of a transparent center, and opaque corners that are meant to match the background on which the user picture will rest. For instance, if the user picture is on a white background, then white opaque rounded corners will be overlaid on the user picture.
The CSS technique for using just a specific part of UIRoundedImage.png is called "CSS sprites". You can read more about it here: http://www.alistapart.com/articles/sprites/
Here are some rounded corners examples: http://www.imagemagick.org/Usage/thumbnails/#rounded_border. You'll need to create a mask of some sort (either by hand or using the drawing tools) and then overlay it onto your image.
Here's the code I wrote to round corners with ImageMagick using Perl. It should port to Ruby fairly easily:
http://article.gmane.org/gmane.comp.video.graphicsmagick.apis/322

Resources