Can I separate image on arbitrary colors? - image-processing

Is it possible to separate an image into channels based on arbitrary colors? If I have an image that's visually pink, white and black, is it possible to create 3 separate images describing the "pinkyness" "whiteness" and "blackness" channels?
My purpose is to mutate - let's say - pink into yellow, black into blue and white into red.
Ideally this should be possible with ImageMagick
I would use color substitution but it would substitutes all colors close to pink with one single colors, whereas I want to preserve the different levels of intensity of pink.
Using this image as an example, I'd like to turn the knit part rom pink/white/black into blue/yellow/green.

You need to use the hue channel from HCL or HSL, etc and mask and swap hues. I have a bash Unix shell script, replace color, for Imagemagick that will do that.
Input:
replacecolor -i "#BA3A67" -o blue Adidas-pink.png Adidas-blue.png
#BA3A67 is your input pinkish color that I measured. Blue is the desired output color. Any opaque color can be use and specified as a color name or hex value or rgb(rr,gg,bb) triplet.
The script cannot change gray tones (black, gray, white), since the hue is the same as red. But you can still change black and/or white (or any color) in imagemagick using:
convert image.suffix -fuzz XX% -fill newcolor -opaque oldcolor output.suffix
Where XX is some percent tolerance.
See http://www.fmwconcepts.com/imagemagick/replacecolor/index.php

Related

Re-color a background of a scanned image with ImageMagic

I have an image, coming out of a scan, that I would like to reproduce it in several different colors against multiple different colored backgrounds, like the one bellow:
I can easily change the color of the bug with level-color conversion, as in:
convert image.png +level-colors red, red-image.png
and produce an stupendously good quality image:
I understand (from many postings here) that making the background color transparent in a scan is one of the most difficult operations on an image. My question is:
Is there a way to change the background color -- by level -- in a similar way?
In ImageMagick, you can recolor the background using -fill ... -opaque. Measure the color of the background, then
convert insect.png -fuzz 5% -fill skyblue -opaque "rgb(235,215,186)" insect_blue.png
The -fuzz X% permits coloring of close but not exactly the measured color. This allows non-uniform background color to be changed. The larger the X%, the more it will color parts of the image.
A value of 0% means only color the exact value measured.
See https://legacy.imagemagick.org/Usage/color_basics/#opaque

regarding the ways of removing surrounding background areas during processing the image

The attached image, showed as follows
It includes some surrounding areas that represents the noise or background introduce while getting the image.
How to remove this part while processing the image. For instance, when I try to segment the original image, I got the following result, where the background areas are also included.
You could use a flood fill starting at the bottom-right corner to fill all pixels less than some "fuzziness" distance (in shades of grey terms rather than in geometric distance terms) with black so they all come out to the same class.
Here I do it with ImageMagick just in Terminal, and colour using red and blue, rather than black, to show the concept:
convert input.jpg -fuzz 15% -fill red -floodfill +1140+760 black result15.jpg
Or, allowing slightly fewer colours (darker) to match via fuzziness:
convert input.jpg -fuzz 10% -fill blue -floodfill +1140+760 black result10.jpg
You can do this with OpenCV in Python, and Wand and other tools. Here is an example showing how to do a floodfill withPIL/Pillow.

ImageMagick Unable to change colour in shade explicitly for image

I want to use ImageMagick to change colour in shade.
I am able to manage the shade change using :
convert input.png -colorspace HCL -channel R -evaluate set 5% +channel -colorspace sRGB output.png
Using set XX% i am able to get different colours like, red, green, yellow, blue, pink, sky-blue, gray, etc.
The below command works for targeting blue colour :
convert input.png -colorspace HCL -channel R -separate +channel -level 48,52% output.png
But I am unable to target other colour explicitly.
For example, if I want to change green colour with some other colour, resulted image will effect green, yellow,red and sky-blue as well.
Is there a way to explicitly change a single colour in shade for :
yellow
sky-blue
pink
green
white
black
red
I tried changing all -channel : R,G,B,C,M,Y,K,A,O.
Using -separate option I can target RBG, but the problem with RGB is R effect red, yellow and pink, G effect green, sky-blue and yellow and B effect blue, pink and Sky-blue.
sample for output :
RGB image colour change
expected output : In the above output for "output-0" it effect red,yellow and pink. i want the command which will effect only red. similarly for other colours as well.
links I used : https://www.imagemagick.org/discourse-server/viewtopic.php?t=33361
I am using python to run this command. I am also open to use other libraries which will work with all the colours explicitly.
If your image is representative like I requested, it is as simple as this:
magick rgb.png -fill white -opaque red result.png
If you also want to affect hues "close to red", you can apply some fuzz:
magick rgb.png -fuzz 40% -fill white -opaque red result.png
Notice that also affects the edges of the red circle where it is a "feathered red".
If not, your ImageMagick code is essentially doing a "Hue rotation" and, as you have noticed, it affects the entire image. Read the Wikipedia page on HSV before continuing. Here is an HSI Hue wheel for reference:
The solution is to do your Hue rotation, but apply its effects via a mask that only selects the colours/areas you want affected. Remember that OpenCV halves the Hue from the range 0..360 to 0..180 so that it can store a Hue in a np.uint8.
So, if we load the same image as above and select only the greens (where Hue is near 120) we can rotate just those into blues by adding 60 (Hue=240):
#!/usr/local/bin/python3
import cv2 as cv
import numpy as np
# Load the image and convert to HSV colourspace
image = cv.imread("rgb.png")
# Convert to HSV and split channels
hsv=cv.cvtColor(image,cv.COLOR_BGR2HSV)
H,S,V = cv.split(hsv)
# Shift only greens (Hue near 120) around hue circle by 120 degrees to blues - remembering OpenCV halves all these values - see comment
H[(H>55)&(H<65)] += 60
# Recombine into single 3-channel image and convert back to RGB
result = cv.merge((H,S,V))
result = cv.cvtColor(result,cv.COLOR_HSV2BGR)
cv.imwrite("result.png",result)
If you want to change the blues (Hue=240) into yellows (Hue=60), just change this:
H[(H>55)&(H<65)] += 60
into this:
H[(H>115)&(H<125)] -= 90
If you want to broaden the range of greens affected, decrease the 55 in my code and/or increase the 65. If you want to move greens to a different hue, either increase or decrease the 60.
You can do all the stuff above with PIL/Pillow if you want to - you don't need to install the (massive) OpenCV.
Keywords: Image, image processing, Python, OpenCV, ImageMagick, Hue, HSL, HSV, hue rotation, colour replacement, selective colour, mask.

