Image Array "ValueError: setting an array element with a sequence" - python

I want to do some operation in numpy array. Actually I'm trying to zoom an image using the nearest neighbour rule. I have facing that above titled issue.
import cv2
import numpy as np
from numpy import ndarray
img = cv2.imread('abc.jpg')
rows = img.shape[0]*2
cols = img.shape[1]*2
zoomed = np.zeros((rows, cols), dtype=img.dtype)
for i in range(0, rows):
for j in range(0, cols):
zoomed[i][j] = img[int(i/2)][int(j/2)]
cv2.imshow('Input Image', img)
cv2.imshow('Zoomed Image', zoomed)
cv2.waitKey(0)

Try:
zoomed = np.zeros((rows, cols, 3), dtype=img.dtype)
The error you're getting is happening because img[int(i/2)][int(j/2)] is actually three RGB values and zoomed[i][j] can only hold integers. Creating zoomed to have shape (rows, cols, 3) allows zoomed to hold 3 integers at every row, column location.

Related

RGB disappears after processing the image

I am working with an image (2192 x 2921 x 3) to replace the pixel values equal to 0 with those of its previous nonzero values.
The code finishes without errors, but the output image is no longer RGB.
Is there anything erroneous in my code that causing this?
The function "fill_zeros_with_last" is from StackOverflow.
The code is given below:
import numpy as np
import cv2
from PIL import Image
def fill_zeros_with_last(arr):
prev = np.arange(len(arr))
prev[arr == 0] = 0
prev = np.maximum.accumulate(prev)
return arr[prev]
image = cv2.imread('path\to\image')
image_modified = [] # to store the processed image
for k in range(3):
for j in range(2921):
image1 = fill_zeros_with_last(image[:, j, k]) # replaces 0s with the previous nonzero value.
image_modified.append(image1)
image_modified = np.reshape(image_modified, ((2192, 2921, 3))) # to reshape the image
image_modified = image_modified.astype('uint8') # convert to uint8
img1 = Image.fromarray(image_modified, 'RGB') # convert to RGB
img1.save('image_modified.png') # save image
Here is a sample input image:
Sample output:
It looks like you are confused by the data ordering of NumPy array storing an OpenCV images.
The natural ordering of image in OpenCV (in memory) is "raw major" with b,g,r,b,g,r... data ordering:
Row 0: BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR
Row 1: BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR
Row 3: BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR
The indexing of the image array is: image[r, c, ch] (row, column, color_channel):
image_modified is a list of modified columns, each element in the list applies one color channel:
[
All columns of blue channel of column
Applies image column 0: BBBBBBBBBBBBBBBBBBBBBBBBBBB,
Applies image column 1: BBBBBBBBBBBBBBBBBBBBBBBBBBB,
Applies image column 2: BBBBBBBBBBBBBBBBBBBBBBBBBBB,
All columns of green channel of column
Applies image column 0: GGGGGGGGGGGGGGGGGGGGGGGGGGG,
Applies image column 1: GGGGGGGGGGGGGGGGGGGGGGGGGGG,
Applies image column 2: GGGGGGGGGGGGGGGGGGGGGGGGGGG,
All columns of red channel of column
Applies image column 0: RRRRRRRRRRRRRRRRRRRRRRRRRRR,
Applies image column 1: RRRRRRRRRRRRRRRRRRRRRRRRRRR,
Applies image column 2: RRRRRRRRRRRRRRRRRRRRRRRRRRR,
...
]
For fixing the ordering, we may apply np.reshape followed by np.transpose:
Reshape to 3 columns by <cols> rows by <rows> elements:
image_modified = np.reshape(image_modified, ((3, cols, rows)))
Transpose (permute) to rows by cols by 3:
image_modified = np.transpose(image_modified, (2, 1, 0))
Code sample:
import numpy as np
import cv2
def fill_zeros_with_last(arr):
prev = np.arange(len(arr))
prev[arr == 0] = 0
prev = np.maximum.accumulate(prev)
return arr[prev]
image = cv2.imread('test_image.jpg')
rows, cols = image.shape[0], image.shape[1] # Get height and width of image
image_modified = [] # to store the processed image
for k in range(3):
for j in range(cols):
image1 = fill_zeros_with_last(image[:, j, k]) # replaces 0s with the previous nonzero value.
image_modified.append(image1)
image_modified = np.reshape(image_modified, ((3, cols, rows))) # to reshape the image
image_modified = np.transpose(image_modified, (2, 1, 0)) # Fix the data ordering to match OpenCV convention
cv2.imwrite('image_modified.png', image_modified) # Use cv2.imwrite instead of using PIL because the color ordering is different.
Instead of messing with the ordering, we may use NumPy array for storing image_modified, instead of using a list:
import numpy as np
import cv2
def fill_zeros_with_last(arr):
prev = np.arange(len(arr))
prev[arr == 0] = 0
prev = np.maximum.accumulate(prev)
return arr[prev]
image = cv2.imread('test_image.jpg')
rows, cols = image.shape[0], image.shape[1] # Get height and width of image
#image_modified = [] # to store the processed image
image_modified = np.zeros_like(image) # Initialize image_modified to array of zeros with same size and type of image
for k in range(3):
for j in range(cols):
image1 = fill_zeros_with_last(image[:, j, k]) # replaces 0s with the previous nonzero value.
image_modified[:, j, k] = image1 # Update the column
#image_modified.append(image1)
cv2.imwrite('image_modified.png', image_modified) # Use cv2.imwrite instead of using PIL because the color ordering is different.
Output:

