Crop an image based on one channel with ImageMagick - imagemagick

I have an image (see below) with a border in the red channel and the stuff I'd like to keep in the green channel.
I'd like to:
crop the image to the extent of the red pixels (ignoring any which aren't 100% red)
crop N more pixels (4, say) from each side
delete the red channel
copy the green channel to the red and blue channels (making it white)
save the result into a new file
I've been reading the docs but am stumped, can anyone with more experience of this program help me?
I'm using windows, version: ImageMagick 7.1.0-7 Q16-HDRI x64 2021-09-12
Thanks,
Charlie

Maybe like this:
magick l1AvD.png -trim -shave 10 -channel g -separate result.png
It does the following steps:
trim to any/all channels
remove 10 pixels off all sides
extracts just the green channel and saves as a single-channel, greyscale image
You may want to add -threshold 50% after -separate if you want pure blacks and whites. You may want to add +repage after -separate to make it forget where on the canvas it originally came from.

The answer came from the GitHub discussions page, this seems to work:
magick ^
file.png ^
-strip ^
( +clone ^
-color-threshold "red-red" ^
-set option:MYCROP "%%#" ^
+delete ^
) ^
-crop %%[MYCROP] +repage ^
-shave 4x4 +repage ^
-channel G -separate +channel ^
output.png

Related

ImageMagick engraving effect on glass

I want to add logo on product image with engraving effect.
The original logo is
After adding it on the product it should look like this.
how to do this with imagemagick.
Using this as the trophy:
Then something along these lines:
convert trophy.jpg -gravity center \
\( G.png -colorspace gray -channel a -evaluate multiply 0.2 -resize 120x120 \) -composite result.png
So, I am basically loading the trophy, then in some "aside processing" in parentheses, loading the Google logo, converting it to greyscale, reducing the opacity by multiplying it by 0.2, resizing it and compositing it on top of the trophy.
By the way, if you were using GraphicsMagick, which doesn't have the parentheses I used to make sure I only convert the logo to greyscale and not the trophy, you would do it in a different order. First load the logo and process it (greyscale, resize etc), then load the trophy, then swap the order so the trophy goes to the background, like this:
gm convert G.png -colorspace gray -resize ... trophy.jpg -swap -composite result.png

Unable to create NDVI image using ImageMagick

I have four separate images - 2-projected.tif, 3-projected.tif, 4-projected.tif and 5-projected.tif. These are four Landsat images. Image 2-projected.tif corresponds to blue channel, image 3-projected.tif - to green channel, image 4-projected.tif - to red channel, and 5-projected.tif - to infrared. Now I want to create NDVI image. To do this, I first create a combined RGB image, using ImageMagic:
$ convert 4-projected.tif 3-projected.tif 2-projected.tif -combine RGB.tif
So far, so good. And then I try to follow a command from this tutorial, which is supposed to create NDVI image. I do it like so:
$ convert 5-projected.tif RGB.tif -channel RGB -fx '(u.r-v.r)/(u.r+v.r+0.001)' -normalize NDVI.tif
But as a result, I get these error messages:
convert: unable to parse expression (u.r-1.0*v.r)' # error/fx.c/FxGetSymbol/183
1.
convert: divide by zero'(u.r-1.0*v.r)/(u.r+v.r+0.001)'' # error/fx.c/FxEvaluat
eSubexpression/2159.
I'm not sure how can I fix it.
The two bands of interest are the red and the NIR and the formula for NDVI is:
NDVI = (NIR-red)/(NIR+red)
You have two options. First off, if you have the red and the NIR in two separate, single channel images, you can do:
convert red.tif NIR.tif -fx '(u.r-v.r)/(u.r+v.r+0.001)' -normalize -compress lzw NDVI.tif
Here, I am using u.r to refer to the first channel of the first image and v.r to refer to the first channel of the second image.
Alternatively, if the red and NIR are the first two channels in an RGB image (i.e. ImageMagick would call them the red and green channels):
convert RGB.tif -fx '(u.r-u.g)/(u.r+u.g+0.001)' -normalize -compress lzw NDVI.tif
Here I am using u.r to refer to the first channel of the first image and u.g to refer to the second channel of the first image.
The -fx method is extremely powerful, but notoriously slow. This method below should give you the same answer, but I have not checked it too thoroughly:
convert 4-projected.tif -write MPC:red +delete \
5-projected.tif -write MPC:NIR +delete \
\( mpc:red mpc:NIR -evaluate-sequence subtract \) \
\( mpc:red mpc:NIR -evaluate-sequence add \) \
-evaluate-sequence divide -normalize -compress lzw NDVI.tif
If you want to colourise the image with false colour, you could generate a Colour Lookup Table (CLUT) and map the grayscale values in the NDVI image to those colours. So, let's say you wanted to map the darkest blacks in your NDVI image to black, the quite dark values to red, the quite bright values to orange and the very brightest values to green, you could make a CLUT like this:
convert xc:black xc:red xc:orange xc:lime +append clut.png
and apply it the greyscale result from above like this:
convert NDVI.tif -normalize clut.png -clut falsecolour.jpg
If you want to make the orange and green tones longer (more prevalent), you can alter their lengths to make them longer in the CLUT:
convert -size 30x1 xc:black -size 40x1 xc:red -size 80x1 xc:orange -size 100x1 xc:lime +append clut.png
Then re-apply the CLUT:
convert NDVI.tif -normalize clut.png -clut result.jpg

Relative imagemagick transforms: Relative Crop?

I'm trying to execute the following set of transformations without knowing the absolute width or height of the target image:
1. Crop image A by 10px on every size :: A1
2. Create duplicate of A1 translating image by 1270px on the y-axis :: A2
3. Create montage of A1 && A2 :: A3
4. Translate A3 by 385px on the y-axis :: A4
5. Crop A4 at 100% width, and 1270px tall (box from 0,0 to WIDTH,1270) :: A5
My issue is how do I do steps 1 and 5 with relative coordinates? Below are my steps that I've come up with:
1. convert A.jpg -shave 10x10 A1.jpg
2. convert A1.jpg -page +0-1270 -background none -flatten A2.jpg
3. montage A1.jpg A2.jpg -geometry +0+0 A3.jpg
4. convert A3.jpg -page +0-385 -background none -flatten A4.jpg
5. convert A4.jpg ????? A5.jpg
Updated Answer
Ok, I think I understand what you want a bit better now. Here's how I would do it:
convert start.jpg -crop +0+383 +repage \
\( -clone 0 -crop x1270+0+0 \) \
\( -clone 0 -crop x1270+0+1270 \) \
-delete 0 +append result.jpg
The first line says..."Take the starting image and crop off the top 383 pixels and reset all the sizes to match what is left. Call that the first image from now onwards."
The second line says..."To one side (because of the parentheses), clone the first image and crop out the full width and 1270 pixels in height from the top. Hold onto that till later - i.e. keep it in the image list.".
The third line says..."To one side (because of the parentheses), clone the first image, and crop out a piece the full width and 1270 pixels in height, but start 1270 pixels from the top. Hold onto that till later - i.e. keep it in the image list."
The last line says..."Delete the initial image, and then take the two slices in the image list and append them side-by-side, Save as result.jpg".
Original Answer
I think we will need to work together on this one, but it can be done. Let's start with a concrete image that is a 400x250 gradient with a 15px black border:
convert -size 250x400 gradient:red-cyan -rotate 90 -bordercolor black -border 15 A.png
So, step 1.
convert A.png -shave 10x10 A1.png
Step 2&3. I don't get the point of these! You appear to be trying to add transparent space to a JPEG which doesn't support transparency. Also, I can't tell what you are montaging where. Please try and express what you want with these two steps in plain English, like "add a transparent area N pixels wide/tall above/below, left/right of A2", or maybe "add a transparent area such that the new dimensions are X,Y and the original A2 image is at the bottom-right of the new canvas."
If I have a stab at steps 2&3, I'll guess this (and add a purple border so you can see it on StackOverflow's white background). I am appending a transparent area 1270 pixels tall below the image.
convert A.png -background none -shave 10x10 xc:none[1x1270\!] -append b.png
Step 4&5. As above.
Or maybe you mean this:
convert A.png -background magenta -shave 10x10 -gravity southeast -extent 1270x385 result.png
I think we can get you down to a single command, with no intermediate files, if we understand your needs.

