How to create a white image in Python? - python

Upon doing my homework, I stumbled across a problem concerning Python and image manipulation. I must say, using the Image lib is not an option. So here it is
from scipy.misc import imread,imsave
from numpy import zeros
imga = zeros([100,100,3])
h = len(imga)
w = len(imga[0])
for y in range(h):
for x in range(w):
imga[y,x] = [255,255,255]
imsave("Result.jpg",imga)
I would assume it makes my picture white, but it turns it black, and I have no idea why
It's not about the code (and I know it looks very ugly). Its just about the fact, that it is a black image.

Every color in an image is represented by one byte. So to create an image array, you should set it's dtype to uint8.
And, you don't need for-loop to set every elements to 255, you can use fill() method or slice index:
import numpy as np
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # or img[:] = 255

Easy!
Check the below Code:
whiteFrame = 255 * np.ones((1000,1000,3), np.uint8)
255 is the color for filling the bytes.
1000, 1000 is the size of the image.
3 is the color channel for the image.
And unit8 is the type
Goodluck

Here's a simple way to create a white image with a python one liner.
$ python3 -c "from PIL import Image;Image.new('RGB', (1900, 1080), color = (255,255,255)).save('Img.jpg')"
This will create a white image with a width of 1900 and hight of 1080.

When creating imga, you need to set the unit type. Specifically, change the following line of code:
imga = zeros([100,100,3], dtype=np.uint8)
And, add the following to your imports:
import numpy as np
That gives a white image on my machine.

The headline is too broad and shows up at Google first. I needed a white image and used PIL and numpy. PILlow actually works well with numpy
import numpy as np
from PIL import Image
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # numpy array!
im = Image.fromarray(img) #convert numpy array to image
im.save('whh.jpg')

Just regarding the headline of this question, I did need a white image as well as a pillow input. And the solutions presented here did not work for me.
Therefore here a different way to generate white images for other purposes:
from PIL import Image
img = Image.new('RGB', (200, 50), color = (255,255,255))
Size and color may be changed in the 2nd and 3rd parameter of the Image.new()-function.
And if you want to write something on this image or save it, this would be example code for this.
from PIL import ImageFont, ImageDraw
fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 30)
ImageDraw.Draw(img).text((0,0), "hello world", font=fnt, fill=(0,0,0))
img.save('test.jpg')

# Create an array with a required colours
# The colours are given in BGR [B, G, R]
# The array is created with values of ones, the size is (H, W, Channels)
# The format of the array is uint8
# This array needs to be converted to an image of type uint8
selectedColor = [75, 19, 77] * np.ones((640, 480, 3), np.uint8)
imgSelectedColor = np.uint8(np.absolute(selectedColor))

Related

Converting images to grayscale using Python

i have to convert a image from, rgb scale to grayscale image using only 4 lines, in "insert code part", I can do this using CV, but instead I have convert a color image to Black and White, by calculate the average of the RGB values. If the average is closer to 255, the pixel is set to white (255), otherwise to black (0). For conversion to a greyscale image, the pixel values have to be set to the averages of the RGB values in principle.i should use a weighting factor for each of the RGB values.
import matplotlib.pyplot
import numpy as np
myImage = matplotlib.pyplot.imread('flower.png')
height=myImage.shape[0]
width=myImage.shape[1]
for x in range(0, height-1):
for y in range(0,width-1):
#insert code
imgplot = matplotlib.pyplot.imshow(myImage)
matplotlib.pyplot.show()
You don't need a loop.
mono = (myImage.mean(2) >= 128) * 255
There is another alternative which is more efficient to use: PIL
you can install it using
pip install pillow \\ pip3 install pillow
and import it using import PIL
this package has a lot of different ways of converting an image into black and white but I would suggest the easiest method:
from PIL import Image
file = "~/Pictures/Test.jpg"
img = Image.open(file)
img = img.convert("L")
img.save("~/Pictures/Test-baw.jpg")
if you are interested in other methods, you can also check this out ;)

Convert a large grayscale PIL image to black and transparent

I am trying to use a large 2d array to create an image mask with black and transparent parts. Originally, the input 2d array was a PIL.Image that was loaded in grayscale ('L') mode. So it contains values between 0 and 255. And now I want to replace all the 0s with [0,0,0,255] (black stays black) and all values >0 should be [0,0,0,0] (transparent). I can do this simply like this:
import numpy as np
# generate some random test data - normally I just read the input image, which is fast
input_data = np.array([np.array([random.choice([0,10]) for x in range(22000)]) for y in range(9000)])
# create a new img containing black and transparent pixels (r,g,b,alpha) and this takes ages
overlay_img = [[[0, 0, 0, 255] if input_data[y][x] == 0 else [0, 0, 0, 0] for x in range(len(input_data[0]))] for y in range(len(input_data))]
overlay_img = np.array(overlay_img)
This takes quite some time because the input data is so large (~22000x9000). I am curious if it is somehow possible to do this faster. I also tried np.where, but I could not get it to work. Maybe there is even a way to directly change the PIL image?
fyi: In the end, I just want to plot this image on top of my matplotlib plot with imshow, so that only the relevant regions are visible (where the image is transparent) and the rest is hidden/black.
Here just a very quick and small example of what I want to do:
I think you want this, but you haven't shown your code for imshow():
#!/usr/bin/env python3
import random
import numpy as np
# Set up dimensions and random input image
h, w = 9000, 22000
im = np.random.randint(0, 11, (h,w), dtype=np.uint8)
# Create 4-channel mask image
mask = np.zeros((h,w,4), dtype=np.uint8)
mask[...,3] = (im==0) * 255
The last line takes 800ms on my MacBook Pro.
If you need a bit more performance, you can use numexpr as follows and the time required is 300ms instead of 800ms:
import random
import numexpr as ne
import numpy as np
# Set up dimensions and random input image
h, w = 9000, 22000
im = np.random.randint(0, 11, (h,w), dtype=np.uint8)
# Create 4-channel mask image
mask = np.zeros((h,w,4), dtype=np.uint8)
# Same but with "numexpr"
mask[...,3] = ne.evaluate("(im==0)*255")

