Detect surfaces from a binary numpy array (image) - python

Assume that I have a binary numpy array (0 or 1 / True or False) that come from a .jpg image (2D array, from a grayscale image). I just made some processing to get the edges of the image, based on color change.
Now, from every surface/body from this array I need to get its centers.
Here the original image:
Here the processed one:
Now I need to get the centers of each surface generated for this lines (i.e. indexes that more or less point the center of each surface generated).
In the case you are interested, you can find the file (.npy) here:
https://gofile.io/d/K8U3ZK
Thanks a lot!

Found a solution that works. scipy.ndimage.label assigns a unique int. to each label or area, to validate the results I simply plot the output array
from scipy.ndimage import label
labeled_array, no_feats = label(my_binary_flower)
plt.imshow(labeled_array)

Related

plt.imshow(np.squeeze(x_train[3]), cmap="gray"); what does this command mean?

I was working on the classification of images. I came across this one line and I'm not able to figure the meaning.
plt.imshow(np.squeeze(x_train[3]), cmap=“gray”);
Could you explain this line to me?
This really depends on what your variable x_train contains. You give no context to your code. I can infer that x_train is a numpy array that is indexed at the fourth element or row.
plt.imshow is a function from the matplotlib library which accepts an array that represents an image and draws that to the screen. The array is usually either a 2D-array representing rows and columns of pixels or a 3D-array, where every pixel is characterized by either 3 values for RGB or 4 values for RGBA (A stands for alpha and indicates the transparency).
The cmap="gray" is a keyword argument passed to plt.imshow, which is responsible for mapping a specific colormap to the values found in the array that you passed as the first argument. You can look up the colormap if you google matplotlib colormaps.
Since the gray colormap is used in your code, it is very likely that your array is a 2D-array that represents a grayscale image. In that case, every pixel is only described by one value (usually between 0 and 255) that indicates its color on a scale from black (0) to white (255).
If you pass a 3D-array (so a color image) to imshow, matplotlib will automatically interpret the values in the third dimension as RGB values and correctly show the image.
If you however pass a 2D-array, which is probably the case, matplotlib will map the values to a colormap, which is "viridis" by default. This will result in a green / yellow / blue image. Therefore, it is necessary to tell matplotlib to map it to a grayscale colormap.
I assume that x_train is therefore a numpy array with more than two dimensions that probably contains multiple images. When you index it at the index 3, you obtain a part of the array that holds the values for the image you want to display. This array seems to have more dimensions than are really in use, which is why np.squeeze is used to reduce the unnecessary dimensions. As an example:
import numpy as np
test_array = np.array([[1, 2, 3]])
np.squeeze(test_array)
>>> array([1, 2, 3])
This is all I can tell you from the little information you've given. Next time consider providing more context to your question.

Convert an image of a signal into a python list - by specifying no of points in 1D

I'm struggling to convert an image of a signal back to a python list (it was plotted a long time ago and I have lost the data I have only the images).
I've searched on the internet but I find answers about how to convert a 2d image into a 1d and I want to get the signal back.
Long story short:
I have this image of a signal:
and I want to convert this to a python list with a size of 65535 so my list should be looking like this:
list = [0.14, 0.144, 0.12 ...... ]
Thanks!
As a first plan, you could load the image using PIL/Pillow, or OpenCV, greyscale it and resize it to 65536 pixels wide by 100 pixels tall.
Then you will have a Numpy array with dimensions (100,65536). You can then run np.argmin() to find the index (y-value) of the darkest pixel in each column.
Or, find the indices of all the low valued pixels and take their median instead of the second step above.
The code starts off like this:
#!/usr/bin/env python3
from PIL import Image
import numpy as np
# Load image and convert to greyscale
im = Image.open('signal.png').convert('L')
# Resize to match required output
big = im.resize((65536,100), resample=Image.NEAREST)
# Make Numpy array
na = np.array(big)
# This looks about right, I think
print(np.argmin(na,axis=0))
If you trim the image so that the signal touches the edges all the way around, then the first black pixel on the left comes out as list element 0, the last pixel on the right comes out as the last element of your list and the lowest black pixel comes out with y-value of 0 and the peak comes out with y-value of 100.
Trimming would look like this:
from PIL import Image, ImageOps
import numpy as np
# Load image and convert to greyscale
im = Image.open('signal.png').convert('L')
# Get bounding box
bbox = ImageOps.invert(im).getbbox()
# Trim original image so that signal touches edge on all sides
im = im.crop(bbox)
... continue as before ...
Essentially, you'll have to "scan" the images left to right and identify the correct signal value at each "time step." As the image you presented doesn't have scale / units, you'll probably want to normalize all signal values from 0 to 1, as you've implied in your answer. Later you can adjust the scale of the signal if that's not the right range.
It looks like your images have some anti-aliasing at each step of the signal, which means that you won't have columns of all zeros except for one "signal" value. You'll have a cluster of signal values at each time step, some of which are weaker, because the image compression has blurred the signal slightly. This shouldn't be a problem, since you'll just find the max at each time step.
Assuming these images are in grayscale (if not, convert to grayscale), you'd want to find the maximum (or minimum, if the signal is drawn in black) color value at each column of pixels in the images (representing timesteps of the signal).
Mark Setchell's suggestion of PIL/Pillow seems like a great first step.
numpy's amax takes a matrix and flattens it to the max across an entire axis.

