Convert plot to nparray - python

I have a numpy array of shape (74, 743) which represents a spectrogram of a few seconds of human speech. I can easily convert this into a matplotlib plot using plt.subplots.matshow, but I want to know if it's possible to convert the plot into the original numpy array? At the least, how does matplotlib generate an image from an arbitrarily shaped array?
I am trying to create a Generative Adverserial Network that will produce images (this is due to the network's superior performance at image generation) of spectrograms. Then, I want to convert these spectrogram images into the quantitative spectrograms, i.e plot into a numpy array.

It seems you want to apply a colormap to a 2D array. Using matplotlib tools this could look like
import numpy as np
from matplotlib.colors import Normalize
import matplotlib.cm as cm
data = np.random.rand(74, 743)
cmap = cm.viridis
norm = Normalize(data.min(), data.max())
output = cmap(norm(data))
print(output.shape)
The output is an array of shape (74, 743, 4) with values between 0 and 1, denoting RGBA colors.

Related

Subtract 2D array from 4D array

I have a greyscale image, represented by a 2D array of integers, shape (1000, 1000).
I then use sklearn.feature_extraction.image.extract_patches_2d() to generate an array of 3x3 'patches' from this image, resulting in an array of shape (1000000, 3, 3), as there are 1 million 3x3 arrays for each pixel value in the original image.
I reshape this to (1000, 1000, 3, 3), which is a 1000x1000 array of 3x3 arrays, one 3x3 array for each pixel in the original image.
I now want to effectively subtract the 2D array from the 4D array. I have already found a method to do this, but I would like to make one using vectorisation.
I currently iterate through each pixel and subtract the value there from the 3x3 array at the same index. This is a little bit slow.
This is what currently loads images, formats the arrays before hand, and then performs this subtraction.
from PIL import Image, ImageOps
from skimage import io
from sklearn.feature_extraction import image
import numpy
jitter = 1
patchsize = (jitter*2)+1
#load image as greyscale image using PIL
original = load_image_greyscale(filename)
#create a padded version of the image so that 1000x1000 patches are made
#instead of 998x998
padded = numpy.asarray(ImageOps.expand(original,jitter))
#extract these 3x3 patches using sklearn
patches = image.extract_patches_2d(padded,(patchsize,patchsize))
#convert image to numpy array
pixel_array = numpy.asarray(original)
#then reshape the array of patches so it matches array_image
patch_array = numpy.reshape(patches, (pixel_array.shape[0],pixel_array.shape[1],patchsize,patchsize))
#create a copy for results
patch_array_copy = numpy.copy(patch_array)
#iterate over each 3x3 array in the patch array and subtract the pixel value
#at the same index in the pixel array
for x in range(pixel_array.shape[0]):
for y in range(pixel_array.shape[1]):
patch_array_copy[x,y] = patch_array[x,y] - pixel_array[x,y]
I would like a way to perform the final step in the for loop using matrix operations.
I would also like to extend this at some point to work with RGB images, effectively making it a subtraction of an array with shape(1000,1000,3) from an array with shape(1000,1000,3,3,3). But i'm trying to go one step at a time here.
Any help or tips or suggestions or links to helpful resources would be greatly appreciated.

How to return Scikit-image Segmentation in 3D array?

I have a four band raster images (which is a 3D array) and I would like to segment the image band by band. The shape of this raster (after converted into a 3D array) is (12200, 7200, 4).
I have tried using scikit-image:
skimage.segmentation.slic(image[, …])
and
skimage.segmentation.quickshift(image[, …])
and the result is only a 2D array (= 1 band raster), with the shape of (12200, 7200).
The command seemed to have flatten the image and I cannot find anything in their documentation regarding the matter.
Here is what I've tried:
from __future__ import print_function
from osgeo import gdal
import numpy as np
from skimage import io
from skimage.segmentation import felzenszwalb, slic, quickshift
from skimage.segmentation import mark_boundaries
from skimage.util import img_as_float
# The input 4-band TSX image
image = r'raw_img/09K0153_20140501T084638_TSX.tif'
#convert image to Np array
img = io.imread(image, as_gray=False, plugin="gdal")
# Run the quick shift segmentation
segments = quickshift(img, kernel_size=3, convert2lab=False, max_dist=6, ratio=0.5)
How do I produce 3D segmentation result (that means, input: 3D array, output: 3D array) using Scikit-image, instead of 2D? Or is there another library that I can use for this purpose?
welcome to StackOverflow.
Indeed, the quickshift algorithm only returns a single (x, y) mask. You can find the implementation here. If you give more than one channel to the algorithm, it will take all of the channels into account to compute the segmentation mask.
If you want to apply the algorithm independently to each channel, you have to do it iteratively, for instance with the following code
from __future__ import print_function
from osgeo import gdal
import numpy as np
from skimage import io
from skimage.segmentation import felzenszwalb, slic, quickshift
from skimage.segmentation import mark_boundaries
from skimage.util import img_as_float
# The input 4-band TSX image
image = r'raw_img/09K0153_20140501T084638_TSX.tif'
#convert image to Np array
img = io.imread(image, as_gray=False, plugin="gdal")
# Instantiate a segments array of same shape than image
segments = np.zeros(img.shape)
Nc = img.shape[-1] # number of channels
# Run the quick shift segmentation for each channel
for c in range(Nc):
segments[:,:,c] = quickshift(img[:,:,c], kernel_size=3, convert2lab=False, max_dist=6, ratio=0.5)
How do I produce 3D segmentation result (that means, input: 3D array,
output: 3D array) using Scikit-image, instead of 2D?
Let's look at what it really means to have a 3D segmentation result as a 3D array. Let's consider a 3 channel image shown below. The segmentation we are interested in is shown in the blue dotted line.
Assume for now that there is some algorithm that will segment the blue dotted segment for us. But then how to represent the blue dotted segment?
If it was a square of a rectangle shape we could have represented the segment in a 3D numpy array (3D slice of the original image). But if the image is arbitary shape then how do we do it?
Segmentation information is captured using a mask. A mask 2D array corresponding to the size of the image is created. Let's assume we have only one segment in our image. In such a case all the pixels inside the segment of the image are marked as 1 in the corresponding mask image. This is a boolean mask (1 segment). If there are multiple segments then pixels in each segment as a unique number.
This is the reason you see that the result of the quickshift is a 2D array with the same dimension of the image. The result is the mask, the locations in the mask having the same values correspond to a segment which will represent a slice (which will be the same for all the channels). However, you will not be able to represent the slice using a numpy array if it of arbitary shape.
Just to add it is a bad idea to run quickshift of one channel at a time because it uses 5D space consisting of color information and image location 2 for segmentation. Using it on 1 channel at a time will give you bad segmentation results.

ValueError: Can not convert from <U12 to uint8

I tried out the following example. This should show image processing results.
from scipy import ndimage as ndi
import matplotlib.pyplot as plt
from scipy import misc
import numpy as np
import cv2
from skimage.morphology import watershed, disk
from skimage import data
from skimage.filters import rank
from skimage.util import img_as_ubyte
from skimage import io; io.use_plugin('matplotlib')
image = img_as_ubyte('imagepath.jpg')
# denoise image
denoised = rank.median(image, disk(2))
# find continuous region (low gradient -
# where less than 10 for this image) --> markers
# disk(5) is used here to get a more smooth image
markers = rank.gradient(denoised, disk(5)) < 10
markers = ndi.label(markers)[0]
# local gradient (disk(2) is used to keep edges thin)
gradient = rank.gradient(denoised, disk(2))
# process the watershed
labels = watershed(gradient, markers)
# display results
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8, 8),
sharex=True, sharey=True)
ax = axes.ravel()
ax[0].imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax[0].set_title("Original")
ax[1].imshow(gradient, cmap=plt.cm.nipy_spectral, interpolation='nearest')
ax[1].set_title("Local Gradient")
ax[2].imshow(markers, cmap=plt.cm.nipy_spectral, interpolation='nearest')
ax[2].set_title("Markers")
ax[3].imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax[3].imshow(labels, cmap=plt.cm.nipy_spectral, interpolation='nearest', alpha=.7)
ax[3].set_title("Segmented")
for a in ax:
a.axis('off')
fig.tight_layout()
plt.show()
I get the follofing error.
Traceback (most recent call last):
File "/home/workspace/calculate_watershed.py", line 15, in <module>
image = img_as_ubyte('koralle0.jpg')
File "/home/workspace/venv/lib/python3.5/site-packages/skimage/util/dtype.py", line 409, in img_as_ubyte
return convert(image, np.uint8, force_copy)
File "/home/workspace/venv/lib/python3.5/site-packages/skimage/util/dtype.py", line 113, in convert
.format(dtypeobj_in, dtypeobj_out))
ValueError: Can not convert from <U12 to uint8.
The path to the image is a valued one. Do You have any idea how to solve this problem? Thanks in advance
The problem is that the ndarray returned from your image has dtype <U12 which cannot be converted to dtype uint8. To check the dtype of your image file, convert it to a numpy array. I get a <U38 dtype for my image:
np.array('CAPTURE.jpg')
#array('Capture.JPG', dtype='<U38')
You should first read the image with skimage.io.imread(image_path). This will return an ndarray of MxN, MxNx3 or MxNx4. Then, reshape the resultant ndarray to 2D if its 3D or 4D. This conversion is required because skimage.filters.rank.median(image) accepts an image ndarray of 2D shape. In the following code, I've used my sample image to perform these steps before passing to img_as_ubyte(sk_image). The rest of the code remains the same.
from skimage.io import imread
#<---code--->
sk_image = imread('CAPTURE.jpg') #read the image to convert to skimage ndarray
sk_image = sk_image.transpose(1,0,2).reshape(130,-1) #convert to 2D array
image = img_as_ubyte(sk_image) #Convert image to 8-bit unsigned integer format.
#<---code--->
I get the following images:
You should consider the following points:
Check the shape of the image array returned from imread: After reading the image with sk_image = imread('CAPTURE.jpg'), check the shape of the array with sk_image.shape. For my image, I get the shape as (74, 130, 3) which shows its a 3D array.
To reshape to 2D, first get the strides with sk_image.strides. For my image, I get (390, 3, 1), then transpose with sk_image.transpose(1,0,2). You can also check the strides after transposing and you will notice the values have been swapped sk_image.transpose(1,0,2).strides: (3, 390, 1). Then, use reshape: sk_image.transpose(1, 0, 2).reshape(130,-1) to reshape to a 2D array. You will notice that the reshape dimensions have been roughly calculated from the stride value(390/2).
P.S: You can read more about 3D to 2D reshaping of numpy arrays here.

