Convert imshow spectrogram to image - python

I would like to save just the wavelet image (no ticks nor labels) shown here to a png file.
I tried to follow the solution posted here for saving a spectrogram plot, but this approach is not working for me.
This is what I get:
This is the code that I have used:
import librosa
import librosa.display
import os
import pywt
import matplotlib.pyplot as plt
import soundfile as sf
import skimage.io
from tftb.generators import anasing
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
from ssqueezepy import cwt
from ssqueezepy.visuals import plot, imshow
# Set the path to the Binary Class dataset
fulldatasetpath = 'G:/AudioFile'
input_file = (r'G:/Audiofile.wav')
[data1, sample_rate1] = sf.read(input_file)
#[sample_rate1, data1] = wav.read(input_file);
duration = len(data1)/sample_rate1
time = np.arange(0, duration, 1/sample_rate1) #time vector
#%%############## Take CWT & plot ##################################################
Wx, scales = cwt(data1, 'morlet')
imshow(Wx, abs=1)
plt.show()
Wx = abs(Wx)
#%%############## SAVE TO IMAGE ###########################################
def scale_minmax(X, min=0.0, max=1.0):
X_std = (X - X.min()) / (X.max() - X.min())
X_scaled = X_std * (max - min) + min
return X_scaled
wave1 = np.log(Wx + 1e-9) # add small number to avoid log(0)
# min-max scale to fit inside 8-bit range
img = scale_minmax(Wx, 0, 255).astype(np.uint8)
img = np.flip(img, axis=0) # put low frequencies at the bottom in image
img = 255-img # invert. make black==more energy
out = 'out.png'
# save as PNG
skimage.io.imsave(out, img)

You can set the position of the axis to cover the entire figure, and you can also play with figsize. For example:
import matplotlib.pyplot as plt
import numpy as np
from ssqueezepy import imshow
# test image
img = np.zeros((500, 40000, 3), dtype=int)
for i in range(img.shape[1]):
img[:, i, 0] = int(abs(1 - 2 * i / img.shape[1]) * 255)
# create a figure and set the size
f = plt.figure(figsize=(8, 4))
# add a new axis into which ssqueezepy is going to plot
ax = f.add_subplot()
imshow(img)
# turn off tick labels
ax.axis(False)
# make the axis to cover the entire figure
ax.set_position([0, 0, 1, 1])
f.savefig("result.png")

Related

How to extract rgb values of this colorbar image in python?

Image
I want to make a colormap used in the attached image colorbar. So far I tried the code given below but didn't get the result I was looking for.
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
img = plt.imread('Climat.png')
colors_from_img = img[:, 0, :]
my_cmap = LinearSegmentedColormap.from_list('my_cmap', colors_from_img, N=651)
y = random_sample((100, 100))
imshow(y, cmap=my_cmap);plt.colorbar()
Looking for your suggestions. Thank you in advance.
bicarlsen has given you the correct direction. Restrict the points from which you extract the colors to the colored rectangles:
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
img = plt.imread('Climat.png')
colors_from_img = img[80::88, 30, :]
my_cmap = LinearSegmentedColormap.from_list('my_cmap', colors_from_img[::-1], N=len(colors_from_img))
y = np.random.random_sample((100, 100))
plt.imshow(y, cmap=my_cmap)
plt.colorbar()
plt.show()
Sample output:
P.S.: Initially, I thought a more general approach with
colors_from_img = np.unique(img[:, 30, :], axis=0)
was possible but as the input image is rasterized, all kinds of mixed colors are present where the black lines separate colored rectangles.

Python: how could this image be properly segmented?

