Colourize a grayscale image using Pillow - python

I have a grayscale image created using Pillow – it's mode L – and I'd like to save it as shades of a single colour, so that instead of shades from black-to-white, it's shades from cyan-to-white.
So, say I was doing this:
from PIL import Image, ImageOps
i = Image.open("old_img.jpg")
g = ImageOps.grayscale(i)
g.save("new_img.jpg")
What could I do to save it as cyan-to-white, rather than black-to-white? I'm going to do similar with other grayscale images for magenta-to-white and yellow-to-white too.

Convert your image to the "L" mode (luminosity, grayscale), and then use the .colorize() method instead of the .grayscale() one:
from PIL import Image, ImageOps
i = Image.open("old_img.jpg").convert("L")
g = ImageOps.colorize(i, black="cyan", white="white")
g.save("new_img.jpg")
or just add the command
g = ImageOps.colorize(g, black="cyan", white="white")
after applying the .grayscale(i) method (because it converts the image to the "L" mode, too):
from PIL import Image, ImageOps
i = Image.open("old_img.jpg")
g = ImageOps.grayscale(i)
g = ImageOps.colorize(g, black="yellow", white="white")
g.save("new_img.jpg")
You may set other desired color in the black= parameter of the .colorize() method.

You might be able to do that with matplotlib.imshow:
from PIL import Image, ImageOps
import matplotlib.pyplot as plt
import numpy as np
i = Image.open("frog.jpg")
g = ImageOps.grayscale(i)
fig, ax = plt.subplots(1, 1)
ax.imshow(np.array(g), cmap=plt.cm.Blues)
plt.show()
Result:

Related

Python invert colors