How to select all grayscale colors?

In ImageMagick convert, I can select a specific color with e.g. -opaque blue. How can I select all grayscale colors (e.g. #000000, #707070, #ffffff)?
Not sure what you are trying to do, but this may help. The greyscale pixels will have a saturation of zero, so that is probably the easiest way to identify them.
First, make a funky sample image:
convert -size 400x100 gradient:black-white -bordercolor red -border 80 image.png
Now make all grey areas (those with very low saturation) transparent:
convert image.png -alpha on -channel A -fx "saturation<0.01?0:1" result.png
Note
Note that the -fx operator is extremely powerful but notoriously slow because it is actually interpolated for each and every pixel. If your images are large, the following technique may be more appropriate.
Basically, I clone the image and convert the whole thing to HSL colorspace and separate the channels. Then I discard the Hue and Lightness channels so I am left with just the Saturation. I then threshold that and copy that back to the original image as the alpha channel. On a 2000x2000 pixel image, this method will run in under a second whereas the -fx method will require 5-6 seconds.
convert image.png \( +clone -colorspace hsl -separate -delete 0,2 -threshold 1% \) -compose copy-opacity -composite result.png

How to output white png version of my image ?**

With ImageMagick shell command (convert?)...
Given a colorful input.png image.
How to us input.png to produce a white output.jpg version with similar dimensions an opacity of 100% ?
I will later on use this layer in my workflow.
This should work:
convert input.png -threshold -1 output.jpg
This transforms any pixel with an intensity greater than (-1), i.e., all of them, to white.
It does not work with GraphicsMagick, though, because in GM the threshold value is unsigned (in ImageMagick it's a signed "double"). Neither of the applications documents exactly what is supposed to happen when the threshold is negative.
Here's a command that works on both ImageMagick and GraphicsMagick, and is documented:
[gm] convert input.png -fuzz 100% -fill white -opaque gray output.jpg
You could use fill, like this:
convert input.png -fill "#ffffff" output.jpg
or
convert input.png -fill white output.jpg
Or you can convert all three channels (red, green and blue) to "1" which is full intensity, like this:
convert input.png -channel red -fx "1" -channel green -fx "1" -channel blue -fx "1" output.jpg

Resources