ImageMagick: Exact remap of greyscale values to RGB ones - imagemagick

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

Related

Gray scale to text scan image to black/white image with higher resolution

convert 0101.jp2 -threshold 50% -type bilevel -monochrome -compress LZW ../0101.tiff
The resulting image looks jagged when I use the above command to convert a colored scanned text page to a black/white image (must be one bit per pixel). I want to make it of a higher resolution to look smoother. How can I use convert to do so?
Note that SO automatically converts tif image to jpg format so the output image shown below is not the same as the output image. You will need to run the convert command to get the true output image in tif.
If instead of thresholding you apply a strong contrast the gray pixels on the edge remain in a range of grays and the output is not jagged.
convert Original.jpg -sigmoidal-contrast 30 Corrected.jpg
(there are several ways to increase contrast in Magick)

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.

PIL - Image processing - how to achieve a clean image with no noisy background?binarization step exagerated?

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)

Using Imagemagick to convert PDFs having rasters in them results in white backgrounds behind the sections covered by the rasters

I tried to use ImageMagick (v6.8.9-9 Q16) to convert a PDF containing a PNG file embedded in it to a PNG file.
The original PNG file had a transparent background. In the PDF too it appears fine. But in the PNG obtained after conversion, the area originally occupied by the PNG in the PDF has a white background. Please see the links for more clarity.
The command I ran is as follows:
convert -colorspace sRGB dice.pdf converted_dice.png
I also tried setting the -transparent white switch but it ends up taking out whites that were actually required in the final image.
Are there any extra switches or parameters to pass to convert in order to get rid of just this white background?
Kurt already explains the whole thing in great detail. So here is just how to assemble an image with ImageMagick after running it through pdfimages -png
pdfimages -png my.pdf my
This resluts in two files
identify my-0*png
my-000.png PNG 360x310 360x310+0+0 8-bit sRGB 256c 3.3KB 0.000u 0:00.000
my-001.png PNG 360x310 360x310+0+0 8-bit sRGB 256c 9.44KB 0.000u 0:00.000
my-001.png is the image labeled smask in pdfimages -list. To reassemble the image back to it's original form use -compose CopyOpacity with the ImageMagick command composite
composite -compose CopyOpacity my-001.png my-000.png my-reassembled.png
See also http://www.imagemagick.org/Usage/masking/#masks for more information.
Your approach to this task cannot work.
The command you used will convert the complete letter-sized PDF page (612 x 792 pt) into a PNG image.
However, the original size of the image embedded in the PDF page (612 x 792 pt) is 800 x 600 pixels. This can be seen by running pdfimages -list:
pdfimages -list dice.pdf
page num type width height color comp bpc enc interp object ID x-ppi y-ppi size ratio
----------------------------------------------------------------------------------------
1 0 image 800 600 rgb 3 8 image no 12 0 72 72 277K 20%
1 1 smask 800 600 gray 1 8 image no 12 0 72 72 50.1K 11%
So this is the first problem when converting the PDF page: it does not give your the correct size of the contained images.
The second, more fundamental problem however is: any image you get from converting a PDF page is the combination of all PDF objects overlayed on each other as they are from the page area. (Of course you could crop only part of the page -- but this gives you likewise the combination of all PDF objects from the cropped area...). The results of this you've encountered when you tried to convert all white pixels into transparent ones: since the originally different objects are merged into one representation of pixels, you can no longer discriminate between them as required.
You should take a different approach and use a different tool to extract the image: use pdfimages (the tool used above with the -list parameter to display image properties from the PDF's pages). As you can see, there are two images list: one is an RGB raster image, the other is a grayscale raster image, dubbed as type smask (softmask).
Here is a command to extract both images as PNG:
pdfimages -png dice.pdf dice-images
This will extract the two:
dice-images-0000.png (a color image)
dice-images-0001.png (a grayscale image)
(Note: Only very recent versions of pdfimages, the Poppler version, will let your extract the images as PNG. Within the PDF there is no such thing as PNG. There are only raster data, compressed with different methods. Older versions will only be able to extract images as PPM or PNM. This does not have any influence on what I describe below. Even if you extract PPM/PNM images, these two files can still be processed as described below...)
Below is a side-by-side, scaled-down montage of the two:
As you can see, the image itself does not have a transparent background, but a white one. (It does not have an Alpha channel.) Within the PDF format, these two images are used in combination to create transparent areas:
what appears completely black in the softmask (right) means: this pixel of the real image (left) is meant to be fully transparent.
what appears completely white in the softmask (right) means: this pixel of the real image (left) is meant to be fully opaque.
what appears in a shade of gray in the softmask (right) means: this pixel of the real image (left) is meant to be partially transparent (in line with its level of gray/black).
To combine these two files (color image and grayscale softmask) back into one PNG with transparency, you can employ ImageMagick now...

ImageMagick: how to reduce colors but keep transparency?

I have some PNG files I wish to convert to 256 colors (i.e. GIF-like). Each image has transparency, but when I try to convert I always end up with a black background on the resulting image.
Here is my current command:
convert file.png -colors 255 file256.png
I'm using 255 colors because I read that you need one color for the alpha channel (though I don't think that should apply to PNGs). I've tried many other options such as -background none, -channel RGBA and -matte but nothing is working at all.
Interestingly, this command did work when converting to grayscale:
convert file.png -channel RGBA -matte -colorspace gray file256.png
It kept the transparent background. But replacing -colorspace gray with -colors 256 doesn't work.
The reason to use 255 instead of 256 colors is that one color needs to be reserved for "binary" / "boolean" transparency, i.e. all pixels of that color are interpreted as completely transparent. There (usually) is no such thing like an alpha channel with 256-color / palette-based images. For reference, you may want to read the ImageMagick usage sections about Color Quantization and Transparency and GIF Boolean Transparency. That said, this should convert your 32-bit true-color PNG with alpha channel to an 8-bit PNG with palette where all pixels that are fully transparent in the input image are also fully transparent in the output image:
convert file.png png8:file256.png
The png8 instructs ImageMagick to write a GIF-like "8-bit indexed with optional binary transparency" PNG and implies to use 255 "real" colors.
Have you tried -colorspace transparent to preserve the Alpha channel?

Resources