Opencv binary mask into white and blue mask - numpy

Let's say I have a mask (100, 100) of 1's and 0's:
mask = np.random.randint(0, 2, size=(100, 100))
How to convert this mask to get white-and-blue image in RGB:
1's from mask goes blue
0's from mask goes white

Easy as piece of cake. You need auxiliary array to do it:
img = np.zeros((100, 100, 3))
img[mask==0,:] = [1, 1, 1]
img[mask==1,:] = [0, 0, 1]

Related

How does the crop_and_resize function of tensorflow work?

I am trying to use the crop_and_resize function of tensorflow.
I use tf2.7
The result of this is different from what I predicted.
Why isn't the value I want coming out?
image = np.arange(25, dtype=np.float32).reshape(1, 5, 5, 1)
# box 2x2
box = np.array([[0.5, 0.5, 2.5, 2.5]]) / 5
a = tf.image.crop_and_resize(image, box, tf.zeros(image.shape[0], dtype=tf.int32), (1, 1))
tensorflow output
7.2
my expected
weights = np.array([[0.25, 0.5, 0.25],
[0.5, 1, 0.5],
[0.25, 0.5, 0.25]], dtype=np.float32)
expected = np.sum(image * weights) / 4
expected output
12
However, if I create the image size as 3x3, the value is the same as what I expected.
Is there something I understand wrong or am I using wrong?

Difference between dimension and channel

I have an image stored as a numpy array:
image = np.array([
[[ 11, 12],
[ 13, 14],
[ 15, 16]],
[[ 21, 22],
[ 23, 24],
[ 25, 26]],
[[ 31, 32],
[ 33, 34],
[ 35, 36]]])
I print the shape and dimensions:
>>> print('image shape', image.shape, 'image dimensions', image.ndim)
image shape (3, 3, 2) image dimensions 3
I understand that the matrix is 3 of Height, 3 of Width and 2 of color channel(?)
But.... if the dimension of the matrix is 3 .. What is the difference between dimension and color channel?
The inherent properties of an array are shape and ndim. Shape is the size of an array in each dimension. image.ndim is just a shortcut for len(image.shape). Another related quantity is image.size, which is np.prod(image.shape). In numpy, dimensions are called "axes", and start with zero. So the first index in an array corresponds to axis 0, the second to axis 1, etc.
Which dimension is "channel" is entirely up to interpretation. Generally, it will be the last dimension, but I have seen it as the first as well. Even more generally, dimensions generally correspond to some useful coordinates in your array. Remember that not all arrays are images. Data can be totally arbitrary, and will be based on your use-case.
Your example is slightly confusing because image.ndim == image.shape[0] == image.shape[1]. Here is an example of an array containing multiple RGB images, all of the same size:
images = np.random.randint(255, size=(5, 7, 7, 3), dtype=np.uint8)
We can interpret axis 0 as the index of the image, axis 1 as the width, axis 2 as the height, and axis 3 as the color channel. In that case, we have five images of size 7x7, with three color channels each. If the channels are R, G, B, then images[3, 0, 0, 2] is the blue component of the upper-left pixel in the fourth image.

How can I use numpy to composite N layers of grayscale image data with each layer colorized in RGB space?

Consider this trivial example with three colors (red, blue, and green):
layers = {
'red': np.random.rand(100, 100),
'blu': np.random.rand(100, 100),
'grn': np.random.rand(100, 100)
}
# Express composite as 3-channel RGB data
composite_arr = np.zeros(shape=(100, 100, 3))
# For each channel red, blue, and green, insert the data for the corresponding layer
composite_arr[:, :, 0] = layers['red']
composite_arr[:, :, 1] = layers['blu']
composite_arr[:, :, 2] = layers['grn']
# Finally, output the image expressed in RGB
composite_img = Image.fromarray(np.array(composite_arr * 255, dtype=np.uint8), mode="RGB")
composite_img.save('test.png')
Now, instead of the above example, let's try that with a list containing four layers:
layers = [
np.random.rand(100, 100),
np.random.rand(100, 100),
np.random.rand(100, 100),
np.random.rand(100, 100)
}
Let's say we choose four tetradic colors in the RGB space to apply one to each layer:
colors = {
(1, 0, 0),
(0, 1, 1),
(0, 0, 1),
(1, 1, 0)
}
How can I similarly build a composite for four layers in the above example?
Now, what about for any number of layers and colors?
I am looking for some generalized expression that I can apply sequentially to composite_arr that will update it for any number of layers and colors.
Alternatively, if this can be done efficiently using PIL or a similar library to colorize each layer and the apply some composite function, please suggest how that can be done.
Thanks!
Edit: To clarify, I would like the end result to be expressed in RGB space. So any number of layers should fit into this (following the above examples of 100x100 images):
composite_arr = np.zeros(shape=(100, 100, 3))

