In Photoshop you can adjust the hue, saturation and lightness of an image with three sliders. ImageMagick you can modulate the brightness, saturation, and hue.
Minimizing the saturation correctly produces a black and white image in both programs.
Maxing out the saturation appears close, but ImageMagick appears to soften some of the blown out edges while Photoshop will expose more the the compression artifacts.
How can I accurately reproduce Photoshop's saturation changes from within ImageMagick, or other command line tool.
Could it be that they each use slightly different RGB colour models? From the names of the attributes they use (lightness and brightness), it certainly seems that;
Photoshop = HSL (hue, saturation,
luminence)
ImageMagik = HSV (hue, saturation,
value)
Check out this Wikiepedia article on HSL and HSV colour spaces.
Related
I'm using ImageMagick 6.8 and I have LUT color table created in text format:
# ImageMagick pixel enumeration: 848,1,255,srgb
0,0: (0 , 0 , 0 ) #000000
1,0: (226, 226, 224) #E2E2E0
2,0: (48 , 74 , 0 ) #304A00
# ...
# few hundred more colors
Which has one colour per grayscale value (between 0 and 848 in my use case).
So, I want to convert a grayscale image to RGB one, using this LUT without any fancy gamma corrections, colour space remaps, interpolations and etc. Just straight replacement. How to do it?
Current issues start since the beginning:
Trying to convert lut.txt lut.png with various options always give me more colours than they are actually. In the LUT, there are 540 unique colours, but inspecting the generated PNG, or even identify lut.txt reports 615! This means that the LUT is not interpreted straight at all.
On the other hand, even if I succeed to read the LUT exactly, or probably avoid converting it to PNG, there comes another problem. Using -clut maps the whole greyscale range (0-65535) to the LUT, so I guess I have to normalize it first. But this screws up the greyscales input to begin with.
P.S. An answer which might be useful here is, if there is image format with bigger than 8-bit indexed palette. Then that text LUT be used as its palette and the greyscale raster as its pixel values.
In Imagemagick, use -clut to process a grayscale image with a colored look-up table image to colorize the grayscale image.
First create a 3-color color table LUT image with red, green and blue hex colors. I show an enlarged version.
convert xc:"#ff0000" xc:"#00ff00" xc:"#0000ff" +append colortable.gif
Here is the input - a simple gradient that I will colorize.
Now apply the color table image to the gradient using -clut.
convert gradient.png colortable.gif -clut gradient_colored.png
The default is a linear interpolation. But if you only want to see the 3 colors, then use -interpolate nearest-neighbor.
convert gradient.png colortable.gif -interpolate nearest-neighbor -clut gradient_colored2.png
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.
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
Good afternoon,
I am writing an ocr program to detect text on images. So far I am getting good results but when text is black and background is white. What can I do to improve images that have white text on light colored background (yellow, green, etc)?
One original example image could be:
So far I am just converting it to grey_scale using:
image = image.convert('L')
Then apply a series of filters like for example:
SHARPEN
SMOOTH
BLUR
etc
Then i do binarization like this:
image = image.point(lambda x: 0 if x<128 else 255, '1') #refers to http://stackoverflow.com/questions/18777873/convert-rgb-to-black-or-white and also to http://stackoverflow.com/questions/29923827/extract-cow-number-from-image
My outoup images are indeed very bad for ocr feeding like this one:
What am I doing wrong? What should be the best approach for white text on light colored background?
Another doubt: is my binarization step to strong/exagerated?
Should I mix some filters? Could you suggest some?
PS: I am a total newbie to image processing, so please keep it simple =x
Thanks so much for your attention and help/advices.
I tried this with ImageMagick, which has Python bindings too - except I did it at the command line. I guess you can adapt what I did quite readily - I don't speak Pythonese nor use PIL but hopefully it will give you some insight as to a possible avenue.
convert http://i.stack.imgur.com/2cFk3.jpg -fuzz 50% -fill black +opaque white -threshold 50% x.png
Basically it takes any colour that is not within 50% of white and fills it with black, then it thresholds the result to pure black and white.
Another option would be to threshold the image according to the saturation of the colours. So, you convert to HSB colorspace, separate the channels and discard the hue and brightness. You are then left with the saturation which you threshold as follows:
convert http://i.stack.imgur.com/2cFk3.jpg -colorspace hsb -separate -delete 0,2 -threshold 50% x.png
Throw in a -negate to get white letters on black.
I have copied some other code for PIL, and am modifying it kind of/sort of to something that may be close to what you need - bear in mind I know no Python:
import colorsys
from PIL import Image
im = Image.open(filename)
ld = im.load()
width, height = im.size
for y in range(height):
for x in range(width):
r,g,b = ld[x,y]
h,s,v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
if s>0.5: // <--- here onwards is my attempted Python
ld[x,y] = (0,0,0)
else:
ld[x,y] = (255,255,255)
Does it make sense to invert RGB image?
I know the algorithm for grayscale images is 1 - value, but for RGB?
Thanks
For rgb just subtract the red, green and blue values from 255.