Different array dimensions causing failure to merge two images into one

When trying to join two images to create one:
img3 = imread('image_home.png')
img4 = imread('image_away.png')
result = np.hstack((img3,img4))
imwrite('Home_vs_Away.png', result)
This error sometimes appears:
all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 192 and the array at index 1 has size 191
How should I proceed to generate the image when there is this difference in array size when np.hstack does not work?
Note:
I use several images, so not always the largest image is the first and not always the largest is the second, it can be quite random which is the smallest or largest between the two.
You can manually add a row/column with a color of your choice to match the shapes. Or you can simply let cv2.resize handle the resizing for you. In this code I show how to use both methods.
import numpy as np
import cv2
img1 = cv2.imread("image_home.png")
img2 = cv2.imread("image_away.png")
# Method 1 (add a column and a row to the smallest image)
padded_img = np.ones(img1.shape, dtype="uint8")
color = np.array(img2[-1, -1]) # take the border color
padded_img[:-1, :-1, :] = img2
padded_img[-1, :, :] = color
padded_img[:, -1, :] = color
# Method 2 (let OpenCV handle the resizing)
padded_img = cv2.resize(img2, img1.shape[:2][::-1])
result = np.hstack((img1, padded_img))
cv2.imwrite("Home_vs_Away.png", result)

How to replace empty numpy array by grayscale image values

EDIT: I have found a workaround, which is assigning it to an array, then use that array to create a numpy array:
a = []
for i in range(0,width/image_size):
for j in range(0,height/image_size):
roi = img[image_size*j:image_size*(j+1),image_size*i:image_size*(i+1)]
a.append(roi)
arr = np.asarray(a) #HERE
ORIGINAL QUESTION:
I have created an empty numpy array of shape (180,28,28), which should hold 180 gray scale images size 28x28.
height, width = img.shape[:2]
arr = np.empty(((height/image_size)*(width/image_size), 28, 28 )) #arr.shape = (180,28,28)
I have multiple image regions size 28x28 that I want to populate into arr
for i in range(0,width/image_size):
for j in range(0,height/image_size):
roi = img[image_size*j:image_size*(j+1),image_size*i:image_size*(i+1)]
#HERE - how can I set the value in arr to be an (28x28) roi
Thank you.
I have found a workaround, which is assigning it to an array, then use that array to create a numpy array:
a = []
for i in range(0,width/image_size):
for j in range(0,height/image_size):
roi = img[image_size*j:image_size*(j+1),image_size*i:image_size*(i+1)]
a.append(roi)
arr = np.asarray(a) #assign it to numpy array here
However, I'm not sure if there is a better, or more elegant way to do it.

How do I display an image from an array in python

I am trying to use PIL to display an image from an array. The array is a long list of elements which are pixel values of an image. How do I display these pixel values as an image ?
You don't specify what kind of data is in your list, so I assume it is an array with 25 elements (grouped in 5 groups of 5), which will be converted to a 5 by 5 black & white image.
from PIL import Image
import random
data = [
[1,0,0,1,0],
[1,1,1,0,0],
[1,1,0,1,0],
[1,0,1,1,0],
[0,1,1,0,1],
]
img = Image.new("1", (5, 5))
pixels = img.load()
for i in range(img.size[0]):
for j in range(img.size[1]):
pixels[i, j] = data[i][j]
img.show()
img.save("img.png")
This is similar to this question: How can I write a binary array as an image in Python?

Import RGB value of each pixel in an image to 1-D array

How to import RGB value of each pixel in an image to 1-D array?
I am using following thing:
from PIL import Image
im = Image.open("bride.jpg")
pix = im.load()
print pix[x,y]
this imports it into 2-D array which is not iterable.
I want this same thing but in 1-D array.
You can flatten the pixels into a 1D array as follows:
width, height = im.size
pixels = [pix[i, j] for i in range(width) for j in range(height)]
Easy if you're using numpy, and no need to load the image.
from PIL import Image
import numpy as np
im = Image.open("bride.jpg")
pix_flatiter = np.asarray(im).flat # is an iterable
If you want to load the whole array, you can do:
pix_flat = np.asarray(im).flatten() # is an array

Categories