How to change grayscale to colour in python? - python

I have found the following link: Python colour to greyscale
I would however like to do the opposite. Is this possible with Pyython (preferably with PIL, but other options are welcome as well like matplotlib)?
I need to read in a greyscale png image, which I would like to convert to a rainbow scale (preferably desaturated rainbow, but not necessary). The images originally come from c-code that generates numbers between 0 and 256 and converts those to grey tones. I would like to map those values now linearly to a colour-map (but I currently only have access to the png-image, not the c-code any more). So is there a way to map white to blue, and black to red, with all colours of the rainbow in between?

The mapping from color to grey is not invertable. So you need to indeed define some colormapping like the matplotlib colormaps do.
import matplotlib.pyplot as plt
# generate gray scale image
import scipy.misc
face = scipy.misc.face()
plt.imsave("face.png", face.mean(2), cmap="gray")
# read in image
im = plt.imread("face.png")
# plot image in color
plt.imshow(im.mean(2), cmap="jet_r")
#save image in color
plt.imsave("color.png", im.mean(2), cmap="jet_r")
plt.show()

Related

Mark with color on grayscale image in Matplotlib

I have a grayscale image (so an 2d numpy array with values between 0 and 1) which I usually show as follows:
plt.imshow(image, cmap='gray')
plt.title(title)
plt.axis("off")
plt.show()
plt.close()
Now I want to kind of "paint" over this image with one single color (to highlight some part). Is there a way to do this in Python (preferably matplotlib)?
For example I have the Shepp Logan Phantom (https://en.wikipedia.org/wiki/Shepp–Logan_phantom), of which I want to mark the right black ellipse with a red edge. I do have an image containing only this edge (of the same size as the Phantom), so how can I "put" it with a color over the original gray scale image?
EDIT: I am actually using more complicated images with arbitrary shapes and not precise ellipses/circles, but suppose I want to highlight the following white parts of the image below (for which I cannot use perfect shapes) of the Shepp Logan phantom with red together with the rest of the Shepp Logan phantom as in the link:
Then my question is: how can I combine these two images (of which one should be colorized and the other one should be a grayscale image).
Thanks in advance!

How to get set of colours in an image using python PIL

After importing an image using python's PIL module I would like to get the set of colours in the image as a list of rgb tuples.
What If I know before hand that there will only be 2 colours and the image will be very small, maybe 20x20 pixels? However, I will be running this algorithm over a lot of images. Will It be more effiient to loop through all pixels until I see 2 unique colours? Because I understand loops are very slow in python.
First, let's make an image. I'll just use ImageMagick to make a blue background with magenta writing:
convert -size 300x120 -background blue -fill magenta -gravity center -font AppleChancery label:"StackOverflow" PNG24:image.png
As you can see, I only specified two colours - magenta and blue, but the PNG image actually contains 200+ colours and the JPEG image contains 2,370 different colours!
So, if I want to get the two main colours, I can do this:
from PIL import Image
# Open the image
im = Image.open('image.png')
# Quantize down to 2 colour palettised image using *"Fast Octree"* method:
q = im.quantize(colors=2,method=2)
# Now look at the first 2 colours, each 3 RGB entries in the palette:
print(q.getpalette()[:6])
Sample Result
[0, 0, 255, 247, 0, 255]
If you write that out as 2 RGB triplets, you get:
RGB 0/0/255 = blue
RGB 247/0/255 = magenta
The best way to do this for lots of images is to use multithreading or multiprocessing if you want them done fast!
Keywords: Python, PIL, Pillow, image, image processing, octree, fast octree, quantise, quantize, palette, palettise, palettize, reduce colours, reduce colors, anti-aliasing, font, unique, unique colours, unique colors.

Changing a color range in an image to a different color texture

I successfully changed a range of colors in an image to a single other color. I would like to make it more realistic by changing the colors to match the distribution of a swatch or, at the very least, a narrow band of random hues.
Some brown-looking grass
changed to very artificial green-looking grass
My code:
import cv2 as cv
import os
import numpy as np
import random
# Load the image and convert to HSV colourspace
image = cv.imread('brown_grass.jpg')
hsv=cv.cvtColor(image,cv.COLOR_BGR2HSV)
# Define lower and uppper limits of what we call "brown"
brown_lo=np.array([18,0,0])
brown_hi=np.array([28,255,255])
# Mask image to only select browns
mask=cv.inRange(hsv,brown_lo,brown_hi)
# Change image to green where we found brown
image[mask>0]=(74,183,125) # how do change it to a nice realistic texture swatch?
cv.imwrite('result.jpg',image)
(Thanks to I want to change the colors in image with python from specific color range to another color for the first part of the solution)
Thanks to #MarkSetchell for the idea; the way to shade the masked area in a more natural way is to exploit the fact that brown and green are adjacent on the HSV color model, and add the delta between them, plus a boost for saturation and value.
hsv[mask>0]=hsv[mask>0]+(25,30,10) # add an HSV vector
image2=cv.cvtColor(hsv,cv.COLOR_HSV2BGR) # convert image back into RGB color space
cv.imwrite('result.jpg', image2)
Exaggerating the effect here:

Making image white space transparent, overlay onto imshow()

I have a plot of spatial data that I display with imshow().
I need to be able to overlay the crystal lattice that produced the data. I have a png
file of the lattice that loads as a black and white image.The parts of this image I want to
overlay are the black lines that are the lattice and not see the white background between the lines.
I'm thinking that I need to set the alphas for each background ( white ) pixel to transparent (0 ? ).
I'm so new to this that I don't really know how to ask this question.
EDIT:
import matplotlib.pyplot as plt
import numpy as np
lattice = plt.imread('path')
im = plt.imshow(data[0,:,:],vmin=v_min,vmax=v_max,extent=(0,32,0,32),interpolation='nearest',cmap='jet')
im2 = plt.imshow(lattice,extent=(0,32,0,32),cmap='gray')
#thinking of making a mask for the white background
mask = np.ma.masked_where( lattice < 1,lattice ) #confusion here b/c even tho theimage is gray scale in8, 0-255, the numpy array lattice 0-1.0 floats...?
With out your data, I can't test this, but something like
import matplotlib.pyplot as plt
import numpy as np
import copy
my_cmap = copy.copy(plt.cm.get_cmap('gray')) # get a copy of the gray color map
my_cmap.set_bad(alpha=0) # set how the colormap handles 'bad' values
lattice = plt.imread('path')
im = plt.imshow(data[0,:,:],vmin=v_min,vmax=v_max,extent=(0,32,0,32),interpolation='nearest',cmap='jet')
lattice[lattice< thresh] = np.nan # insert 'bad' values into your lattice (the white)
im2 = plt.imshow(lattice,extent=(0,32,0,32),cmap=my_cmap)
Alternately, you can hand imshow a NxMx4 np.array of RBGA values, that way you don't have to muck with the color map
im2 = np.zeros(lattice.shape + (4,))
im2[:, :, 3] = lattice # assuming lattice is already a bool array
imshow(im2)
The easy way is to simply use your image as a background rather than an overlay. Other than that you will need to use PIL or Python Image Magic bindings to convert the selected colour to transparent.
Don't forget you will probably also need to resize either your plot or your image so that they match in size.
Update:
If you follow the tutorial here with your image and then plot your data over it you should get what you need, note that the tutorial uses PIL so you will need that installed as well.

Displaying a grayscale Image

My aim:
Read an image into the PIL format.
Convert it to grayscale.
Plot the image using pylab.
Here is the code i'm using:
from PIL import Image
from pylab import *
import numpy as np
inputImage='C:\Test\Test1.jpg'
##outputImage='C:\Test\Output\Test1.jpg'
pilImage=Image.open(inputImage)
pilImage.draft('L',(500,500))
imageArray= np.asarray(pilImage)
imshow(imageArray)
##pilImage.save(outputImage)
axis('off')
show()
My Problem:
The image get's displayed like the colours are inverted.
But I know that the image is getting converted to grayscale, because when I write it to the disk it is appearing as a grayscale image.(Just as I expect).
I feel that the problem is somewhere in the numpy conversion.
I've just started programming in Python for Image Processing.
And Tips and Guideline will also be appreciated.
You want to over-ride the default color map:
imshow(imageArray, cmap="Greys_r")
Here's a page on plotting images and pseudocolor in matplotlib .
This produces a B&W image:
pilImage=Image.open(inputImage)
pilImage = pilImage.convert('1') #this convert to black&white
pilImage.draft('L',(500,500))
pilImage.save('outfile.png')
From the convert method docs:
convert
im.convert(mode) => image
Returns a converted copy of an image.
When translating from a palette image, this translates pixels through the palette.
If mode is omitted, a mode is chosen so that all information in the image and the palette can be represented without a palette.
When from a colour image to black and white, the library uses the ITU-R 601-2 luma transform:
L = R * 299/1000 + G * 587/1000 + B * 114/1000
When converting to a bilevel image (mode "1"), the source image is first converted to black and white.
Resulting values larger than 127 are then set to white, and the image is dithered.
To use other thresholds, use the point method.

Categories

Resources