binpack_rect_array.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
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): # python2
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 # def hoge(msg):
00092 #     print "~input", msg.header.stamp.to_sec()
00093 # def fuga(msg):
00094 #     print "~input/rect_array", msg.header.stamp.to_sec()
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         # self.sub_.registerCallback(hoge)
00104         # self.sub_rects_.registerCallback(fuga)
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         # Solve 2D BinPacking problem
00129         packer = Packer()
00130         blocks = [Block(rect) for rect in rects.rects]
00131         # sort by some algorithms
00132         #blocks.sort(key=lambda x: x.rect.width*x.rect.height, reverse=True)
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         # for block in blocks:
00138         #     if block.fit_location:
00139         #         print (block.fit_location.rect.x, block.fit_location.rect.y, block.fit_location.rect.width, block.fit_location.rect.height)
00140         #         print " --", (block.rect.x, block.rect.y, block.rect.width, block.rect.height)
00141         
00142         
00143 if __name__ == '__main__':
00144     rospy.init_node('binpack')
00145     bin_pack = BinPack()
00146     rospy.spin()


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