I want to convert my b&w image(.png) to binary array(black is 1 white is 0). I have written some code, but it's not working. Error says: argument 2 to map() must support iteration.
Here is my code:
from PIL import Image
from resizeimage import resizeimage
import sys
def threshold(col):
s = sum(col)
return int(s > 255 * 3 // 2)
img = Image.open("filename.png")
ratio = float((img.size[1]) / (img.size[0]))
img = resizeimage.resize_cover(img, [100, int(ratio * 100)])
pixels = img.getdata()
binary = list(map(threshold, img))
array2d = [binary[i * img.size[0] : (i+1) * img.size[0]] for i in range(img.size[1])]
print('\n'.join(''.join(map(str, line)) for line in array2d))
Here is the image:
You need to convert your image to grayscale first, since PIL opens it as RGB. Then, invert the 0 & 255 values. Then, you can convert the non-zero values to 1. Here's one way:
from PIL import Image
import numpy as np
img = Image.open('bw_circle.png').convert('L')
np_img = np.array(img)
np_img = ~np_img # invert B&W
np_img[np_img > 0] = 1
And an alternative way using PIL for the inversion:
from PIL import Image, ImageOps
import numpy as np
img = Image.open('bw_circle.png').convert('L')
img_inverted = ImageOps.invert(img)
np_img = np.array(img_inverted)
np_img[np_img > 0] = 1
Related
How to calculate each channel contrast in images?
Since they are lot of contrast definitions out there
Webar Contrast
Michelson Contrast
RMS contrast
I need to calculate these contrasts.
from PIL import Image
import numpy as np
from numpy import mean, sqrt, square
im = Image.open("leaf.jpg") # Image file name
pixels = list(im.getdata())
width, height = im.size
pixels = np.asarray([pixels[i * width:(i + 1) * width] for i in range(height)], dtype=int)
ch_1 = pixels[:,:,0]
ch_2 = pixels[:,:,1]
ch_3 = pixels[:,:,2]
rms_of_ch1 = sqrt(mean(square(ch_1)))
rms_of_ch2 = sqrt(mean(square(ch_2)))
rms_of_ch3 = sqrt(mean(square(ch_3)))
I have read in some images with the code below. These images are of different sizes. In order to get them to equal sizes, I would like to add a black frame around the images. I found some code to do this for a single image but not for a list as in my case.
import cv2
import numpy
import glob
import matplotlib.pyplot as plt
from PIL import Image, ImageOps
folders = glob.glob(r'path\to\images\*')
imagenames_list = []
for folder in folders:
for f in glob.glob(folder+'/*.png'):
imagenames_list.append(f)
read_images = []
for image in imagenames_list:
read_images.append(cv2.imread(image, cv2.IMREAD_GRAYSCALE))
To add a black frame for a single picture I used this code:
from PIL import Image
import numpy as np
old_im = Image.open('path/to/single/picture/*.png')
old_size = old_im.size
print(old_size)
new_size = (500, 500)
print(new_size)
new_im = Image.new("RGB", new_size)
x = int((new_size[0]-old_size[0])/2)
y = int((new_size[1]-old_size[1])/2)
new_im.paste(old_im, (x,y))
Image read by OpenCV are just numpy arrays. You can just use numpy slicing to copy:
def makeborder(cv2img, new_width, new_height):
'''
cv2img: an image returned by cv2.imread()
'''
# gray scale or BGR/BGRA
if len(cv2img.shape) == 2:
new_shape = (new_height, new_width)
else:
new_shape = (new_height, new_width, cv2img.shape[-1])
new_img = np.zeros(new_shape, dtype=cv2img.dtype)
# compute the offsets, similar to your x & y
offset_height = (new_height - cv2img.shape[0])//2
offset_weight = (new_width - cv2img.shape[1])//2
# should check offset_height >= 0 and offset_weight >= 0
# but we skip here
# ...
# now we just use numpy slicing to copy
new_img[offset_height:offset_height + cv2img.shape[0],
offset_width: offset_width + cv2img.shape[1]] \
= cv2img
return new_img
Here I use the PIL Library to read and manipulate images. I am confused, how to create a new image from the list of arrays containing binary pixel data, after being converted to binary images.
I have tried it, but the resulting image is of type RGB, not a binary image. The following is the code that I wrote:
from PIL import Image
import numpy as np
img = Image.open('data_train/ga.jpeg')
pixels = img.load()
width, height = img.size
all_pixels = []
for x in range(width):
for y in range(height):
hpixel = pixels[x, y]
img_gray = (0.2989 * hpixel[0]) + (0.5870 * hpixel[1]) + (0.1140 * hpixel[2])
if img_gray >= 110:
all_pixels.append('1')
else:
all_pixels.append('0')
data_isi = {'0': 0,
'1': 255}
data = [data_isi[letter] for letter in all_pixels]
img_new = Image.fromarray(data)
img_new.save('data_train/gabiner.jpeg')
Updated Answer
As you are required to use a for loop, you could go with something more like this:
#!/usr/bin/env python3
from PIL import Image
# Load image and get dimensions
img = Image.open('start.jpg').convert('RGB')
width, height = img.size
# Actually load input pixels, else PIL is too lazy
imi = img.load()
# List of result pixels
imo = []
for y in range(height):
for x in range(width):
R, G, B = imi[x, y]
gray = (0.2989 * R) + (0.5870 * G) + (0.1140 * B)
if gray >= 110:
imo.append(255)
else:
imo.append(0)
# Make output image and put output pixels into it
result = Image.new('L', (width,height))
result.putdata(imo)
# Save result
result.save('result.png')
Which turns this start image:
Into this result:
Original Answer
You appear to be converting the image to greyscale and thresholding at 110, which can be done much more simply, and faster, like this:
#!/usr/local/bin/python3
from PIL import Image
# Load image and make greyscale
im = Image.open('image.png').convert('L')
# Threshold to make black and white
thr = im.point(lambda p: p > 110 and 255)
# Save result
thr.save('result.png')
I'm trying to convert an image from a numpy array format to a PIL one. This is my code:
img = numpy.array(image)
row,col,ch= np.array(img).shape
mean = 0
# var = 0.1
# sigma = var**0.5
gauss = np.random.normal(mean,1,(row,col,ch))
gauss = gauss.reshape(row,col,ch)
noisy = img + gauss
im = Image.fromarray(noisy)
The input to this method is a PIL image. This method should add Gaussian noise to the image and return it as a PIL image once more.
Any help is greatly appreciated!
In my comments I meant that you do something like this:
import numpy as np
from PIL import Image
img = np.array(image)
mean = 0
# var = 0.1
# sigma = var**0.5
gauss = np.random.normal(mean, 1, img.shape)
# normalize image to range [0,255]
noisy = img + gauss
minv = np.amin(noisy)
maxv = np.amax(noisy)
noisy = (255 * (noisy - minv) / (maxv - minv)).astype(np.uint8)
im = Image.fromarray(noisy)
I tried coding for EyeMapC but couldn't get expected output.
EyeMapC = 1/3(Cb2 + Cr'2 + Cb/Cr)
where Cr' = 255 - Cr
Here's my code
from __future__ import division
import cv2
import numpy as np
img = cv2.imread('img/file.jpg')
EyeMap = cv2.cvtColor(img,cv2.COLOR_BGR2YCR_CB)
y,Cr,Cb = cv2.split(EyeMap)
Q = np.square(Cb) #,dtype=np.float64)
Cr_bar = (255-Cr)
R = np.square(Cr_bar) #,dtype=np.float64)
G = Cb/Cr
EyeC = (Q/3+R/3+G/3)
#EyeC = np.mod(EyeC,255)
cv2.imshow('EyeC',EyeC)
cv2.waitKey(0)
cv2.destroyAllWindows()
Cb2 and Cr'2 have to be normalized between [0,255] before putting in formula or the final EyeC value needs to be normalized ?
Original Image: Original Image
Output: Output Image