I need to invert the colors of an image in Python using PIL, the problem is that I only have to invert the colors of the right half of the image and I don't know how to do it. Here is an example of how the image should look like.
And here is the code I made, bot it invert the colors of all the image.
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import PIL.ImageOps
image_file = Image.open("Abbildung1.jpg")
image_file.load()
image_data = np.asarray(image_file, dtype=np.uint8)
inverted_image = PIL.ImageOps.invert(image_file)
inverted_image.save("neuesBild.jpg")
You can use numpy to make two parts of the image then apply the transformation and finally combine it.
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import PIL.ImageOps
image_file = Image.open("some_image.jpeg")
image_file.load()
image_data = np.asarray(image_file, dtype=np.uint8)
width = image_data.shape[1]
left_half = image_data[:,0:width//2, :]
right_half = image_data[:,width//2:, :]
inverted_image_right = np.asarray(PIL.ImageOps.invert(Image.fromarray(right_half)))
total_image = np.hstack((left_half, inverted_image_right))
inverted_image = Image.fromarray(total_image)
inverted_image.save("invertion_half.jpeg")
That's it:
from PIL import Image
import PIL.ImageOps
img = Image.open('img.png').convert('RGB')
img.paste(ImageOps.invert(img.crop((img.width/2,0,img.width,img.height))),box=(int(img.width/2),0))
We have croped, inverted and pasted this croped-inverted image back.
Then you can check:
img.show()

Turn a image to grayscale in python

I'm a newbie to tensorflow and keras, and I'm trying to create a CNN model for The Street View House Numbers (SVHN) dataset. The dataset contains color images, and I want to turn them in grayscale. I found some code on the web that claims they're turning image to grayscale, but it just changes colors.
People are reading the second image with a gray colormap. Is there any way to actually turn this image to grayscale?
(I do not know how to process an image in this kind of programming languages. If this is a dumb question, please forgive me and provide a brief explain.)
I provided images and code below, I'll be grateful for any help.
Code:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
#Read picture:
picture = plt.imread('google.jpg')
print("google logo's shape is: ",picture.shape) #(500, 500, 3)
#saving picture as an np array:
pic_array = np.array(picture)
#Turning image to grayscale
grayscale_pic = np.expand_dims(np.dot(pic_array[...,:3],[0.299, 0.587, 0.144]),axis = 0)
#Dimensions shifted, (probly my mistake):
grayscale_pic = np.moveaxis(grayscale_pic, 0, -1)
print("shape of grayscale pic = ", grayscale_pic.shape) # (500, 500, 1)
plt.imshow(picture) #Figure_1
plt.show()
plt.imshow(grayscale_pic) #Figure_2
plt.show()
U can convert a normal image to grayscale using opencv like this:
import cv2
gray = cv2.cvtColor(picture,cv2.COLOR_RGB2GRAY)
If u prefer numpy over opencv, then u can use this:
gray = np.dot(picture[...,:3], [0.2989, 0.5870, 0.1140])
You can use matplotlib with weights:
import numpy as np
import matplotlib.pyplot as plt
an_image = plt.imread('google.png')
rgb_weights = [0.2989, 0.5870, 0.1140]
grayscale_image = np.dot(an_image[..., :3], rgb_weights)
plt.axis('off')
plt.imshow(grayscale_image, cmap=plt.get_cmap("gray"), aspect='auto')
plt.show()
Output:
If you remove aspect='auto' parameter:
or you can use opencv
import cv2
an_image = cv2.imread("google.png")
grey_image = cv2.cvtColor(an_image, cv2.COLOR_BGR2GRAY)
or you can use PIL library
from PIL import Image
img = Image.open('google.png').convert('LA')
LA mode is L (8-bit pixels, black and white) with ALPHA desinged for .gif and .png. If your images are .jpeg use L.
Output:
There can be several ways to do this. One potential way is to utilize PIL(Pillow) library:
from PIL import Image
import matplotlib.pyplot as plt
picture = Image.open('google.jpg')
grayscale_pic = picture.convert('LA')
grayscale_pic.save('grayscale.png')
fig,ax = plt.subplots(nrows=1, ncols=2)
plt.subplot(1,2,1)
plt.imshow(picture)
plt.subplot(1,2,2)
plt.imshow(grayscale_pic)
plt.show()
Output:

How to write PILcode with opencv

from PIL import Image, ImageDraw, ImageFilter
im_rgb = Image.open('x.JPG')
im_a = Image.open('blackandwhitex.png').convert('L').resize(im_rgb.size)
im_rgba = im_rgb.copy()
im_rgba.putalpha(im_a)
im_rgba.save('xtransparent.png')
Thanks to this code I made transparent on blacka and put another photo on it, so in the end I have transparent background.
How it will be look like in opencv. I need open cv, because PIL rotate photos. But it is hard to write this for someone new in opencv and google colab.
I've made transparent black using this code:
import cv2
file_name = "x.png"
src = cv2.imread(file_name, 1)
tmp = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
_,alpha = cv2.threshold(tmp,0,255,cv2.THRESH_BINARY)
b, g, r = cv2.split(src)
rgba = [b,g,r, alpha]
dst = cv2.merge(rgba,4)
cv2.imwrite("newx.png", dst)
It's not so good...
After puttingc togehter second and third photo I want this:
It is the input of using PIL. (All images have the same size.)
Show color photo:
%pylab inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img2=mpimg.imread('colorphoto.JPG')
imgplot = plt.imshow(img2)
plt.show()
Some photos are flipped after that.
Show black and white photo:
%pylab inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img2=mpimg.imread('bawphoto.png')
imgplot = plt.imshow(img2)
plt.show()
For some of the photos I need to use:
from PIL import Image
def rotate(image_path, saved_location):
image_obj = Image.open(image_path)
transposed = image_obj.transpose(Image.ROTATE_90)
transposed = transposed.transpose(Image.ROTATE_180)
transposed.save(saved_location)
transposed.show()
if __name__ == '__main__':
image = 'colorphoto.JPG'
rotate(image, 'rotated_colorphoto.JPG')
And after that I convert them into one photo:
from PIL import Image, ImageDraw, ImageFilter
im_rgb = Image.open('rotated_colorphoto.JPG')
im_a = Image.open('bawphoto.png').convert('L').resize(im_rgb.size)
im_rgba = im_rgb.copy()
im_rgba.putalpha(im_a)
im_rgba.save('imagewithtransparentbackground.png')
I don't want flipped photos. I need them original size not flipped..

Adaptive Histogram Equalization in Python

I am trying to implement adaptive histogram equalization in python. I take an image and split it into smaller regions and then apply the traditional histogram equalization to it. I then combine the smaller images into one and obtain a final resultant image. The final image appears to be very blocky in nature and has different contrast levels for each individual region. Is there a way I could maintain a uniform contrast for each individual image so that it looks like a single image instead of smaller images stitched together.
import cv2
import numpy as np
from matplotlib import pyplot as plt
from scipy.misc import imsave
from scipy import ndimage
from scipy import misc
import scipy.misc
import scipy
import image_slicer
from image_slicer import join
from PIL import Image
img = 'watch.png'
num_tiles = 25
tiles = image_slicer.slice(img, num_tiles)
for tile in tiles:
img = scipy.misc.imread(tile.filename)
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
cdf_normalized = cdf *hist.max()/ cdf.max()
plt.plot(cdf_normalized, color = 'g')
plt.hist(img.flatten(),256,[0,256], color = 'g')
plt.xlim([0,256])
plt.legend(('cdf','histogram'), loc = 'upper left')
cdf_m = np.ma.masked_equal(cdf,0)
cdf_o = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_o,0).astype('uint8')
img3 = cdf[img]
cv2.imwrite(tile.filename,img3)
tile.image = Image.open(tile.filename
image = join(tiles)
image.save('watch-join.png')
I reviewed the actual algorithm and came up with the following implementation. I am sure there is a better way to do this. Any suggestions are appreciated.
import numpy as np
import cv2
img = cv2.imread('watch.png',0)
print img
img_size=img.shape
print img_size
img_mod = np.zeros((600, 800))
for i in range(0,img_size[0]-30):
for j in range(0,img_size[1]-30):
kernel = img[i:i+30,j:j+30]
for k in range(0,30):
for l in range(0,30):
element = kernel[k,l]
rank = 0
for m in range(0,30):
for n in range(0,30):
if(kernel[k,l]>kernel[m,n]):
rank = rank + 1
img_mod[i,j] = ((rank * 255 )/900)
im = np.array(img_mod, dtype = np.uint8)
cv2.imwrite('target.png',im)

How to crop the background from an inclined image?

The input is an image(document) from the scanner and my task is to crop the background and return only the document, just like this: Input Output
I've done this through thresholding and getbbox:
import matplotlib.pyplot as plt
import matplotlib.image as pli
from skimage.filters import threshold_otsu as otsu
from PIL import Image
cnh_gray = Image.open("cnh.jpg").convert('L')
cnh_gray.save('cnhgray.jpg')
img = pli.imread('cnhgray.jpg')
imagem = Image.open('cnhgray.jpg')
thresh = otsu(img)
mask = img < thresh
msk = Image.fromarray(mask,'L')
box = msk.getbbox()
crop = imagem.crop(box)
The problem is: The getbbox function doesn't work when the document isn't vertical. Since I don't know the angle, how can I rotate the image to use the getbbox funcion? If there's another function that I can use for inclined images instead of getbbox, please tell me.
Thanks for the help.

Categories

Resources