How would I take an RGB image in Python and convert it to black OR white? Not grayscale, I want each pixel to be either fully black (0, 0, 0) or fully white (255, 255, 255).
Is there any built-in functionality for this in the popular Python image processing libraries? If not, would the best way be just to loop through each pixel, if it's closer to white set it to white, if it's closer to black set it to black?
Scaling to Black and White
Convert to grayscale and then scale to white or black (whichever is closest).
Original:
Result:
Pure Pillow implementation
Install pillow
if you haven't already:
$ pip install pillow
Pillow (or PIL) can help you work with images effectively.
from PIL import Image
col = Image.open("cat-tied-icon.png")
gray = col.convert('L')
bw = gray.point(lambda x: 0 if x<128 else 255, '1')
bw.save("result_bw.png")
Alternatively, you can use Pillow with numpy.
Pillow + Numpy Bitmasks Approach
You'll need to install numpy:
$ pip install numpy
Numpy needs a copy of the array to operate on, but the result is the same.
from PIL import Image
import numpy as np
col = Image.open("cat-tied-icon.png")
gray = col.convert('L')
# Let numpy do the heavy lifting for converting pixels to pure black or white
bw = np.asarray(gray).copy()
# Pixel range is 0...255, 256/2 = 128
bw[bw < 128] = 0 # Black
bw[bw >= 128] = 255 # White
# Now we put it back in Pillow/PIL land
imfile = Image.fromarray(bw)
imfile.save("result_bw.png")
Black and White using Pillow, with dithering
Using pillow you can convert it directly to black and white. It will look like it has shades of grey but your brain is tricking you! (Black and white near each other look like grey)
from PIL import Image
image_file = Image.open("cat-tied-icon.png") # open colour image
image_file = image_file.convert('1') # convert image to black and white
image_file.save('/tmp/result.png')
Original:
Converted:
Black and White using Pillow, without dithering
from PIL import Image
image_file = Image.open("cat-tied-icon.png") # open color image
image_file = image_file.convert('1', dither=Image.NONE) # convert image to black and white
image_file.save('/tmp/result.png')
I would suggest converting to grayscale, then simply applying a threshold (halfway, or mean or meadian, if you so choose) to it.
from PIL import Image
col = Image.open('myimage.jpg')
gry = col.convert('L')
grarray = np.asarray(gry)
bw = (grarray > grarray.mean())*255
imshow(bw)
Pillow, with dithering
Using pillow you can convert it directly to black and white. It will look like it has shades of grey but your brain is tricking you! (Black and white near each other look like grey)
from PIL import Image
image_file = Image.open("cat-tied-icon.png") # open colour image
image_file = image_file.convert('1') # convert image to black and white
image_file.save('/tmp/result.png')
Original:
Converted:
And you can use colorsys
(in the standard library) to convert rgb to hls and use the lightness value to determine black/white:
import colorsys
# convert rgb values from 0-255 to %
r = 120/255.0
g = 29/255.0
b = 200/255.0
h, l, s = colorsys.rgb_to_hls(r, g, b)
if l >= .5:
# color is lighter
result_rgb = (255, 255, 255)
elif l < .5:
# color is darker
result_rgb = (0,0,0)
Using opencv You can easily convert rgb to binary image
import cv2
%matplotlib inline
import matplotlib.pyplot as plt
from skimage import io
from PIL import Image
import numpy as np
img = io.imread('http://www.bogotobogo.com/Matlab/images/MATLAB_DEMO_IMAGES/football.jpg')
img = cv2.cvtColor(img, cv2.IMREAD_COLOR)
imR=img[:,:,0] #only taking gray channel
print(img.shape)
plt.imshow(imR, cmap=plt.get_cmap('gray'))
#Gray Image
plt.imshow(imR)
plt.title('my picture')
plt.show()
#Histogram Analyze
imgg=imR
hist = cv2.calcHist([imgg],[0],None,[256],[0,256])
plt.hist(imgg.ravel(),256,[0,256])
# show the plotting graph of an image
plt.show()
#Black And White
height,width=imgg.shape
for i in range(0,height):
for j in range(0,width):
if(imgg[i][j]>60):
imgg[i][j]=255
else:
imgg[i][j]=0
plt.imshow(imgg)
img_rgb = cv2.imread('image.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
(threshi, img_bw) = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)