I have an image with this dimension (1280 x 960). To create a Blank image with this dimension, I use this:
import cv2
import numpy as np
blank_image2 = 255 * np.ones(shape=[960, 1280, 3], dtype=np.uint8)
Is it possible to create a blank image based on the dimension of another image? Something like this:
import cv2
import numpy as np
blank_image2 = 255 * np.ones(shape=image, dtype=np.uint8)
You can use the shape of the image object:
image = cv2.imread('img.jpg')
h, w, c = image.shape
blank_image2 = 255 * np.ones(shape=(h, w, c), dtype=np.uint8)
Amin is correct, I'm just sharing an alternative using 'ones_like' - similar to Mark's suggestion:
image = cv2.imread('img.jpg')
blank_image = 255 * np.ones_like(image , dtype = np.uint8)
Related
trying to save an inverted image, saved inverted RGB colour data in array pixelArray, then converted this to a numpy array. Not sure what is wrong but any help is appreciated.
from PIL import Image
import numpy as np
img = Image.open('image.jpg')
pixels = img.load()
width, height = img.size
pixelArray = []
for y in range(height):
for x in range(width):
r, g, b = pixels[x, y]
pixelArray.append((255-r,255-b,255-g))
invertedImageArray = np.array(pixelArray, dtype=np.uint8)
invertedImage = Image.fromarray(invertedImageArray, 'RGB')
invertedImage.save('inverted-image.jpeg')
img.show()
getting error code "ValueError : not enough image data"
Your np.array creates an array shape (4000000, 3) instead of (2000, 2000, 3).
Also, you may find that directly mapping the subtraction to the NumPy array is faster and easier
from PIL import Image
import numpy as np
img = Image.open('image.jpg')
pixelArray = np.array(img)
pixelArray = 255 - pixelArray
invertedImageArray = np.array(pixelArray, dtype=np.uint8)
invertedImage = Image.fromarray(invertedImageArray, 'RGB')
invertedImage.save('inverted-image.jpeg')
PIL already provides an easier way to invert the image colours with the ImageOps module.
from PIL import Image, ImageOps
img = Image.open('image.jpg')
invertedImage = ImageOps.invert(img)
invertedImage.save('inverted-image.jpeg')
I try to convert a RGB image to grayscale using python as a function but the problem is I give it a RGB image that have height, width and channel but after the code I should have an image with just height and width but it gives me an image with height, width and channel why?
def RGBtoGRAY(img):
height, width, channels = img.shape
grayimg = img
for i in range(height):
for j in range(width):
grayimg[i,j] = 0.3 * image[i,j][0] + 0.59 * image[i,j][1] + 0.11 * image[i,j][2]
return grayimg
the size of the input image is
image.shape
(533, 541, 3)
the size of the output image is
grayimage.shape
(533, 541, 3)
normally I want to find in the size of the output image
(533, 541)
You should avoid using for loops when performing image processing since it is very slow. Instead you can use Numpy which is highly optimized for vector operations. Using this grayscale conversion formula:
gray = R * .299 + G * .587 + B * .114
Method #1: apply_along_axis:
import cv2
import numpy as np
def grayscale(colors):
r, g, b = colors
return 0.299 * r + 0.587 * g + 0.114 * b
# Create image of size 100x100 of random pixels
# Convert to grayscale
image = np.random.randint(255, size=(100,100,3),dtype=np.uint8)
gray = np.apply_along_axis(grayscale, 2, image)
# Display
cv2.imshow('image', image)
cv2.imshow('gray', gray)
cv2.waitKey()
Before -> After
Method #2: cv2.cvtColor
You could use OpenCV directly and read in the image as grayscale with cv2.imread by passing in the cv2.IMREAD_GRAYSCALE or 0 flag to load the image as grayscale.
image = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE) # OR
# image = cv2.imread('img.png', 0)
If you already have the image loaded, you can convert the RGB or BGR image to grayscale using cv2.cvtColor
image = cv2.imread('img.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
Assuming you are using a for loop, because you intent to solve it "manually" (like C code), there are number of issues with your implementation:
The assignment grayimg = img in Python does not create a copy of img (the result is that grayimg referencing img).
You meant to use: grayimg = img.copy().
img has 3 dimensions, so when using grayimg = img, grayimg also has 3 dimensions.
You need to create grayimg with two dimensions.
Example for creating grayimg and initialize to zeros:
grayimg = np.zeros((height, width), img.dtype)
Inside the for loop, you are using image instead of img.
Here is a corrected version of RGBtoGRAY:
def RGBtoGRAY(img):
height, width, channels = img.shape
#grayimg = img
# Create height x width array with same type of img, and initialize with zeros.
grayimg = np.zeros((height, width), img.dtype)
for i in range(height):
for j in range(width):
grayimg[i,j] = 0.3 * img[i,j][0] + 0.59 * img[i,j][1] + 0.11 * img[i,j][2]
return grayimg
I'm trying to invert the pixels of an RGB image. That is, simply subtracting the intensity value of each channel (red, green, blue) of each pixel from 255.
I have the following so far:
from PIL import Image
im = Image.open('xyz.png')
rgb_im = im.convert('RGB')
width, height = im.size
output_im = Image.new('RGB', (width,height))
for w in range(width):
for h in range(height):
r,g,b = rgb_im.getpixel((w,h))
output_r = 255 - r
output_g = 255 - g
output_b = 255 - b
output_im[w,h] = (output_r, output_g, output_b)
When I run the above script, I get the following error:
Traceback (most recent call last):
File "image_inverse.py", line 31, in <module>
output_im[w,h] = (output_r, output_g, output_b)
File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 528, in __getattr__
raise AttributeError(name)
AttributeError: __setitem__
How can I solve this issue?
Thanks.
I guess you can use a vectorized operation if the image is a numpy array
from PIL import Image
im = Image.open('xyz.png')
im = 255 - im
You can use img.putpixel to assign the r,g,b,a values at each pixel-
from PIL import Image
im = Image.open('xyz.png')
rgb_im = im.convert('RGB')
width, height = im.size
output_im = Image.new('RGB', (width,height))
for w in range(width):
for h in range(height):
r,g,b = rgb_im.getpixel((w,h))
output_r = 255 - r
output_g = 255 - g
output_b = 255 - b
alpha = 1
output_im.putpixel((w, h), (output_r, output_g, output_b, alpha))
Convert image to numpy array, and you can perform the operation on all 2-dimensional arrays in one line
from PIL import Image
import numpy as np
image = Image.open('my_image.png')
# Convert Image to numpy array
image_array = np.array(image)
print(image_array.shape)
# Prints something like: (1024, 1024, 4)
# So we have 4 two-dimensional arrays: R, G, B, and the alpha channel
# Do `255 - x` for every element in the first 3 two-dimensional arrays: R, G, B
# Keep the 4th array (alpha channel) untouched
image_array[:, :, :3] = 255 - image_array[:, :, :3]
# Convert numpy array back to Image
inverted_image = Image.fromarray(image_array)
inverted_image.save('inverted.png')
I have a question like Mask a 3d array with a 2d mask in numpy, but the answer from that isn't working for my issue; I am trying to get elements of an RGB image selected based on a 2d mask. I created a 2d mask with values of 1, on the elements that I want to preserve, with the rest being 0. I then want to apply this mask to an RGB image array and want to retain values only for elements that match the mask value of 1. I tried this code and it bombed. How do I select the pixels (and its values) based on the mask location. My bombed code based on the solution that is in the link is below.
import numpy as np
from PIL import Image, ImageDraw
polygon = [(5,5), (10,5), (15,15), (2,15)]
width = 20
height = 20
# create a mask
img = Image.new('L', (width, height), 0)
ImageDraw.Draw(img).polygon(polygon, outline=1, fill=1)
mask = np.array(img)
mask = mask[:,:,np.newaxis]
a_arr = np.arange(1200).reshape(20,20,3) # create a test image type array
o_arr = np.ma.array(a_arr, mask=mask)
print o_arr
Why not just create a boolean array from your mask and index the image based on that array. Like so:
import numpy as np
from PIL import Image, ImageDraw
polygon = [(5,5), (10,5), (15,15), (2,15)]
width = 20
height = 20
# create a mask
img = Image.new('L', (width, height), 0)
ImageDraw.Draw(img).polygon(polygon, outline=1, fill=1)
mask = np.array(img)
b_mask = mask.astype(bool)
a_arr = np.arange(1200).reshape(20,20,3)
o_arr = a_arr[b_mask]
print(o_arr)
Update
Based on your comment have you tried just stacking the mask along the third dimension?
Instead of mask = mask[:, :, np.newaxis] use mask = np.dstack((mask, mask, mask))
I have a numpy array from image
So, is there a good way to do so:
from PIL import Image
a = Image.open('img')
a = a.filter(MOTION_BLUR)
import cv2
import numpy as np
img = cv2.imread('input.jpg')
cv2.imshow('Original', img)
size = 15
# generating the kernel
kernel_motion_blur = np.zeros((size, size))
kernel_motion_blur[int((size-1)/2), :] = np.ones(size)
kernel_motion_blur = kernel_motion_blur / size
# applying the kernel to the input image
output = cv2.filter2D(img, -1, kernel_motion_blur)
cv2.imshow('Motion Blur', output)
cv2.waitKey(0)
explanation you can found here
draw a rotated line as kernel, then apply a convolution filter to an image with that kernel.
The code below uses opencv framework.
import cv2
import numpy as np
#size - in pixels, size of motion blur
#angel - in degrees, direction of motion blur
def apply_motion_blur(image, size, angle):
k = np.zeros((size, size), dtype=np.float32)
k[ (size-1)// 2 , :] = np.ones(size, dtype=np.float32)
k = cv2.warpAffine(k, cv2.getRotationMatrix2D( (size / 2 -0.5 , size / 2 -0.5 ) , angle, 1.0), (size, size) )
k = k * ( 1.0 / np.sum(k) )
return cv2.filter2D(image, -1, k)
if you want to apply vertical, you can use this kernel:
kernel_motion_blur = np.zeros((size, size))
kernel_motion_blur[int(:, (size-1)/2)] = np.ones(size)
kernel_motion_blur = kernel_motion_blur / size
I would use matplotlib:
from PIL import Image
img = Image.open('your_image')
imgplot = plt.imshow(img, interpolation="bicubic")