Creating a more effective matt for chromakey?

I'm trying to chromakey some pictures. Here is an example of one:
Here is another one,
Now using image magic, I can generate a mat like this..
But I can never get the mat to be "full". My plan is to create a static mat for the turntable and the lightbank -- those won't have to be removed. But, I'd like to fix the problems I'm seeing with the grill, licenseplate, and window. I'd like the car to show up pitch-black. I'm using ImageMagick's convert to get this working,
convert 1.bmp -channel g -separate +channel -fuzz 45% -fill black -opaque black -fill white +opaque black greenscreensample_mask_1.gif
How can I improve this to fill in the bumper of the vehicle?
I would guess the shinny parts are slightly green and you could try reducing the fuzz value.
You can use the -fx operator and then work with specific channels. The following is by no means optimal, and also, it is very inefficient to execute:
convert ./in.jpg -background none -transparent white -channel Alpha -fx '1-((g-r)+(g-b)+(g-(r+b)/2))^2' -channel Green -fx '(r+b)/2' ./out.png;eog ./out.png
in order to obtain a key for the green channel you can subtract the
red from the green
blue from green
average of blue and red channels from the green channels
the very basic colour correction involves replacing fringed areas with the average of the blue and red channels, here however the entire image had its green channel replaced with the average of the blue and red channels. you should actually write an algorithm that seperates the fringe into a seperate channel, then you colour correct the entire image and mix it in with the original based on this "fringe" matt.
thankyou, best of luck

How do I set a colour to be transparent in a GIF using ImageMagick?

I've had a hard time finding out how to set a colour (black in my case) to be transparent in a GIF using ImageMagick. How can I do that to a set of existing GIF images?
I've tried this option but it doesn't seem to do anything:
mogrify -transparent-color black -transparent black *.gif
I've read through this but it seems a little baffling in what actually makes a colour become transparent in a GIF: http://www.imagemagick.org/Usage/formats/#boolean_trans
For example:
Note that setting "-transparent-color" does NOT add any transparency
to a GIF image, nor does it convert the specified color to become
transparent. All the option does is specify what color should placed
in the color table for the color index that is used representing the
transparent colors in a GIF image.
If you want to change a specific (exact) color to become transparent,
then use the "-transparent" Color Replacement Operator.
but then...
Use +transparent to invert the pixels matched. that is make all
non-matching colors transparent.
The -opaque operator is exactly the same as -transparent but replaces
the matching color with the current -fill color setting, rather than
transparent. However the -transparent operator also ensures that the
image has an alpha channel enabled, as per "-alpha set", and does not
require you to modify the -channel to enable alpha channel handling.
Note that this does not define the color as being the 'transparency
color' used for color-mapped image formats, such as GIF. For that use
-transparent-color
I'd like to warn you from using mogrify. mogrify does convert images by overwriting the original ones. If anything goes wrong, your images are gone.
Rather use convert. You can always delete your original images after you are sure the conversion is ok.
To make black pixels transparent, use this:
convert orig.gif -transparent black transp.gif
Works perfectly for me.
My IM version: ImageMagick 6.7.8-0 2012-07-04 Q16. What's yours?
If it still doesn't work for you, the 'black' in your GIFs may not be black after all, but only very dark gray. ImageMagick also has tools to enumerate all colors in a GIF. The following 2 commands may help you in this case:
identify \
-format "%f: - Uniq Colors: %k - Image transparency channel enabled: %A - Image Depth: %z %c\n" \
*.gif
and
convert \
*.gif \
-format "%f :\n%c\n\n" \
histogram:info:
Use of color black can be identified by name 'black', by RGB-values '(0, 0, 0)' as well as by hex value '#000000'. So pure blacks should appear in the output of the last command as something like:
5000: ( 0, 0, 0) #000000 black
Dark grays could for example be:
100: ( 14, 14, 14,255) #0E0E0E srgba(14,14,14,1)
2100: ( 1, 1, 1,255) #010101 srgba(1,1,1,1)
Once there is transparency enabled in your GIF, the last command should show a tuple of 4 values for each color, the last value representing the Alpha channel. Your formerly black would appear in the output as something like:
5000: ( 0, 0, 0, 0) #00000000 none
Try -background color once you generate it to GIF.
Check the http://www.imagemagick.org/script/mogrify.php url for both mogrify and background options. See the image below.

Resources