draw rgb spectrum in python/numpy

I'm new to Python and i need to draw a RGB spectrum as a numpy array.
For me it's clear that i need to rise the RGB values across the dimensions to get the spectrum.
import numpy as np
import matplotlib.pyplot as plt
spectrum = np.zeros([255,255, 3], dtype=np.unit8) #init the array
#fill the array with rgb values to create the spectrum without the use of loops
plt.imshow(spectrum)
plt.axis('off') # don't show axis
plt.show()
Is there a possiblity (e.g. a python or numpy method) to create the spectrum without the use of loops?
Not sure if this is the result you'd like, but you could define the arrays for the RGB values yourself (see HSV-RGB comparison). I've used Pillow to convert grayscale to colour.
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
spectrum = np.zeros([256,256*6, 3], dtype=np.uint8) # init the array
# fill the array with rgb values to create the spectrum without the use of loops
spectrum[:,:,0] = np.concatenate(([255]*256, np.linspace(255,0,256), [0]*256, [0]*256, np.linspace(0,255,256), [255]*256), axis=0)
spectrum[:,:,1] = np.concatenate((np.linspace(0,255,256), [255]*256, [255]*256, np.linspace(255,0,256), [0]*256,[0]*256), axis=0)
spectrum[:,:,2] = np.concatenate(([0]*256, [0]*256,np.linspace(0,255,256),[255]*256, [255]*256, np.linspace(255,0,256)), axis=0)
img = Image.fromarray(spectrum, 'RGB')
img.show()

3d numpy array to grayscale picture

while extracting the cifar10 dataset im confronted by arrays with the dimension of 32x32x3.
i can plot the image in colour with e.g. plt.imshow(train_data[2]); whats a common way to transform the array to the dimension 32x32 with grayscale values?
train_data, train_labels, test_data, test_labels =
load_cifar10_data(data_dir)
print(train_data.shape)
print(train_labels.shape)
output:
(50000, 32, 32, 3)
(50000,)
meanwhile, i'm just saving the images and read them again, but i guess there is a by far more elegant way to directly store the pictures to grayscale.
You can use your current 3D array to plot a grayscale image using matplotlib's imshow as described here.
import matplotlib.pyplot as plt
plt.imshow(train_data , cmap = "gray")

Categories

Resources