I would like to segment (isolate) the rod-like structures shown in this image:
The best I've managed to do is this
# Imports the libraries.
from skimage import io, filters
import matplotlib.pyplot as plt
import numpy as np
# Imports the image as a numpy array.
img = io.imread('C:/Users/lopez/Desktop/Test electron/test.tif')
# Thresholds the images using a local threshold.
thresh = filters.threshold_local(img,301,offset=0)
binary_local = img > thresh # Thresholds the image
binary_local = np.invert(binary_local) # inverts the thresholded image (True becomes False and vice versa).
# Shows the image.
plt.figure(figsize=(10,10))
plt.imshow(binary_local,cmap='Greys')
plt.axis('off')
plt.show()
Which produces this result
However, as you can see from the segmented image, I haven't managed to isolate the rods. What should be black background is filled with interconnected structures. Is there a way to neatly isolate the rod-like structures from all other elements in the image?
The original image can be downloaded from this website
https://dropoff.nbi.ac.uk/pickup.php
Claim ID: qMNrDHnfEn4nPwB8
Claim Passcode: UkwcYoYfXUfeDto8
Here is my attempt using a Meijering filter. The Meijering filter relies on symmetry when it looks for tubular structures and hence the regions where rods overlap (breaking the symmetry of the tubular shape) are not that well recovered, as can be seen in the overlay below.
Also, there is some random crap that I have trouble getting rid off digitally, but maybe you can clean your prep a bit more before imaging.
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread
from skimage.transform import rescale
from skimage.restoration import denoise_nl_means
from skimage.filters import meijering
from skimage.measure import label
from skimage.color import label2rgb
def remove_small_objects(binary_mask, size_threshold):
label_image = label(binary_mask)
object_sizes = np.bincount(label_image.ravel())
labels2keep, = np.where(object_sizes > size_threshold)
labels2keep = labels2keep[1:] # remove the first label, which corresponds to the background
clean = np.in1d(label_image.ravel(), labels2keep).reshape(label_image.shape)
return clean
if __name__ == '__main__':
raw = imread('test.tif')
raw -= raw.min()
raw /= raw.max()
# running everything on the large image took too long for my patience;
raw = rescale(raw, 0.25, anti_aliasing=True)
# smooth image while preserving edges
smoothed = denoise_nl_means(raw, h=0.05, fast_mode=True)
# filter for tubular shapes
sigmas = range(1, 5)
filtered = meijering(smoothed, sigmas=sigmas, black_ridges=False)
# Meijering filter always evaluates to high values at the image frame;
# we hence set the filtered image to zero at those locations
frame = np.ones_like(filtered, dtype=np.bool)
d = 2 * np.max(sigmas) + 1 # this is the theoretical minimum ...
d += 2 # ... but doesn't seem to be enough so we increase d
frame[d:-d, d:-d] = False
filtered[frame] = np.min(filtered)
thresholded = filtered > np.percentile(filtered, 80)
cleaned = remove_small_objects(thresholded, 200)
overlay = raw.copy()
overlay[np.invert(cleaned)] = overlay[np.invert(cleaned)] * 2/3
fig, axes = plt.subplots(2, 3, sharex=True, sharey=True)
axes = axes.ravel()
axes[0].imshow(raw, cmap='gray')
axes[1].imshow(smoothed, cmap='gray')
axes[2].imshow(filtered, cmap='gray')
axes[3].imshow(thresholded, cmap='gray')
axes[4].imshow(cleaned, cmap='gray')
axes[5].imshow(overlay, cmap='gray')
for ax in axes:
ax.axis('off')
fig, ax = plt.subplots()
ax.imshow(overlay, cmap='gray')
ax.axis('off')
plt.show()
If this code makes it into a paper, I want an acknowledgement and a copy of the paper. ;-)

How to compute the gradients of image using Python

I wonder how to use Python to compute the gradients of the image. The gradients include x and y direction. I want to get an x gradient map of the image and a y gradient map of the image. Can anyone tell me how to do this?
Thanks~
I think you mean this:
import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt
# Create a black image
img=np.zeros((640,480))
# ... and make a white rectangle in it
img[100:-100,80:-80]=1
# See how it looks
plt.imshow(img,cmap=plt.cm.gray)
plt.show()
# Rotate it for extra fun
img=ndimage.rotate(img,25,mode='constant')
# Have another look
plt.imshow(img,cmap=plt.cm.gray)
plt.show()
# Get x-gradient in "sx"
sx = ndimage.sobel(img,axis=0,mode='constant')
# Get y-gradient in "sy"
sy = ndimage.sobel(img,axis=1,mode='constant')
# Get square root of sum of squares
sobel=np.hypot(sx,sy)
# Hopefully see some edges
plt.imshow(sobel,cmap=plt.cm.gray)
plt.show()
Or you can define the x and y gradient convolution kernels yourself and call the convolve() function:
# Create a black image
img=np.zeros((640,480))
# ... and make a white rectangle in it
img[100:-100,80:-80]=1
# Define kernel for x differences
kx = np.array([[1,0,-1],[2,0,-2],[1,0,-1]])
# Define kernel for y differences
ky = np.array([[1,2,1] ,[0,0,0], [-1,-2,-1]])
# Perform x convolution
x=ndimage.convolve(img,kx)
# Perform y convolution
y=ndimage.convolve(img,ky)
sobel=np.hypot(x,y)
plt.imshow(sobel,cmap=plt.cm.gray)
plt.show()
you can use opencv to compute x and y gradients as below:
import numpy as np
import cv2
img = cv2.imread('Desert.jpg')
kernely = np.array([[1,1,1],[0,0,0],[-1,-1,-1]])
kernelx = np.array([[1,0,-1],[1,0,-1],[1,0,-1]])
edges_x = cv2.filter2D(img,cv2.CV_8U,kernelx)
edges_y = cv2.filter2D(img,cv2.CV_8U,kernely)
cv2.imshow('Gradients_X',edges_x)
cv2.imshow('Gradients_Y',edges_y)
cv2.waitKey(0)
We can do it with scikit-image filters module functions too, as shown below:
import matplotlib.pylab as plt
from skimage.io import imread
from skimage.color import rgb2gray
from skimage import filters
im = rgb2gray(imread('../images/cameraman.jpg')) # RGB image to gray scale
plt.gray()
plt.figure(figsize=(20,20))
plt.subplot(221)
plt.imshow(im)
plt.title('original', size=20)
plt.subplot(222)
edges_y = filters.sobel_h(im)
plt.imshow(edges_y)
plt.title('sobel_x', size=20)
plt.subplot(223)
edges_x = filters.sobel_v(im)
plt.imshow(edges_x)
plt.title('sobel_y', size=20)
plt.subplot(224)
edges = filters.sobel(im)
plt.imshow(edges)
plt.title('sobel', size=20)
plt.show()

