color_histogram_visualizer.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright: Yuki Furuta <furushchev@jsk.imi.i.u-tokyo.ac.jp>
4 
5 import math
6 import cv2
7 from cv_bridge import CvBridge
8 from distutils.version import LooseVersion
9 from dynamic_reconfigure.server import Server
10 import numpy as np
11 import matplotlib
12 matplotlib.use('Agg')
13 from matplotlib import pyplot as plt
14 from matplotlib import gridspec
15 import rospy
16 from jsk_topic_tools import ConnectionBasedTransport
17 from jsk_recognition_msgs.msg import ColorHistogram, ColorHistogramArray
18 from sensor_msgs.msg import Image
19 from jsk_pcl_ros.cfg import ColorHistogramVisualizerConfig as Config
20 
21 
22 # matplotlib outputs image with size 800x600 by default
23 IMG_WIDTH=800
24 IMG_HEIGHT=600
25 
26 
27 class ColorHistogramVisualizer(ConnectionBasedTransport):
28  def __init__(self):
29  super(ColorHistogramVisualizer, self).__init__()
30 
31  self.dyn_server = Server(Config, self.config_callback)
32 
33  self.cv_bridge = CvBridge()
34  self.hsv_color_map = plt.cm.get_cmap('hsv')
36 
37  self.pub_image = self.advertise("~output", Image, queue_size=1)
38 
39  def config_callback(self, config, level):
40  self.histogram_policy = config.histogram_policy
41  self.histogram_index = config.histogram_index
42  self.histogram_scale = config.histogram_scale
43  return config
44 
45  def subscribe(self):
46  self.sub_histogram = rospy.Subscriber("~input", ColorHistogram,
47  self.callback, queue_size=1)
48  self.sub_histogram_array = rospy.Subscriber("~input/array", ColorHistogramArray,
49  self.callback_array, queue_size=1)
50 
51  def unsubscribe(self):
52  self.sub_histogram.unregister()
53  self.sub_histogram_array.unregister()
54 
56  hsv_map = np.zeros((IMG_HEIGHT, IMG_WIDTH, 3), np.uint8)
57  h, s = np.indices(hsv_map.shape[:2])
58  hsv_map[:, :, 0] = h / float(IMG_HEIGHT) * 180.0
59  hsv_map[:, :, 1] = 125.0
60  hsv_map[:, :, 2] = s / float(IMG_WIDTH) * 256.0
61  hsv_map = cv2.cvtColor(hsv_map, cv2.COLOR_HLS2BGR)
62  return hsv_map
63 
64  def callback(self, msg):
65  if self.histogram_policy == Config.ColorHistogramVisualizer_HUE:
66  img = self.plot_hist_hue(msg.histogram)
67  elif self.histogram_policy == Config.ColorHistogramVisualizer_HUE_AND_SATURATION:
68  img = self.plot_hist_hs(msg.histogram)
69  else:
70  rospy.logerr("Invalid histogram policy")
71  return
72  try:
73  pub_msg = self.cv_bridge.cv2_to_imgmsg(img, "bgr8")
74  self.pub_image.publish(pub_msg)
75  except Exception as e:
76  rospy.logerr("Failed to convert image: %s" % str(e))
77 
78  def callback_array(self, msg):
79  if 0 <= self.histogram_index < len(msg.histograms):
80  self.callback(msg.histograms[self.histogram_index])
81  else:
82  rospy.logerr("histogram index Out-of-index")
83 
84  def image_from_plot(self):
85  fig = plt.gcf()
86  fig.canvas.draw()
87  w, h = fig.canvas.get_width_height()
88  img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8)
89  fig.clf()
90  img.shape = (h, w, 3)
91  img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
92  return img
93 
94  def plot_hist_hue(self, hist):
95  gs = gridspec.GridSpec(1, 2, width_ratios=[4, 1])
96  if LooseVersion(matplotlib.__version__).version[0] > 1:
97  plt.subplot(gs[0], facecolor='silver')
98  else: # matplotlib version < 2.0.0
99  plt.subplot(gs[0], axisbg='silver')
100  bin_size = len(hist) - 2
101  bin_step = 360.0 / bin_size
102  x = np.arange(360.0, step=bin_step)
103  bars = plt.bar(x, hist[:-2], width=bin_step)
104  cs = np.arange(0.0, 1.0, 1.0 / bin_size)
105  for c, b in zip(cs, bars):
106  b.set_facecolor(self.hsv_color_map(c))
107  plt.xlim(0, 360.0)
108  plt.ylim(ymin=0.0, ymax=1.0)
109  ymin, ymax = plt.ylim()
110  if LooseVersion(matplotlib.__version__).version[0] > 1:
111  plt.subplot(gs[1], facecolor='silver')
112  else: # matplotlib version < 2.0.0
113  plt.subplot(gs[1], axisbg='silver')
114  bars = plt.bar(range(2), hist[-2:], label=["white", "black"],
115  width=1.0, linewidth=2.0)
116  bars[0].set_facecolor((1.0, 1.0, 1.0, 1.0))
117  bars[1].set_facecolor((0.0, 0.0, 0.0, 1.0))
118  plt.ylim(ymin, ymax)
119  return self.image_from_plot()
120 
121  def plot_hist_saturation(self, hist):
122  bin_size = len(hist)
123  bin_step = 256.0 / bin_size
124  x = np.arange(256.0, step=bin_step)
125  plt.bar(x, hist, width=bin_step)
126  plt.xlim(0, 256.0)
127  return self.image_from_plot()
128 
129  def plot_hist_hs(self, hist):
130  bin_size = int(math.sqrt(len(hist) - 2))
131  white, black = hist[-2], hist[-1]
132  hist = np.array(hist[:-2]).reshape(bin_size, bin_size).T
133  rospy.loginfo("white: %f, black: %f" % (white, black))
134  hist = np.clip(hist * 150 * self.histogram_scale, white, 1.0 - black)
135  hist = hist[:, :, np.newaxis]
136  hist = cv2.resize(hist, (IMG_WIDTH, IMG_HEIGHT))
137  hist = hist[:, :, np.newaxis]
138  img = self.hsv_color_map_2d * hist
139  img = img.astype(np.uint8)
140  return img
141 
142 if __name__ == '__main__':
143  rospy.init_node("color_histogram_visualizer")
145  rospy.spin()


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Mon May 3 2021 03:03:46