How to transpose each element of a Numpy Matrix [duplicate]

I'm starting off with a numpy array of an image.
In[1]:img = cv2.imread('test.jpg')
The shape is what you might expect for a 640x480 RGB image.
In[2]:img.shape
Out[2]: (480, 640, 3)
However, this image that I have is a frame of a video, which is 100 frames long. Ideally, I would like to have a single array that contains all the data from this video such that img.shape returns (480, 640, 3, 100).
What is the best way to add the next frame -- that is, the next set of image data, another 480 x 640 x 3 array -- to my initial array?
A dimension can be added to a numpy array as follows:
image = image[..., np.newaxis]
Alternatively to
image = image[..., np.newaxis]
in #dbliss' answer, you can also use numpy.expand_dims like
image = np.expand_dims(image, <your desired dimension>)
For example (taken from the link above):
x = np.array([1, 2])
print(x.shape) # prints (2,)
Then
y = np.expand_dims(x, axis=0)
yields
array([[1, 2]])
and
y.shape
gives
(1, 2)
You could just create an array of the correct size up-front and fill it:
frames = np.empty((480, 640, 3, 100))
for k in xrange(nframes):
frames[:,:,:,k] = cv2.imread('frame_{}.jpg'.format(k))
if the frames were individual jpg file that were named in some particular way (in the example, frame_0.jpg, frame_1.jpg, etc).
Just a note, you might consider using a (nframes, 480,640,3) shaped array, instead.
Pythonic
X = X[:, :, None]
which is equivalent to
X = X[:, :, numpy.newaxis] and
X = numpy.expand_dims(X, axis=-1)
But as you are explicitly asking about stacking images,
I would recommend going for stacking the list of images np.stack([X1, X2, X3]) that you may have collected in a loop.
If you do not like the order of the dimensions you can rearrange with np.transpose()
You can use np.concatenate() use the axis parameter to specify the dimension that should be concatenated. If the arrays being concatenated do not have this dimension, you can use np.newaxis to indicate where the new dimension should be added:
import numpy as np
movie = np.concatenate((img1[:,np.newaxis], img2[:,np.newaxis]), axis=3)
If you are reading from many files:
import glob
movie = np.concatenate([cv2.imread(p)[:,np.newaxis] for p in glob.glob('*.jpg')], axis=3)
Consider Approach 1 with reshape method and Approach 2 with np.newaxis method that produce the same outcome:
#Lets suppose, we have:
x = [1,2,3,4,5,6,7,8,9]
print('I. x',x)
xNpArr = np.array(x)
print('II. xNpArr',xNpArr)
print('III. xNpArr', xNpArr.shape)
xNpArr_3x3 = xNpArr.reshape((3,3))
print('IV. xNpArr_3x3.shape', xNpArr_3x3.shape)
print('V. xNpArr_3x3', xNpArr_3x3)
#Approach 1 with reshape method
xNpArrRs_1x3x3x1 = xNpArr_3x3.reshape((1,3,3,1))
print('VI. xNpArrRs_1x3x3x1.shape', xNpArrRs_1x3x3x1.shape)
print('VII. xNpArrRs_1x3x3x1', xNpArrRs_1x3x3x1)
#Approach 2 with np.newaxis method
xNpArrNa_1x3x3x1 = xNpArr_3x3[np.newaxis, ..., np.newaxis]
print('VIII. xNpArrNa_1x3x3x1.shape', xNpArrNa_1x3x3x1.shape)
print('IX. xNpArrNa_1x3x3x1', xNpArrNa_1x3x3x1)
We have as outcome:
I. x [1, 2, 3, 4, 5, 6, 7, 8, 9]
II. xNpArr [1 2 3 4 5 6 7 8 9]
III. xNpArr (9,)
IV. xNpArr_3x3.shape (3, 3)
V. xNpArr_3x3 [[1 2 3]
[4 5 6]
[7 8 9]]
VI. xNpArrRs_1x3x3x1.shape (1, 3, 3, 1)
VII. xNpArrRs_1x3x3x1 [[[[1]
[2]
[3]]
[[4]
[5]
[6]]
[[7]
[8]
[9]]]]
VIII. xNpArrNa_1x3x3x1.shape (1, 3, 3, 1)
IX. xNpArrNa_1x3x3x1 [[[[1]
[2]
[3]]
[[4]
[5]
[6]]
[[7]
[8]
[9]]]]
a = np.expand_dims(a, axis=-1)
or
a = a[:, np.newaxis]
or
a = a.reshape(a.shape + (1,))
There is no structure in numpy that allows you to append more data later.
Instead, numpy puts all of your data into a contiguous chunk of numbers (basically; a C array), and any resize requires allocating a new chunk of memory to hold it. Numpy's speed comes from being able to keep all the data in a numpy array in the same chunk of memory; e.g. mathematical operations can be parallelized for speed and you get less cache misses.
So you will have two kinds of solutions:
Pre-allocate the memory for the numpy array and fill in the values, like in JoshAdel's answer, or
Keep your data in a normal python list until it's actually needed to put them all together (see below)
images = []
for i in range(100):
new_image = # pull image from somewhere
images.append(new_image)
images = np.stack(images, axis=3)
Note that there is no need to expand the dimensions of the individual image arrays first, nor do you need to know how many images you expect ahead of time.
You can use stack with the axis parameter:
img.shape # h,w,3
imgs = np.stack([img1,img2,img3,img4], axis=-1) # -1 = new axis is last
imgs.shape # h,w,3,nimages
For example: to convert grayscale to color:
>>> d = np.zeros((5,4), dtype=int) # 5x4
>>> d[2,3] = 1
>>> d3.shape
Out[30]: (5, 4, 3)
>>> d3 = np.stack([d,d,d], axis=-2) # 5x4x3 -1=as last axis
>>> d3[2,3]
Out[32]: array([1, 1, 1])
I followed this approach:
import numpy as np
import cv2
ls = []
for image in image_paths:
ls.append(cv2.imread('test.jpg'))
img_np = np.array(ls) # shape (100, 480, 640, 3)
img_np = np.rollaxis(img_np, 0, 4) # shape (480, 640, 3, 100).
This worked for me:
image = image[..., None]
This will help you add axis anywhere you want
import numpy as np
signal = np.array([[0.3394572666491664, 0.3089068053925853, 0.3516359279582483], [0.33932706934615525, 0.3094755563319447, 0.3511973743219001], [0.3394407172182317, 0.30889042266755573, 0.35166886011421256], [0.3394407172182317, 0.30889042266755573, 0.35166886011421256]])
print(signal.shape)
#(4,3)
print(signal[...,np.newaxis].shape) or signal[...:none]
#(4, 3, 1)
print(signal[:, np.newaxis, :].shape) or signal[:,none, :]
#(4, 1, 3)
there is three-way for adding new dimensions to ndarray .
first: using "np.newaxis" (something like #dbliss answer)
np.newaxis is just given an alias to None for making it easier to
understand. If you replace np.newaxis with None, it works the same
way. but it's better to use np.newaxis for being more explicit.
import numpy as np
my_arr = np.array([2, 3])
new_arr = my_arr[..., np.newaxis]
print("old shape", my_arr.shape)
print("new shape", new_arr.shape)
>>> old shape (2,)
>>> new shape (2, 1)
second: using "np.expand_dims()"
Specify the original ndarray in the first argument and the position
to add the dimension in the second argument axis.
my_arr = np.array([2, 3])
new_arr = np.expand_dims(my_arr, -1)
print("old shape", my_arr.shape)
print("new shape", new_arr.shape)
>>> old shape (2,)
>>> new shape (2, 1)
third: using "reshape()"
my_arr = np.array([2, 3])
new_arr = my_arr.reshape(*my_arr.shape, 1)
print("old shape", my_arr.shape)
print("new shape", new_arr.shape)
>>> old shape (2,)
>>> new shape (2, 1)

Mayavi doesn't draw lines

I want to draw very simple graph with 4 nodes and 3 edges:
from numpy import array, vstack
from mayavi import mlab
mlab.figure(1, bgcolor=(1, 0.9, 1))
mlab.clf()
x = array([0, 3, 2, 3])
y = array([0, 4, 5, 1])
z = array([0, 0, 1, 1])
color = array([0.1, 0.3, 0.5, 0.7])
pts = mlab.points3d(x, y, z,
color,
scale_factor=1,
scale_mode='none',
colormap='Blues',
resolution=20)
edges = vstack([[0, 1], [0, 2], [0, 3]])
pts.mlab_source.dataset.lines = edges
tube = mlab.pipeline.tube(pts, tube_radius=0.1, tube_sides=7)
mlab.pipeline.surface(tube, color=(0.8, 0.8, 0.8))
mlab.show()
It returns that:
Why edges are missing?
There is a bug in Mayavi about this. It is related to unsynchronized changes with VTK and are thus a bit hard to pinpoint. There is a discussion on Mayavi's GitHub https://github.com/enthought/mayavi/issues/388
The bug also shows up with the protein.py example that comes up with Mayavi and it is fixed there by adding
pts.mlab_source.update()
after setting the lines. It is fixed online for the example at https://github.com/enthought/mayavi/commit/afb17fceafe787c8260ca7a37fbb3b8c2fbfd36c
Using the fix did not work for me though but you might try.