label_image_decomposer.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 import sys
00004 
00005 import cv2
00006 import matplotlib
00007 matplotlib.use('Agg')  # NOQA
00008 import matplotlib.cm
00009 import numpy as np
00010 import scipy.ndimage
00011 
00012 import cv_bridge
00013 import dynamic_reconfigure.server
00014 from jsk_recognition_utils import bounding_rect_of_mask
00015 from jsk_recognition_utils import get_tile_image
00016 from jsk_recognition_utils.color import labelcolormap
00017 from jsk_topic_tools import ConnectionBasedTransport
00018 from jsk_topic_tools import warn_no_remap
00019 import message_filters
00020 import rospy
00021 from sensor_msgs.msg import Image
00022 
00023 from jsk_perception.cfg import LabelImageDecomposerConfig
00024 
00025 
00026 def get_text_color(color):
00027     if color[0] * 0.299 + color[1] * 0.587 + color[2] * 0.114 > 170:
00028         return (0, 0, 0)
00029     return (255, 255, 255)
00030 
00031 
00032 def label2rgb(lbl, img=None, label_names=None, alpha=0.3, bg_label=0):
00033     if label_names is None:
00034         n_labels = lbl.max() + 1  # +1 for bg_label 0
00035     else:
00036         n_labels = len(label_names)
00037     cmap = labelcolormap(256)
00038     cmap = (cmap * 255).astype(np.uint8)
00039     bg_color, cmap = cmap[0], cmap[1:]  # bg_color is 0
00040 
00041     lbl_viz = np.zeros((lbl.shape[0], lbl.shape[1], 3), dtype=np.uint8)
00042     fg_mask = lbl != bg_label
00043     lbl_viz[fg_mask] = cmap[lbl[fg_mask] % 256]
00044     lbl_viz[~fg_mask] = bg_color
00045 
00046     if img is not None:
00047         if img.ndim == 3:
00048             img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
00049         else:
00050             assert img.ndim == 2
00051             img_gray = img
00052         img_gray = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2RGB)
00053         lbl_viz = alpha * lbl_viz + (1 - alpha) * img_gray
00054         lbl_viz = lbl_viz.astype(np.uint8)
00055 
00056     if label_names is None:
00057         return lbl_viz
00058 
00059     np.random.seed(1234)
00060     labels = np.unique(lbl)
00061     labels = labels[labels != 0]
00062     for label in labels:
00063         mask = lbl == label
00064         mask = (mask * 255).astype(np.uint8)
00065         y, x = scipy.ndimage.center_of_mass(mask)
00066         y, x = map(int, [y, x])
00067 
00068         if lbl[y, x] != label:
00069             Y, X = np.where(mask)
00070             point_index = np.random.randint(0, len(Y))
00071             y, x = Y[point_index], X[point_index]
00072 
00073         text = label_names[label]
00074         font_face = cv2.FONT_HERSHEY_SIMPLEX
00075         font_scale = 0.7
00076         thickness = 2
00077         text_size, baseline = cv2.getTextSize(
00078             text, font_face, font_scale, thickness)
00079 
00080         color = get_text_color(lbl_viz[y, x])
00081         cv2.putText(lbl_viz, text,
00082                     (x - text_size[0] // 2, y),
00083                     font_face, font_scale, color, thickness)
00084     return lbl_viz
00085 
00086 
00087 class LabelImageDecomposer(ConnectionBasedTransport):
00088 
00089     def __init__(self):
00090         super(LabelImageDecomposer, self).__init__()
00091 
00092         self._srv_dynparam = dynamic_reconfigure.server.Server(
00093             LabelImageDecomposerConfig, self._config_callback)
00094 
00095         self.pub_img = self.advertise('~output', Image, queue_size=5)
00096         self.pub_label_viz = self.advertise('~output/label_viz', Image,
00097                                             queue_size=5)
00098         self._bg_label = rospy.get_param('~bg_label', 0)  # ignored label
00099         self._only_label = rospy.get_param('~only_label', False)
00100         self._label_names = rospy.get_param('~label_names', None)
00101         # publish masks of fg/bg by decomposing each label
00102         self._publish_mask = rospy.get_param('~publish_mask', False)
00103         if self._publish_mask:
00104             self.pub_fg_mask = self.advertise('~output/fg_mask', Image,
00105                                               queue_size=5)
00106             self.pub_bg_mask = self.advertise('~output/bg_mask', Image,
00107                                               queue_size=5)
00108         # publish each region image. this can take time so optional.
00109         self._publish_tile = rospy.get_param('~publish_tile', False)
00110         rospy.loginfo('~publish_tile: {}'.format(self._publish_tile))
00111         if self._only_label and self._publish_tile:
00112             rospy.logerr('Can not publish tile image when ~only_label is true,'
00113                          ' so forcely set ~publish_tile to false.')
00114             self._publish_tile = False
00115         if self._publish_tile:
00116             self.pub_tile = self.advertise('~output/tile', Image, queue_size=5)
00117 
00118     def _config_callback(self, config, level):
00119         self._alpha = config.alpha
00120         return config
00121 
00122     def subscribe(self):
00123         self.sub_label = message_filters.Subscriber('~input/label', Image)
00124         if self._only_label:
00125             self.sub_label.registerCallback(self._apply)
00126             return
00127         self.sub_img = message_filters.Subscriber('~input', Image)
00128         warn_no_remap('~input', '~input/label')
00129         use_async = rospy.get_param('~approximate_sync', False)
00130         queue_size = rospy.get_param('~queue_size', 10)
00131         rospy.loginfo('~approximate_sync: {}, queue_size: {}'
00132                       .format(use_async, queue_size))
00133         if use_async:
00134             slop = rospy.get_param('~slop', 0.1)
00135             rospy.loginfo('~slop: {}'.format(slop))
00136             async = message_filters.ApproximateTimeSynchronizer(
00137                 [self.sub_label, self.sub_img],
00138                 queue_size=queue_size, slop=slop)
00139             async.registerCallback(self._apply)
00140             if self._publish_tile:
00141                 async.registerCallback(self._apply_tile)
00142         else:
00143             sync = message_filters.TimeSynchronizer(
00144                 [self.sub_label, self.sub_img], queue_size=queue_size)
00145             sync.registerCallback(self._apply)
00146             if self._publish_tile:
00147                 sync.registerCallback(self._apply_tile)
00148 
00149     def unsubscribe(self):
00150         self.sub_img.sub.unregister()
00151         self.sub_label.sub.unregister()
00152 
00153     def _apply(self, label_msg, img_msg=None):
00154         bridge = cv_bridge.CvBridge()
00155         label_img = bridge.imgmsg_to_cv2(label_msg)
00156         if img_msg:
00157             img = bridge.imgmsg_to_cv2(img_msg)
00158             # publish only valid label region
00159             applied = img.copy()
00160             applied[label_img == self._bg_label] = 0
00161             applied_msg = bridge.cv2_to_imgmsg(applied, encoding=img_msg.encoding)
00162             applied_msg.header = img_msg.header
00163             self.pub_img.publish(applied_msg)
00164             # publish visualized label
00165             if img_msg.encoding in {'16UC1', '32SC1'}:
00166                 # do dynamic scaling to make it look nicely
00167                 min_value, max_value = img.min(), img.max()
00168                 img = (img - min_value) / (max_value - min_value) * 255
00169                 img = img.astype(np.uint8)
00170                 img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
00171         else:
00172             img = None
00173 
00174         label_viz = label2rgb(label_img, img, label_names=self._label_names,
00175                               alpha=self._alpha, bg_label=self._bg_label)
00176         label_viz_msg = bridge.cv2_to_imgmsg(label_viz, encoding='rgb8')
00177         label_viz_msg.header = label_msg.header
00178         self.pub_label_viz.publish(label_viz_msg)
00179 
00180         # publish mask
00181         if self._publish_mask:
00182             bg_mask = (label_img == 0)
00183             fg_mask = ~bg_mask
00184             bg_mask = (bg_mask * 255).astype(np.uint8)
00185             fg_mask = (fg_mask * 255).astype(np.uint8)
00186             fg_mask_msg = bridge.cv2_to_imgmsg(fg_mask, encoding='mono8')
00187             fg_mask_msg.header = label_msg.header
00188             bg_mask_msg = bridge.cv2_to_imgmsg(bg_mask, encoding='mono8')
00189             bg_mask_msg.header = label_msg.header
00190             self.pub_fg_mask.publish(fg_mask_msg)
00191             self.pub_bg_mask.publish(bg_mask_msg)
00192 
00193     def _apply_tile(self, label_msg, img_msg):
00194         bridge = cv_bridge.CvBridge()
00195         img = bridge.imgmsg_to_cv2(img_msg)
00196         label_img = bridge.imgmsg_to_cv2(label_msg)
00197 
00198         imgs = []
00199         labels = np.unique(label_img)
00200         for label in labels:
00201             if label == 0:
00202                 # should be skipped 0, because
00203                 # 0 is to label image as black region to mask image
00204                 continue
00205             img_tmp = img.copy()
00206             mask = label_img == label
00207             img_tmp[~mask] = 0
00208             img_tmp = bounding_rect_of_mask(img_tmp, mask)
00209             imgs.append(img_tmp)
00210         tile_img = get_tile_image(imgs)
00211         tile_msg = bridge.cv2_to_imgmsg(tile_img, encoding='bgr8')
00212         tile_msg.header = img_msg.header
00213         self.pub_tile.publish(tile_msg)
00214 
00215 
00216 if __name__ == '__main__':
00217     rospy.init_node('label_image_decomposer')
00218     label_image_decomposer = LabelImageDecomposer()
00219     rospy.spin()


jsk_perception
Author(s): Manabu Saito, Ryohei Ueda
autogenerated on Tue Jul 2 2019 19:41:07