Handling matplotlib.figure.Figure using openCV

Viewed 614

I am using the following code to find the spectrogram of a signal and save it.

spec,freq,t,im = plt.specgram(raw_signal,Fs=100,NFFT=100,noverlap=50)
plt.axis('off')
figure = plt.gcf()
figure.set_size_inches(12, 1)
plt.savefig('spectrogram',bbox_inches = 'tight',pad_inches=0)

enter image description here

But I have multiple spectrograms like this and the end product I need is a concatenation of all these. Right now, what I am doing is, I am saving all these individual images using plt.savefig() as earlier and reading them back using cv2.imread() and concatenating them. But this process is not very good I think. So is there any other way I can do this without saving it and re-reading it?

One possible idea I have is, somehow converting matplotlib.figure.Figure into a format that can be handled by OpenCV (specifically cv2). However, it should also not have white padding.

2 Answers

You can get the image as an array using buffer_rgba (don't forget to draw the image first). Then in OpenCV, you need to convert the image from RGB to OpenCV's BGR channel ordering.

import matplotlib.pyplot as plt
import numpy as np
import cv2

raw_signal =  np.random.random(1000)
spec,freq,t,im = plt.specgram(raw_signal,Fs=100,NFFT=100,noverlap=50)
plt.axis('off')
figure = plt.gcf()
figure.set_size_inches(12, 1)
figure.set_dpi(50)

figure.canvas.draw()

b = figure.axes[0].get_window_extent()
img = np.array(figure.canvas.buffer_rgba())
img = img[int(b.y0):int(b.y1),int(b.x0):int(b.x1),:]
img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA)
cv2.imshow('OpenCV',img)

Top: matplotlib, bottom OpenCV:

enter image description here

don't save the figure. matplotlib happens to have a convenience function for displaying time series data in this way but that's not how you deal with spectrograms. any handling of spectrogram "pictures" is a kludge.

use scipy.signal.spectrogram to get the actual spectrogram.

Related