I'm working with images in Python, and need to write a program that can handle both color and grayscale image. They're numpy array
Shape of Color: (512,512,3)
Shape of Grayscale:(512,512)
Now I have to loop through every channel of images, i.e. return :
For Color: im[:,:,0], im[:,:,1], im[:,:,2]
For Grayscale: im[:,:]
How to write them in the same format without any if condition? I tried im[:,:,0] for grayscale but it's out of range for the index.
I'm not sure if this is helpful or not, but numpy provides the ability to insert new axes:
im_new = im_old[:,:,np.newaxis]
As I understand it, this makes it so that im_new[i,j,k] is the same as im_old[i,j] for any k.
(also note that np.newaxis is simply an alias for None)
Related
Using the following code, PIL easily returns an array of single pixel values from an image. Not sure what the term for it is; but instead of a 3d array (RGB), it simplifies each pixel into one of 256 values.
from PIL import Image
im = Image.open(image_path, 'r')
pixel_values = list(im.getdata())
The question is, how can I edit pixels on an image with this same method? I believe the default arg for the putpixel method expects a 3d array (RGB), and if I only give one value; it only ranges over shades of black.
im.putpixel((x, y), value)
im.show()
I would like to be able to substitute integers (0-255) in for value and have access to the wider spectrum of discrete colors.
Is this possible? Seems like it should already be a built in method.
I have been trying to learn some image processing on OpenCV python. I have a 16-bit image, and I would like to apply a LUT conversion on this 16-bit image without reducing it to 8-bit. From the documentation, I read that LUT function in OpenCV is applicable only for 8-bit images. Does anyone know of an efficient way to use this function for 16-bit image?
I have used LUT coversion for 8-bit images. They work alright, but for 16bit images, the follwing error throws up: error: (-215:Assertion failed) (lutcn == cn || lutcn == 1) && \_lut.total() == 256 && \_lut.isContinuous() && (depth == CV_8U || depth == CV_8S) in function 'cv::LUT'.
Later, I found that this is because LUT function is application only for 8-bit images.
As you've already discovered, the implementation of OpenCV's LUT method only supports 8-bit LUTs. However, you can implement your own for arbitrary bit resolutions and it's actually quite simple. For each value in the image, this is directly used to access the LUT which will output the desired value. Because OpenCV interfaces with NumPy, you can just use the input image and index into the LUT directly in order to obtain the final output, taking advantage of NumPy array indexing.
First define a LUT - you'll need to ensure it's 16-bit and I'm assuming you have values that go from 0 to 65535 to respect the 16-bit resolution. Once you do that, use the table to index into your image. Here's an example using gamma adjusting:
import numpy as np
def adjust_gamma(image, gamma=1.0):
# build a lookup table mapping the pixel values [0, 65535] to
# their adjusted gamma values
inv_gamma = 1.0 / gamma
table = ((np.arange(0, 65536) / 65535) ** inv_gamma) * 65535
# Ensure table is 16-bit
table = table.astype(np.uint16)
# Now just index into this with the intensities to get the output
return table[image]
This applies inverse gamma adjusting of an input image, where we first generate a LUT that is 16-bit, then the image is used to directly index into it to create the output image. Take note that the input image is also assumed to be 16-bit. If you have any values that are beyond the 0-65535 range, this will give you an out-of-bounds indexing error.
Note - Multi-channel images
Take note that the above case assumes a single-channel image. If you want to apply this for multi-channel (i.e. RGB images), then you'll need to define a LUT for each channel and apply the LUT to each channel separately. The easiest way to do this would be a for loop across all channels. There are definitely more vectorized ways to do this in one-shot, but I will not diverge from the intent of your question and I want this to be as simple to read as possible.
First define a 2D LUT where each row in this matrix is a single LUT. Specifically, row i corresponds to the LUT to apply to channel i of the image. Once you're finished, loop through the channel dimension and apply the LUT. What we can also do to save some time is to preallocate the output image so that it's all zeroes, then fill in each channel accordingly.
Something like:
# Assume LUT is defined as `table` and it's a 2D NumPy array
output = np.zeros_like(image)
for i in range(image.shape[2]):
output[..., i] = table[i, image[..., i]]
output will contain the desired result. However, for the special case where the LUT is the same across all channels, you can just use the same 1D LUT you had previously and you can use the same indexing method that I talked about earlier:
output = table[image]
I have a dataset which comprises of the binary data of pixelated 50x50 images. The array shape is (50, 50, 90245). I want to reach 50x50 pixels of each of the 90245 images. How can I slice the array?
If data is the variable storing the image data, and i is the index of the image you want to access, then you can do:
data[:,:,i]
to get the desired image data.
If data is the variable storing the image data, and i is the index of the image you want to access, then you can do as #BrokenBenchmark suggested. In case you want a (50,50,1) 3D array as the output, you could do:
data[:,:,i:i+1]
to get the image as a 3D array.
Edit1: If you reshaped your data matrix to be of shape (90245,50,50), you can get the ith image by doing data[i,:,:] or just data[i] to get a (50,50) image. Similarly, to get a (1,50,50) image, you could do data[i:i+1,:,:] or just data[i:i+1].
Edit2: To reshape the array, you could use the swapaxes() function in numpy.
I am trying to convert an image into an array of pixels.
Here is my current code.
im = Image.open("beeleg.png")
pixels = im.load()
im.getdata() # doesn't work
print(pixels # doesn't work
Ideally, my end goal is to convert the image into a vector of just pixels, so for instance if I have an image of dimensions 100x100, then I want a vector of dimensions 1x10000, where each value is between [0, 255]. Then, divide each of the values in the array by 256 and add a bias of 1 in the front of the vector. However, I am not able to proceed with all this without being able to obtain an array. How to proceed?
Scipy's ndimage library is generally the go-to library for working with pixels as data (arrays). You can load an image from file (most common formats supported) using scipy.ndimage.imread into a numpy array which can be easily reshaped and mathematically operated on. The mode keyword can be used to specify a colorspace transformation upon load (convert an RGB image to black and white). In your case you asked for single color pixels from 0-255 (8bit grayscale) so you would use mode='L'. See The Documentation for usage / more useful functions.
If use OpenCV, gray=cv2.imread(image,0) will return a grayscale image with n rows x m cols single channel numpy array. rows, cols = gray.shape will return the height and width of the image.
I am using Pillow and numpy, but have a problem with conversion between Pillow Image object and numpy array.
when I execute following code, the result is weird.
im = Image.open(os.path.join(self.img_path, ifname))
print im.size
in_data = np.asarray(im, dtype=np.uint8)
print in_data.shape
result is
(1024, 768)
(768, 1024)
Why dimension is changed?
im maybe column-major while arrays in numpy are row-major
do in_data = in_data.T to transpose the python array
probably should check in_data with matplotlib's imshow to make sure the picture looks right.
But do you know that matplotlib comes with its own loading functions that gives you numpy arrays directly? See: http://matplotlib.org/users/image_tutorial.html
If your image is greyscale do:
in_data = in_data.T
but if you are working with rbg images you want to make sure your transpose operation is along only two axis:
in_data = np.transpose(in_data, (1,0,2))
actually this is because most image libraries give you images that are transpozed compared to numpy arrays. this is (i think) because you write image files line by line, so the first index (let's say x) refers to the line number (so x is the vertical axis) and the second index (y) refers to the subsequent pixel in line (so y is the horizontal axis), which is against our everyday coordinates sense.
If you want to handle it correctly you need to remember to write:
image = library.LoadImage(path)
array = (library.FromImageToNumpyArray(image)).T
and consequently:
image = library.FromNumpyArrayToImage(array.T)
library.WriteImage(image, path)
Which works also for 3D images. But i'm not promising this is the case for ALL image libraries - just these i worked with.