Copy black pixels from image and paste in same image with offset

I've been trying to get some masking to work in my pictures, but I guess there has to be an easier way to do this:
a) I have an BW picture (photo) showing numbers from a display, "test.png" ( 1000x300 px)
b) I want to copy (only) the black pixels and paste them in the same image
c) When pasting, I want the paste to be offset by its "original" place by 20px (both x/y)
I try running the code below but get an error:
import cv2
test = Image.open('test.png')
np = Image.new('1', (1000, 300), 255)
mask = np.bitwise_and(test, np.roll(test, 20, (0,1)))
mask.save('mask.png')
I get AttributeError: 'Image' object has no attribute 'bitwise_and'
If image is logical (0/1) then:
res=np.bitwise_and(image, np.roll(image, 20, (0,1)))
You can do it like this:
from PIL import Image
import numpy as np
# Load image and make Numpy array
im = Image.open('image.png').convert('L')
na = np.array(im)
# Get x,y coordinates of black pixels
Y, X = np.where(na==0)
# Make pixels 30 across and 30 down from them black
na[Y+30, X+30] = 0
# Convert back to PIL Image and save
Image.fromarray(na).save('result.png')

How do I resize image but maintain features in the image? Python

I have an image that looks like this:
array.resize(20,20,3)
img = Image.fromarray(array, 'RGB')
img.save('my.png',quality=90)
img.show()
It is currently a 500x500x3 NumPy array. The underlying space is a 20x20 grid of cells and I want to resize the image so that each grid cell has entries in a 20x20x3 NumPy Array corresponding to it's RGB values instead of (500/20)*(500/20)*3 entries per cell.
The code above does not seem to work unfortunately as it seems to be giving more entries per cell than I expected although I am not 100% sure.
To resize image with pillow you can use Image.resize()
from PIL import Image
import urllib.request
import numpy as np
data = urllib.request.urlopen('https://i.stack.imgur.com/7bPlZ.png')
old_img = Image.open(data)
new_img = old_img.resize((20, 20))
new_img.save('my.png',quality=90)
new_img.show()
array = np.array(new_img)
print(array)
But resizing image you can create pixels with half-tones.
Maybe you should get values directly from numpy.array. You have solid colors so you could get single pixel from every cell - because every cell has size 25x25 so it could be:
new_array = old_array[::25,::25,:]
and then you don't have to convert to image.
And if you convert this array to image then it should be sharper than create with Image.resize.
from PIL import Image
import urllib.request
import numpy as np
data = urllib.request.urlopen('https://i.stack.imgur.com/7bPlZ.png')
old_img = Image.open(data)
old_array = np.array(old_img)
new_array = array[::25,::25,:]
print(new_array)
new_img = Image.fromarray(new_array)
new_img.save('my.png',quality=90)
new_img.show()
Try this
size = 20, 20
img = Image.fromarray(array, 'RGB')
img.thumbnail(size, Image.ANTIALIAS)
img.save('my.png',quality=90)
img.show()

convert image to value matrix

I have an image which is like a chess board with 4 colors (Black, white, Red, Blue). I have to convert this image to a matrix of numbers: 1 for white, 2 for black, 3 for red so on.
For example the image:
should be converted to the matrix:
[[1,2,1,2,1,2...]
[2,1,2,1,2,1...]
...]
I'd prefer a solution in python.
I am not sure about SVG Images but lets suppose you have an image format readable by PIL (e.g. GIF, TIFF, JPEG, BMP, ...). Then you can read it using PIL like that:
import Image
img = Image.open("Chess_Board.bmp")
Now we want do do quantization, so the image pixels are not RGB anymore but a color index from 0 to 3 (suppose you want 4 different colors):
quantized = img.convert('P', palette=Image.ADAPTIVE, colors=4)
Next I suppose we convert it to numpy for easier access of the individual pixels. Then we do numpy magic to count how many go into one block:
import numpy as np
a = np.array(quantized)
blockLengthX = np.argmin(a[0]==a[0,0])
blockLengthY = np.argmin(a[:,0]==a[0,0])
After that it is easy. We just access the array using stepsize blockLengthX for cols and blockLengthY for rows:
result = a[::blockLengthX, ::blockLengthY]
Of course this assumes all of your blocks are exactly the same size.
Here is the complete program for easier copy and paste. I also shortened a bit:
import Image
import numpy as np
img = Image.open("Chess_Board.bmp")
a = np.array(img.convert('P', palette=Image.ADAPTIVE, colors=4))
blockLengthX = np.argmin(a[0]==a[0,0])
blockLengthY = np.argmin(a[:,0]==a[0,0])
result = a[::blockLengthX, ::blockLengthY]

Categories