Reputation: 729
I have a series of images coming from a video stream that I would like to display with Matplotlib (in greyscale). For some reason I can get them to display in colour perfectly fine, but not when I convert them to greyscale.
Since I have a lot of images, I am using set_data( image )
instead of imshow( image )
as it is much faster. Colour images work fine with both of these commands, but greyscale only works with imshow()
. If I use set_data()
I just get a black image, no matter what data I sent it.
Any idea what could be going on here?
My code is below for reference. I've highlighted the important bit with a big comment, but I've included all of my other code in case something else is causing the issue. The rest of the code basically sets up a queue which is populated with images from a camera and I want to display them as I get them.
import matplotlib.pyplot as plt
from matplotlib import cm
from cv_bridge import CvBridge, CvBridgeError
import cv
from collections import deque
import rospy
from sensor_msgs.msg import Image
import numpy as np
class CameraViewer():
def __init__( self, root='navbot' ):
self.root = root
self.im_data = deque()
self.bridge = CvBridge() # For converting ROS images into a readable format
self.im_fig = plt.figure( 1 )
self.im_ax = self.im_fig.add_subplot(111)
self.im_ax.set_title("DVS Image")
self.im_im = self.im_ax.imshow( np.zeros( ( 256, 256 ),dtype='uint8' ), cmap=plt.cm.gray ) # Blank starting image
#self.im_im = self.im_ax.imshow( np.zeros( ( 256, 256 ),dtype='float32' ), cmap=plt.cm.gray ) # Tried a different format, also didn't work
self.im_fig.show()
self.im_im.axes.figure.canvas.draw()
def im_callback( self, data ):
cv_im = self.bridge.imgmsg_to_cv( data, "mono8" ) # Convert Image from ROS Message to greyscale CV Image
im = np.asarray( cv_im ) # Convert from CV image to numpy array
#im = np.asarray( cv_im, dtype='float32' ) / 256 # Tried a different format, also didn't work
self.im_data.append( im )
def run( self ):
rospy.init_node('camera_viewer', anonymous=True)
sub_im = rospy.Subscriber( self.root + '/camera/image', Image, self.im_callback)
while not rospy.is_shutdown():
if self.im_data:
im = self.im_data.popleft()
#######################################################
# The following code is supposed to display the image:
#######################################################
self.im_im.set_cmap( 'gray' ) # This doesn't seem to do anything
self.im_im.set_data( im ) # This won't show greyscale images
#self.im_ax.imshow( im, cmap=plt.cm.gray ) # If I use this, the code runs unbearably slow
self.im_im.axes.figure.canvas.draw()
def main():
viewer = CameraViewer( root='navbot' )
viewer.run()
if __name__ == '__main__':
main()
Upvotes: 2
Views: 986
Reputation: 284642
What's happening is that the min and max of the data are changing. im.set_data
just blindly sets the data -- it doesn't try to update the color scaling.
Initially, you plot an array of all zeros, so imshow
scales the image between 0 and 0 (plus a tiny fudge factor). However, the data you update it with has a range between 0 and 255.
You'll need to either a) set the vmin
and vmax
of the data to the maximum range when you initially plot the image, or b) update the color limits with the min and max of the data each time you update the image (use im.set_clim
).
Because you seem to be expecting the data to be uint8
's, it's probably best to just specify vmin
and vmax
when you initially plot your blank image.
Try doing:
# Blank starting image
self.im_im = self.im_ax.imshow(np.zeros((256, 256)), cmap=plt.cm.gray,
vmin=0, vmax=255)
Upvotes: 8