how to find the histogram of an input image using python?

i am trying to find the histogram of an input image. But instead of seeing a histogram, the code runs then stops without showing anything. Can someone point out to me why this is happening?
import pylab as plt
import matplotlib.image as mpimg
import numpy as np
img = np.uint8(mpimg.imread('jack.jpg'))
# convert to grayscale
# do for individual channels R, G, B, A for nongrayscale images
img = np.uint8((0.2126* img[:,:,0]) + \
np.uint8(0.7152 * img[:,:,1]) +\
np.uint8(0.0722 * img[:,:,2]))
plt.histogram(img,10)
plt.show()
You are confusing histogram with hist. And yes, plt.histogram is a call to numpy.histogram.
Try this:
import pylab as plt
import matplotlib.image as mpimg
import numpy as np
img = np.uint8(mpimg.imread('jack.jpg'))
# convert to grayscale
# do for individual channels R, G, B, A for nongrayscale images
img = np.uint8(0.2126 * img[:,:,0]) +\
np.uint8(0.7152 * img[:,:,1]) +\
np.uint8(0.0722 * img[:,:,2])
plt.hist(img,10)
plt.show()
[edit to answer comment]
According to the documentation (links above on the functions names), np.histogram will Compute the histogram of a set of data, returning:
hist : array The values of the histogram. [...]
bin_edges : array of dtype
float Return the bin edges (length(hist)+1).
And plt.hist will Compute and draw the histogram of x, returning a tuple (n, bins, patches).

Crop out partial image using NumPy (or SciPy)

Using numpy or scipy (I am not using OpenCV) I am trying to crop a region out of an image.
For instance, I have this:
and I want to get this:
Is there something like cropPolygon(image, vertices=[(1,2),(3,4)...]) with numpy or SciPy?
Are you using matplotlib?
One approach I've taken previously is to use the .contains_points() method of a matplotlib.path.Path to construct a boolean mask, which can then be used to index into the image array.
For example:
import numpy as np
from matplotlib.path import Path
from scipy.misc import lena
img = lena()
# vertices of the cropping polygon
xc = np.array([219.5, 284.8, 340.8, 363.5, 342.2, 308.8, 236.8, 214.2])
yc = np.array([284.8, 220.8, 203.5, 252.8, 328.8, 386.2, 382.2, 328.8])
xycrop = np.vstack((xc, yc)).T
# xy coordinates for each pixel in the image
nr, nc = img.shape
ygrid, xgrid = np.mgrid[:nr, :nc]
xypix = np.vstack((xgrid.ravel(), ygrid.ravel())).T
# construct a Path from the vertices
pth = Path(xycrop, closed=False)
# test which pixels fall within the path
mask = pth.contains_points(xypix)
# reshape to the same size as the image
mask = mask.reshape(img.shape)
# create a masked array
masked = np.ma.masked_array(img, ~mask)
# if you want to get rid of the blank space above and below the cropped
# region, use the min and max x, y values of the cropping polygon:
xmin, xmax = int(xc.min()), int(np.ceil(xc.max()))
ymin, ymax = int(yc.min()), int(np.ceil(yc.max()))
trimmed = masked[ymin:ymax, xmin:xmax]
Plotting:
from matplotlib import pyplot as plt
fig, ax = plt.subplots(2, 2)
ax[0,0].imshow(img, cmap=plt.cm.gray)
ax[0,0].set_title('original')
ax[0,1].imshow(mask, cmap=plt.cm.gray)
ax[0,1].set_title('mask')
ax[1,0].imshow(masked, cmap=plt.cm.gray)
ax[1,0].set_title('masked original')
ax[1,1].imshow(trimmed, cmap=plt.cm.gray)
ax[1,1].set_title('trimmed original')
plt.show()

Categories