How to get border pixels of an image in python?

I have an image, using steganography I want to save the data in border pixels only.
In other words, I want to save data only in the least significant bits(LSB) of border pixels of an image.
Is there any way to get border pixels to store data( max 15 characters text) in the border pixels?
Plz, help me out...
OBTAINING BORDER PIXELS:
Masking operations are one of many ways to obtain the border pixels of an image. The code would be as follows:
a= cv2.imread('cal1.jpg')
bw = 20 //width of border required
mask = np.ones(a.shape[:2], dtype = "uint8")
cv2.rectangle(mask, (bw,bw),(a.shape[1]-bw,a.shape[0]-bw), 0, -1)
output = cv2.bitwise_and(a, a, mask = mask)
cv2.imshow('out', output)
cv2.waitKey(5000)
After I get an array of ones with the same dimension as the input image, I use cv2.rectangle function to draw a rectangle of zeros. The first argument is the image you want to draw on, second argument is start (x,y) point and the third argument is the end (x,y) point. Fourth argument is the color and '-1' represents the thickness of rectangle drawn (-1 fills the rectangle). You can find the documentation for the function here.
Now that we have our mask, you can use 'cv2.bitwise_and' (documentation) function to perform AND operation on the pixels. Basically what happens is, the pixels that are AND with '1' pixels in the mask, retain their pixel values. Pixels that are AND with '0' pixels in the mask are made 0. This way you will have the output as follows:
.
The input image was :
You have the border pixels now!
Using LSB planes to store your info is not a good idea. It makes sense when you think about it. A simple lossy compression would affect most of your hidden data. Saving your image as JPEG would result in loss of info or severe affected info. If you want to still try LSB, look into bit-plane slicing. Through bit-plane slicing, you basically obtain bit planes (from MSB to LSB) of the image. (image from researchgate.net)
I have done it in Matlab and not quite sure about doing it in python. In Matlab,
the function, 'bitget(image, 1)', returns the LSB of the image. I found a question on bit-plane slicing using python here. Though unanswered, you might want to look into the posted code.
To access border pixel and enter data into it.
A shape of an image is accessed by t= img.shape. It returns a tuple of the number of rows, columns, and channels.A component is RGB which 1,2,3 respectively.int(r[0]) is variable in which a value is stored.
import cv2
img = cv2.imread('xyz.png')
t = img.shape
print(t)
component = 2
img.itemset((0,0,component),int(r[0]))
img.itemset((0,t[1]-1,component),int(r[1]))
img.itemset((t[0]-1,0,component),int(r[2]))
img.itemset((t[0]-1,t[1]-1,component),int(r[3]))
print(img.item(0,0,component))
print(img.item(0,t[1]-1,component))
print(img.item(t[0]-1,0,component))
print(img.item(t[0]-1,t[1]-1,component))
cv2.imwrite('output.png',img)

Python - Get coordinates of important value of 2D array

I would like to determine an angle from an image (2D array).
I can get the coordinates of the point whose intensity is maximum with "unravel_index" and "argmax" but i would like to know how to get an another point whose intensity is high in order to calculate my angle.
I have to automatise that because i have a great number of images for post-treatement
So for the first coordinates, i can do that :
import numpy as np
from numpy import unravel_index
t = unravel_index(eyy.argmax(), eyy.shape)
And i need an another coordinates in order to calculate my angle...
t2 = ....
theta = np.arctan2(t[0]-t2[0],t[1]-t2[1])
What you could try is to look into the Hough Transform (Wikipedia - Hough Transform). The Hough Transform is a tool developed for finding lines and their orientation in images.
There is a Python implementation of the Hough Transform over at Rosetta Code.
I'm not sure if the lines in your data are distinct enough for the Hough Transform to yield good results but I hope it helps.
You can put your array in a masked array, find the pixel with the maximum intensity, then mask it, then find the next pixel with the maximum intensity.

Python - matplotlib - imshow - How to influence displayed value of unzoomed image

I need to search outliers in more or less homogeneous images representing some physical array. The images have a resolution which is much higher than the screen resolution. Thus every pixel on screen originates from a block of image pixels. Is there the possibility to customize the algorithm which calculates the displayed value for such a block? Especially the possibility to either use the lowest or the highest value would be helpful.
Thanks in advance
Scipy provides several such filters. To get a new image (new) whose pixels are the maximum/minimum over a w*w block of an original image (img), you can use:
new = scipy.ndimage.filters.maximum_filter(img, w)
new = scipy.ndimage.filters.minimum_filter(img, w)
scipy.ndimage.filters has several other filters available.
If the standard filters don't fit your requirements, you can roll your own. To get you started here is an example that shows how to get the minimum in each block in the image. This function reduces the size of the full image (img) by a factor of w in each direction. It returns a smaller image (new) in which each pixel is the minimum pixel in a w*w block of pixels from the original image. The function assumes the image is in a numpy array:
import numpy as np
def condense(img, w):
new = np.zeros((img.shape[0]/w, img.shape[1]/w))
for i in range(0, img.shape[1]//w):
col1 = i * w
new[:, i] = img[:, col1:col1+w].reshape(-1, w*w).min(1)
return new
If you wanted the maximum, replace min with max.
For the condense function to work well, the size of the full image must be a multiple of w in each direction. The handling of non-square blocks or images that don't divide exactly is left as an exercise for the reader.

Categories