00001
00002
00003 import numpy as np
00004
00005 import cv_bridge
00006 from jsk_recognition_utils.depth import split_fore_background
00007 from jsk_topic_tools import ConnectionBasedTransport
00008 from jsk_recognition_msgs.msg import RectArray, Rect
00009 import message_filters
00010 import rospy
00011 from sensor_msgs.msg import Image
00012
00013 class Block():
00014 def __init__(self, rect):
00015 self.rect = rect
00016 self.used = False
00017 def max_cmp(self, another):
00018 return max(self.rect.width, self.rect.height) - max(another.rect.width, another.rect.height)
00019 def min_cmp(self, another):
00020 return min(self.rect.width, self.rect.height) - min(another.rect.width, another.rect.height)
00021 def height_cmp(self, another):
00022 return self.rect.height - another.rect.height
00023 def width_cmp(self, another):
00024 return self.rect.width - another.rect.width
00025 def __cmp__(self, another):
00026 return self.max_cmp(another) or self.min_cmp(another) or self.height_cmp(another) or self.width_cmp(another) or 0
00027
00028 class Packer():
00029 def __init__(self):
00030 pass
00031 def fit(self, blocks):
00032 if len(blocks) == 0:
00033 return
00034 self.root = Block(Rect(x=0, y=0, width=blocks[0].rect.width, height=blocks[0].rect.height))
00035 for block in blocks:
00036 node = self.find_node(self.root, block.rect.width, block.rect.height)
00037 if node:
00038 block.fit_location = self.split(node, block.rect.width, block.rect.height)
00039 else:
00040 block.fit_location = self.grow_node(block.rect.width, block.rect.height)
00041 def find_node(self, root, w, h):
00042 if root.used:
00043 return self.find_node(root.right, w, h) or self.find_node(root.down, w, h)
00044 elif w <= root.rect.width and h <= root.rect.height:
00045 return root
00046 else:
00047 return False
00048 def split(self, node, w, h):
00049 node.used = True
00050 node.down = Block(Rect(x=node.rect.x, y=node.rect.y + h, width=w, height=node.rect.height - h))
00051 node.right = Block(Rect(x=node.rect.x + w, y=node.rect.y, width=node.rect.width - w, height=h))
00052 return node
00053 def grow_node(self, w, h):
00054 can_grow_down = w <= self.root.rect.width
00055 can_grow_right = h <= self.root.rect.height
00056 should_grow_right = can_grow_right and self.root.rect.height >= self.root.rect.width + w
00057 should_grow_down = can_grow_down and self.root.rect.width >= self.root.rect.height + h
00058 if should_grow_right:
00059 return self.grow_right(w, h)
00060 elif should_grow_down:
00061 return self.grow_down(w, h)
00062 elif can_grow_right:
00063 return self.grow_right(w, h)
00064 elif can_grow_down:
00065 return self.grow_down(w, h)
00066 else:
00067 return None
00068 def grow_right(self, w, h):
00069 prev_root = self.root
00070 self.root = Block(Rect(x=0, y=0, width=self.root.rect.width + w, height=self.root.rect.height))
00071 self.root.down = prev_root
00072 self.root.right = Block(Rect(x=prev_root.rect.width, y=0, width=w, height=prev_root.rect.height))
00073 self.root.used = True
00074 node = self.find_node(self.root, w, h)
00075 if node:
00076 return self.split(node, w, h)
00077 else:
00078 return None
00079 def grow_down(self, w, h):
00080 prev_root = self.root
00081 self.root = Block(Rect(x=0, y=0, width=self.root.rect.width, height=self.root.rect.height + h))
00082 self.root.right = prev_root
00083 self.root.down = Block(Rect(x=0, y=prev_root.rect.height, width=prev_root.rect.width, height=h))
00084 self.root.used = True
00085 node = self.find_node(self.root, w, h)
00086 if node:
00087 return self.split(node, w, h)
00088 else:
00089 return None
00090
00091
00092
00093
00094
00095
00096 class BinPack(ConnectionBasedTransport):
00097 def __init__(self):
00098 super(BinPack, self).__init__()
00099 self.pub_ = self.advertise('~output', Image, queue_size=10)
00100 def subscribe(self):
00101 self.sub_ = message_filters.Subscriber('~input', Image, queue_size=1)
00102 self.sub_rects_ = message_filters.Subscriber('~input/rect_array', RectArray, queue_size=1)
00103
00104
00105 if rospy.get_param('~approximate_sync', False):
00106 self.sync = message_filters.ApproximateTimeSynchronizer(
00107 [self.sub_, self.sub_rects_], queue_size=100, slop=.1)
00108 else:
00109 self.sync = message_filters.TimeSynchronizer(
00110 [self.sub_, self.sub_rects_], queue_size=100)
00111 self.sync.registerCallback(self._apply)
00112 def unsubscribe(self):
00113 self.sub_.sub.unregister()
00114 self.sub_rects_.sub.unregister()
00115 def _apply(self, img_msg, rects):
00116 bridge = cv_bridge.CvBridge()
00117 img = bridge.imgmsg_to_cv2(img_msg)
00118 root_rect, blocks = self.bin_pack(rects)
00119 output_img = np.zeros((root_rect.height, root_rect.width, img.shape[2]), dtype=img.dtype)
00120 for block in blocks:
00121 location = block.fit_location
00122 output_img[location.rect.y:location.rect.y + block.rect.height,
00123 location.rect.x:location.rect.x + block.rect.width] = img[block.rect.y:block.rect.y+block.rect.height, block.rect.x:block.rect.x + block.rect.width]
00124 output_img_msg = bridge.cv2_to_imgmsg(output_img, encoding=img_msg.encoding)
00125 output_img_msg.header = img_msg.header
00126 self.pub_.publish(output_img_msg)
00127 def bin_pack(self, rects):
00128
00129 packer = Packer()
00130 blocks = [Block(rect) for rect in rects.rects]
00131
00132
00133 blocks.sort(reverse=True)
00134 packer.fit(blocks)
00135 print (packer.root.rect.width, packer.root.rect.height)
00136 return (packer.root.rect, blocks)
00137
00138
00139
00140
00141
00142
00143 if __name__ == '__main__':
00144 rospy.init_node('binpack')
00145 bin_pack = BinPack()
00146 rospy.spin()