def __call__(self, fname):
        with Image.open(fname) as img:
            img = img.convert('RGB')
        img_size = Size(img.size[0], img.size[1])

        if self.dataset == 'VOC':
            #fname : '~/VOC/JPEGImages/002222.jpg'
            with open(
                    os.path.join(fname[:-21], 'Annotations',
                                 fname[-10:-4] + '.xml'), 'r') as f:
                doc = lxml.etree.parse(f)
                boxes = []
                objects = doc.xpath('/annotation/object')

                for obj in objects:
                    label = obj.xpath('name')[0].text
                    xmin = float(obj.xpath('bndbox/xmin')[0].text)
                    xmax = float(obj.xpath('bndbox/xmax')[0].text)
                    ymin = float(obj.xpath('bndbox/ymin')[0].text)
                    ymax = float(obj.xpath('bndbox/ymax')[0].text)

                    labels = self.label2idx[label]

                    center, size = abs2prop(
                        xmin, xmax, ymin, ymax,
                        img_size)  # make gt to 0~1 important!!!!!!!!!!!!!!
                    box = Box(obj, labels, center, size)
                    boxes.append(box)

        elif self.dataset == 'KITTI':
            with open(
                    os.path.join(fname[:-18], 'label_2',
                                 fname[-10:-4] + '.txt'), 'r') as fp:
                objs = [line.split(' ') for line in fp.readlines()]
            boxes = []
            for obj in objs:
                if not obj[0] == 'DontCare':
                    xmin = float(obj[4])
                    ymin = float(obj[5])
                    xmax = float(obj[6])
                    ymax = float(obj[7])
                    label = self.label2idx[obj[0]]
                    center, size = abs2prop(
                        xmin, xmax, ymin, ymax, img_size
                    )  # Convert the absolute min-max box bound to proportional center-width bounds
                    # (/300 , /1300) -> (0~1, 0~1)
                    box = Box(obj[0], label, center, size)
                    boxes.append(box)

        sample = Sample(fname, boxes, img_size)
        return img, labels, sample
Exemple #2
0
    def initialize_screen(self):
        self.screen = pygame.display.set_mode(
            (self.SCREEN_WIDTH, self.SCREEN_HEIGHT),
            HWSURFACE | DOUBLEBUF | RESIZABLE, 32)
        self.field_rect_outer = Rect(
            self.FIELD_LIMITS[0], self.FIELD_LIMITS[1],
            int(self.FIELD_SIZE[0] * self.zoom_factor),
            int(self.FIELD_SIZE[1] * self.zoom_factor))

        self.field_box = Box(surface=self.screen,
                             rect=self.field_rect_outer,
                             background_color=self.field_bgcolor)

        self.field_rect = self.field_box.get_internal_rect()
def transform_box(box, orig_size, new_size, h_off, w_off):
    #---------------------------------------------------------------------------
    # Compute the new coordinates of the box
    #---------------------------------------------------------------------------
    xmin, xmax, ymin, ymax = prop2abs(box.center, box.size, orig_size)
    xmin += w_off
    xmax += w_off
    ymin += h_off
    ymax += h_off

    #---------------------------------------------------------------------------
    # Check if the center falls within the image
    #---------------------------------------------------------------------------
    width = xmax - xmin
    height = ymax - ymin
    new_cx = xmin + int(width / 2)
    new_cy = ymin + int(height / 2)
    if new_cx < 0 or new_cx >= new_size.w:
        return None
    if new_cy < 0 or new_cy >= new_size.h:
        return None

    center, size = abs2prop(xmin, xmax, ymin, ymax, new_size)

    return Box(box.label, box.labelid, center, size)
Exemple #4
0
    def _load_target(self, image_id, img_size=None):
        annotation_path = path.join(
            config.DATA_PATH.format(name=self._NAME),
            config.ANNOTATIONS_PATH.format(id_=image_id))
        with open(annotation_path) as fp:
            next(fp), next(fp)  # Skip the first two rows
            reader = csv.DictReader(fp,
                                    fieldnames=("x1", "y1", "x2", "y2", "x3",
                                                "y3", "x4", "y4", "category",
                                                "difficult"),
                                    delimiter=" ")

            boxes = []
            labels = []
            for r in reader:
                label_id = self._REVERSE_LABELS_DICT.get(r["category"])
                if label_id is None:
                    continue
                x1, y1, x2, y2, x3, y3, x4, y4 = [
                    float(r[k])
                    for k in ("x1", "y1", "x2", "y2", "x3", "y3", "x4", "y4")
                ]

                x_min = min(x1, x2, x3, x4)
                y_min = min(y1, y2, y3, y4)
                x_max = max(x1, x2, x3, x4)
                y_max = max(y1, y2, y3, y4)
                boxes.append(Box(x_min, y_min, x_max, y_max))
                labels.append(label_id)

        return dict(boxes=boxes, labels=labels)
 def __build_sample_list(self, root, annot_files, dataset_name):
     image_root = root + '/JPEGImages/'
     samples = []
     for fn in tqdm(annot_files, desc=dataset_name, unit='samples'):
         with open(fn, 'r') as f:
             doc = lxml.etree.parse(f)
             filename = image_root + doc.xpath(
                 '/annotation/filename')[0].text
             if not os.path.exists(filename):
                 continue
             img = cv2.imread(filename)
             imgsize = Size(img.shape[1], img.shape[0])
             boxes = []
             objects = doc.xpath('/annotation/object')
             for obj in objects:
                 label = obj.xpath('name')[0].text
                 if label == myObject:
                     xmin = int(float(obj.xpath('bndbox/xmin')[0].text))
                     xmax = int(float(obj.xpath('bndbox/xmax')[0].text))
                     ymin = int(float(obj.xpath('bndbox/ymin')[0].text))
                     ymax = int(float(obj.xpath('bndbox/ymax')[0].text))
                     center, size = abs2prop(xmin, xmax, ymin, ymax,
                                             imgsize)
                     box = Box(label, self.lname2id[label], center, size)
                     boxes.append(box)
             if not boxes:
                 continue
             sample = Sample(filename, boxes, imgsize)
             samples.append(sample)
     return samples
    def __call__(self, img, targets):
        if self._symmetric:
            scale_y = 1 + random.uniform(-self._scale, self._scale)
            scale_x = scale_y
        else:
            scale_y = 1 + random.uniform(-self._scale, self._scale)
            scale_x = 1 + random.uniform(-self._scale, self._scale)

        H, W, C = img.shape
        img = cv2.resize(img, None, fx=scale_x, fy=scale_y)
        
        new_H, new_W, _ = img.shape
        y_pad = H - new_H
        x_pad = W - new_W
        # When we scale, with a factor >1 some part of the image must be dropped,
        # We handle this via a ._pad<0 and we make sure we drop the same amount on each side of the image
        # ie the center of the image remains fixes
        # Same for factors <1, describing padding of size ._pad>0 to be added
        y_pad_1, y_pad_2 = ceil(y_pad/2.), floor(y_pad/2.)
        x_pad_1, x_pad_2 = ceil(x_pad/2.), floor(x_pad/2.)

        canvas = np.zeros((H, W, C))
   
        canvas[max(y_pad_1,0):min(H-y_pad_2,H), max(x_pad_1,0):min(W-x_pad_2,W), :] = \
            img[max(-y_pad_1,0):H-y_pad_1, max(-x_pad_1,0):W-x_pad_1, :]
        img = canvas
    
        targets["boxes"] *= [scale_x, scale_y, scale_x, scale_y]
        targets["boxes"] += [x_pad/2, y_pad/2, x_pad/2, y_pad/2]
        targets = clip_boxes(targets, Box(0,0,W,H))
    
        return img, targets
Exemple #7
0
    def _crop_to_size(cls, image, target, recurs_cnt=0):
        # Dota contains images of differnt size, but each pixel represents the same scale
        # Make sure all images are at the same scale by croping to a maximum size
        H, W = image.size[::-1]  # PIL returns W, H
        nH, nW = config.CROP_TO_SIZE
        nH, nW = min(H, nH), min(W, nW)
        offset_y, offset_x = random.randint(0,
                                            H - nH), random.randint(0, W - nW)
        new_image = image.crop(
            (offset_x, offset_y, offset_x + nW, offset_y + nH))
        new_boxes = [
            Box(b.x_min - offset_x, b.y_min - offset_y, b.x_max - offset_x,
                b.y_max - offset_y) for b in target["boxes"]
        ]

        # Remove boxes outside the image
        new_target = {"boxes": [], "labels": []}
        for box, label in zip(new_boxes, target["labels"]):
            if box.x_min >= 0 and box.y_min >= 0 and box.x_max <= nW and box.y_max <= nH:
                new_target["boxes"].append(box)
                new_target["labels"].append(label)

        if not new_target["labels"]:
            # We removed all boxes, retry
            return cls._crop_to_size(image, target, recurs_cnt + 1)
        else:
            return new_image, new_target
 def __call__(self, data, label, gt):
     flip = data.transpose(Image.FLIP_LEFT_RIGHT)
     boxes = []
     for box in gt.boxes:
         center = Point(1 - box.center.x, box.center.y)
         box = Box(box.label, box.labelid, center, box.size)
         boxes.append(box)
     gt = Sample(gt.filename, boxes, gt.imgsize)
     return flip, label, gt
Exemple #9
0
    def __call__(self, data, label, gt):
        data = cv2.flip(data, 1)
        boxes = []
        for box in gt.boxes:
            center = Point(1 - box.center.x, box.center.y)
            box = Box(box.label, box.labelid, center, box.size)
            boxes.append(box)
        gt = Sample(gt.filename, boxes, gt.imgsize)

        return data, label, gt
Exemple #10
0
    def __call__(self, data, label, gt):
        #-----------------------------------------------------------------------
        # Check whether to sample or not
        #-----------------------------------------------------------------------
        if not self.sample:
            return data, label, gt

        #-----------------------------------------------------------------------
        # Retry sampling a couple of times
        #-----------------------------------------------------------------------
        source_boxes = anchors2array(gt.boxes, gt.imgsize)
        box = None
        box_arr = None
        for _ in range(self.max_trials):
            #-------------------------------------------------------------------
            # Sample a bounding box
            #-------------------------------------------------------------------
            scale = random.uniform(self.min_scale, self.max_scale)
            aspect_ratio = random.uniform(self.min_aspect_ratio,
                                          self.max_aspect_ratio)

            # make sure width and height will not be larger than 1
            aspect_ratio = max(aspect_ratio, scale**2)
            aspect_ratio = min(aspect_ratio, 1 / (scale**2))

            width = scale * sqrt(aspect_ratio)
            height = scale / sqrt(aspect_ratio)
            cx = 0.5 * width + random.uniform(0, 1 - width)
            cy = 0.5 * height + random.uniform(0, 1 - height)
            center = Point(cx, cy)
            size = Size(width, height)

            #-------------------------------------------------------------------
            # Check if the box satisfies the jaccard overlap constraint
            #-------------------------------------------------------------------
            box_arr = np.array(prop2abs(center, size, gt.imgsize))
            overlap = compute_overlap(box_arr, source_boxes, 0)
            if overlap.best and overlap.best.score >= self.min_jaccard_overlap:
                box = Box(None, None, center, size)
                break

        if box is None:
            return None

        #-----------------------------------------------------------------------
        # Crop the box and adjust the ground truth
        #-----------------------------------------------------------------------
        new_size = Size(box_arr[1] - box_arr[0], box_arr[3] - box_arr[2])
        w_off = -box_arr[0]
        h_off = -box_arr[2]
        data = data[box_arr[2]:box_arr[3], box_arr[0]:box_arr[1]]
        gt = transform_gt(gt, new_size, h_off, w_off)

        return data, label, gt
    def __build_sample_list(self, root, annot_files):
        """
        Build a list of samples for the VOC dataset (either trainval or test)
        """
        image_root = os.path.join(root, 'rgb-images')
        samples = []
        #-----------------------------------------------------------------------
        # Process each annotated sample
        #-----------------------------------------------------------------------
        for fn in tqdm(annot_files, desc='ucf_24_frame', unit='samples'):
            act = fn.split('/')[4]
            video = fn.split('/')[5]
            frame_id = fn.split('/')[-1][:-4]
            image_path = os.path.join(image_root, act, video,
                                      '{}.jpg'.format(frame_id))

            #---------------------------------------------------------------
            # Get the file dimensions
            #---------------------------------------------------------------
            if not os.path.exists(image_path):
                continue

            img = cv2.imread(image_path)
            imgsize = Size(img.shape[1], img.shape[0])

            #---------------------------------------------------------------
            # Get boxes for all the objects
            #---------------------------------------------------------------
            boxes = []
            with open(fn, 'r') as fin:
                objects = fin.readlines()
            for line in objects:
                line = line[:-1]
                #-----------------------------------------------------------
                # Get the properties of the box and convert them to the
                # proportional terms
                #-----------------------------------------------------------
                obj = line.split(' ')
                label = int(obj[0]) - 1
                xmin = int(float(obj[1]))
                ymin = int(float(obj[2]))
                xmax = int(float(obj[3]))
                ymax = int(float(obj[4]))

                center, size = abs2prop(xmin, xmax, ymin, ymax, imgsize)
                box = Box(self.lid2name[label], label, center, size)
                boxes.append(box)
            if not boxes:
                continue
            sample = Sample(image_path, boxes, imgsize)
            samples.append(sample)

        return samples
    def _build_sample_list(self, root, annot_files):
        image_root = root + 'VOC_Jpeg/'
        image_seg_root = root + 'VOC_Segmentation/'
        samples = []

        for fn in tqdm(annot_files, unit='samples'):
            with open(fn, 'r') as f:
                doc = lxml.etree.parse(f)
                filename = image_root + doc.xpath(
                    '/annotation/filename')[0].text
                with open(fn, 'r') as f1:
                    doc1 = lxml.etree.parse(f1)
                    seg_gt = image_seg_root + doc1.xpath(
                        '/annotation/filename')[0].text
                    seg_gt = seg_gt.replace('jpg', 'png')
                    seg_gt_to_compare = seg_gt

                #---------------------------------------------------------------
                # Get the file dimensions
                #---------------------------------------------------------------
                if not os.path.exists(filename):
                    continue

                img = cv2.imread(filename)
                img_seg_gt = cv2.imread(seg_gt)
                imgsize = Size(img.shape[1], img.shape[0])

                #---------------------------------------------------------------
                # Get boxes for all the objects
                #---------------------------------------------------------------
                boxes = []
                objects = doc.xpath('/annotation/object')
                for obj in objects:
                    #-----------------------------------------------------------
                    # Get the properties of the box and convert them to the
                    # proportional terms
                    #-----------------------------------------------------------
                    label = obj.xpath('name')[0].text
                    xmin = int(float(obj.xpath('bndbox/xmin')[0].text))
                    xmax = int(float(obj.xpath('bndbox/xmax')[0].text))
                    ymin = int(float(obj.xpath('bndbox/ymin')[0].text))
                    ymax = int(float(obj.xpath('bndbox/ymax')[0].text))
                    center, size = abs2prop(xmin, xmax, ymin, ymax, imgsize)
                    box = Box(label, self.lname2id[label], center, size)
                    boxes.append(box)
                if not boxes:
                    continue
                sample = Sample(filename, boxes, imgsize, seg_gt,
                                seg_gt_to_compare)
                samples.append(sample)

        return samples
    def __build_sample_list(self, root, dataset_name):
        """
        Build a list of samples for the VOC dataset (either trainval or test)
        """
        image_root = root + '/JPEGImages/'
        annot_root = root + '/Annotations/'
        annot_files = glob(annot_root + '/*xml')
        samples = []

        #-----------------------------------------------------------------------
        # Process each annotated sample
        #-----------------------------------------------------------------------
        for fn in tqdm(annot_files, desc=dataset_name, unit='samples'):
            with open(fn, 'r') as f:
                doc = lxml.etree.parse(f)
                filename = image_root + doc.xpath(
                    '/annotation/filename')[0].text

                #---------------------------------------------------------------
                # Get the file dimensions
                #---------------------------------------------------------------
                if not os.path.exists(filename):
                    continue

                img = cv2.imread(filename)
                imgsize = Size(img.shape[1], img.shape[0])

                #---------------------------------------------------------------
                # Get boxes for all the objects
                #---------------------------------------------------------------
                boxes = []
                objects = doc.xpath('/annotation/object')
                for obj in objects:
                    #-----------------------------------------------------------
                    # Get the properties of the box and convert them to the
                    # proportional terms
                    #-----------------------------------------------------------
                    label = obj.xpath('name')[0].text
                    xmin = int(float(obj.xpath('bndbox/xmin')[0].text))
                    xmax = int(float(obj.xpath('bndbox/xmax')[0].text))
                    ymin = int(float(obj.xpath('bndbox/ymin')[0].text))
                    ymax = int(float(obj.xpath('bndbox/ymax')[0].text))
                    center, size = abs2prop(xmin, xmax, ymin, ymax, imgsize)
                    box = Box(label, self.lname2id[label], center, size)
                    boxes.append(box)
                if not boxes:
                    continue
                sample = Sample(filename, boxes, imgsize)
                samples.append(sample)

        return samples
Exemple #14
0
    def initialize_screen(self):
        self.screen = pygame.display.set_mode((self.SCREEN_WIDTH, self.SCREEN_HEIGHT),
                                              HWSURFACE | DOUBLEBUF | RESIZABLE, 32)
        self.field_rect_outer = Rect(self.FIELD_LIMITS[0],
                                     self.FIELD_LIMITS[1],
                                     int(self.FIELD_SIZE[0]*self.zoom_factor),
                                     int(self.FIELD_SIZE[1]*self.zoom_factor))

        self.field_box = Box(surface=self.screen,
            rect=self.field_rect_outer, 
            background_color=self.field_bgcolor
        )

        self.field_rect = self.field_box.get_internal_rect()
    def __call__(self, img, targets):
        H, W, C = img.shape
        move_y = int(random.uniform(-self._rel_step, self._rel_step) * H)
        move_x = int(random.uniform(-self._rel_step, self._rel_step) * W)

        canvas = np.zeros((H, W, C), dtype=np.float)
   
        canvas[max(move_y,0):min(H+move_y, H), max(move_x,0):min(W+move_x, W), :] = \
            img[max(-move_y,0):min(H-move_y, H), max(-move_x,0):min(W-move_x, W), :]
        img = canvas

        targets["boxes"] += [move_x, move_y, move_x, move_y]
        targets = clip_boxes(targets, Box(0,0,W,H))

        return img, targets
 def __build_sample_list(self, root,image_dir,info_dir):
     """
     Build a list of samples for the VOC dataset (either trainval or test)
     """
     samples     = []
     file = open(root+info_dir ,'r')
     All = file.read()
     file.close()
     lines = All.split('\n')
     print(len(lines))
     #-----------------------------------------------------------------------
     # Process each annotated sample
     #-----------------------------------------------------------------------
     i=0
     while i<(len(lines)-1)/10:
         #---------------------------------------------------------------
         # Get the file dimensions
         #---------------------------------------------------------------
         filename = root+image_dir+lines[i]
         img = cv2.imread(filename)
         imgsize = Size(img.shape[1], img.shape[0])
         #---------------------------------------------------------------
         # Get boxes for all the objects
         #---------------------------------------------------------------
         boxes    = []
         i+=1
         num_objects  = int(lines[i])
         if not num_objects:
             i+=2
             continue
         i+=1
         for obj in range(num_objects):
             #-----------------------------------------------------------
             # Get the properties of the box and convert them to the
             # proportional terms
             #-----------------------------------------------------------
             label = 'face'
             xmin = int(lines[i+obj].split()[0])-int(lines[i+obj].split()[2])/2
             xmax = int(lines[i+obj].split()[0])+int(lines[i+obj].split()[2])/2
             ymin = int(lines[i+obj].split()[1])-int(lines[i+obj].split()[3])/2
             ymax = int(lines[i+obj].split()[1])+int(lines[i+obj].split()[3])/2
             center, size = abs2prop(xmin, xmax, ymin, ymax, imgsize)
             box = Box(label, self.lname2id[label], center, size)
             boxes.append(box)
         i+=num_objects
         sample = Sample(filename, boxes, imgsize)
         samples.append(sample)
     return samples
Exemple #17
0
def _match_batch_img_sizes(batch):
    # Resize so that all images have the same size -> Varying sizes create memory leak in FasterRCNN
    # nH = max(img.size[1] for img, _ in batch)
    # nW = max(img.size[0] for img, _ in batch)
    nH = nW = config.IMAGE_SIZE
    new_batch = []
    for image, target in batch:
        H, W = image.size[::-1]  # PIL returns W, H
        scale_y, scale_x = nH / H, nW / W
        image = image.resize((nW, nH))
        target["boxes"] = [
            Box(b.x_min * scale_x, b.y_min * scale_y, b.x_max * scale_x,
                b.y_max * scale_y) for b in target["boxes"]
        ]
        new_batch.append((image, target))
    return new_batch
Exemple #18
0
    def _load_target(self, image_id, img_size=None):
        annotation_path = self._annotation_path(image_id)
        with open(annotation_path) as fp:
            reader = csv.DictReader(fp, fieldnames=("label", "cx", "cy", "width", "height"), delimiter=" ")

            boxes = []
            labels = []
            W, H = img_size
            for r in reader:
                cx, cy, w, h = float(r["cx"]), float(r["cy"]), float(r["width"]), float(r["height"])
                    
                x_min = max(cx*W - w*W/2, 0)
                y_min = max(cy*H - h*H/2, 0)
                x_max = min(cx*W + w*W/2, W)
                y_max = min(cy*H + h*H/2, H)
                boxes.append(Box(x_min, y_min, x_max, y_max))
                labels.append(int(r["label"]))

        return dict(boxes=boxes, labels=labels)
Exemple #19
0
def decode_boxes(pred,
                 anchors,
                 confidence_threshold=0.01,
                 lid2name={},
                 detections_cap=200):
    """
    Decode boxes from the neural net predictions.
    Label names are decoded using the lid2name dictionary - the id to name
    translation is not done if the corresponding key does not exist.
    """

    #---------------------------------------------------------------------------
    # Find the detections
    #---------------------------------------------------------------------------
    num_classes = pred.shape[1] - 4
    bg_class = num_classes - 1
    box_class = np.argmax(pred[:, :num_classes - 1], axis=1)
    confidence = pred[np.arange(len(pred)), box_class]
    if detections_cap is not None:
        detections = np.argsort(confidence)[::-1][:detections_cap]
    else:
        detections = np.argsort(confidence)[::-1]

    #---------------------------------------------------------------------------
    # Decode coordinates of each box with confidence over a threshold
    #---------------------------------------------------------------------------
    boxes = []
    for idx in detections:
        confidence = pred[idx, box_class[idx]]
        if confidence < confidence_threshold:
            break

        center, size = decode_location(pred[idx, num_classes:], anchors[idx])
        cid = box_class[idx]
        cname = None
        if cid in lid2name:
            cname = lid2name[cid]
        det = (confidence, normalize_box(Box(cname, cid, center, size)))
        boxes.append(det)

    return boxes
Exemple #20
0
 def __call__(self, img, targets):
     H, W, _ = img.shape
     targets = clip_boxes(targets, Box(0, 0, W, H))
     return img, targets
Exemple #21
0
class Simulation(object):
    """ 
    The main simulation entry point 
    """

    # basic defaults
    SCREEN_WIDTH, SCREEN_HEIGHT = 700, 700
    GRID_SIZE = 20, 20
    FIELD_SIZE = 500, 500
    FIELD_LIMITS = 0, 0, 600, 600
    field_bgcolor = SIM_COLORS['white']

    def __init__(self, params=None):
        pygame.init()

        if params is not None:
            self.SCREEN_HEIGHT, self.SCREEN_WIDTH = int(float(params['display']['height']) * SCALE), \
                                                    int(float(params['display']['width']) * SCALE)
            self.FIELD_LIMITS = int(float(params['field_top_left_x']) * SCALE), \
                                int(float(params['field_top_left_y']) * SCALE), \
                                int(float(params['field_bottom_right_x']) * SCALE), \
                                int(float(params['field_bottom_right_y']) * SCALE)
            self.FIELD_SIZE = self.FIELD_LIMITS[2] - self.FIELD_LIMITS[
                0], self.FIELD_LIMITS[3] - self.FIELD_LIMITS[1]
            self.GRID_SIZE = int(float(params['cell']['width']) * SCALE), int(
                float(params['cell']['height']) * SCALE)

        # zoom and centering
        self.offset = 0, 0
        self.zoom_factor = 1.0
        self._old_screen = self.SCREEN_WIDTH, self.SCREEN_HEIGHT

        # setup the screen and the box field of play
        self.initialize_screen()

        # agents
        self.agents = pygame.sprite.Group()
        self.agent_image = pygame.image.load(
            'assets/blueagent.bmp').convert_alpha()
        self.controller = SocialForceController(self)
        # self.controller = RandomController(self)

        # time related items
        self.clock = pygame.time.Clock()
        self.paused = False
        self.simulation_timer = Timer(10, self.simulation_update)

        # create the grid
        self.setup_grid()

        # additional options (remove this)
        self.options = dict(draw_grid=True)

        # setup objects (waypoints, obstacles)
        self.waypoints = dict()
        self.obstacles = []
        self._agent_count = 0

        # initialize the time
        self.time_passed = 0

    def initialize_screen(self):
        self.screen = pygame.display.set_mode(
            (self.SCREEN_WIDTH, self.SCREEN_HEIGHT),
            HWSURFACE | DOUBLEBUF | RESIZABLE, 32)
        self.field_rect_outer = Rect(
            self.FIELD_LIMITS[0], self.FIELD_LIMITS[1],
            int(self.FIELD_SIZE[0] * self.zoom_factor),
            int(self.FIELD_SIZE[1] * self.zoom_factor))

        self.field_box = Box(surface=self.screen,
                             rect=self.field_rect_outer,
                             background_color=self.field_bgcolor)

        self.field_rect = self.field_box.get_internal_rect()

    def setup_grid(self):
        self.grid_nrows = self.FIELD_SIZE[1] / int(
            self.GRID_SIZE[0] * self.zoom_factor)
        self.grid_ncols = self.FIELD_SIZE[0] / int(
            self.GRID_SIZE[1] * self.zoom_factor)

    def get_agent_neighbors(self, agent, dist_range):
        neighbors = []
        for other in self.agents:
            if not agent.id == other.id:
                dist = agent.position.get_distance(other.position)
                if dist <= dist_range:
                    neighbors.append(other)

        return neighbors

    def draw_grid(self):
        for y in range(self.grid_nrows + 1):
            pygame.draw.line(
                self.screen, SIM_COLORS['light gray'],
                (self.field_rect.left, self.field_rect.top +
                 y * int(self.GRID_SIZE[1] * self.zoom_factor) - 1),
                (self.field_rect.right - 1, self.field_rect.top +
                 y * int(self.GRID_SIZE[1] * self.zoom_factor) - 1))

        for x in range(self.grid_ncols + 1):
            pygame.draw.line(
                self.screen, SIM_COLORS['light gray'],
                (self.field_rect.left +
                 x * int(self.GRID_SIZE[0] * self.zoom_factor) - 1,
                 self.field_rect.top),
                (self.field_rect.left +
                 x * int(self.GRID_SIZE[0] * self.zoom_factor) - 1,
                 self.field_rect.bottom - 1))

    def xy2coord(self, pos):
        """ Convert a (x, y) pair to a (nrow, ncol) coordinate
        """
        x, y = (pos[0] - self.field_rect.left, pos[1] - self.field_rect.top)
        return int(y) / self.GRID_SIZE[1], int(x) / self.GRID_SIZE[0]

    def coord2xy_mid(self, coord):
        """ Convert a (nrow, ncol) coordinate to a (x, y) pair,
            where x,y is the middle of the square at the coord
        """
        nrow, ncol = coord
        return (self.field_rect.left + ncol * self.GRID_SIZE[0] +
                self.GRID_SIZE[0] / 2, self.field_rect.top +
                nrow * self.GRID_SIZE[1] + self.GRID_SIZE[1] / 2)

    def draw_background(self):
        pygame.draw.rect(self.screen, SIM_COLORS['light gray'],
                         [0, 0, self.SCREEN_WIDTH, self.SCREEN_HEIGHT])

    def draw(self):
        self.draw_background()
        self.field_box.draw()

        if self.options['draw_grid']:
            self.draw_grid()

        for waypoint in self.waypoints:
            self.waypoints[waypoint].draw()

        for obstacle in self.obstacles:
            obstacle.draw()

        for agent in self.agents:
            agent.draw()

    def demo_populate_scene(self):
        # agents
        self.agents.add(
            Agent(agent_id=0,
                  screen=self.screen,
                  game=self,
                  agent_image=self.agent_image,
                  field=self.field_rect,
                  init_position=(3, 1),
                  init_direction=(1, 1),
                  max_speed=1.8,
                  waypoints=[self.waypoints['stop'], self.waypoints['start']]))
        self.agents.add(
            Agent(agent_id=1,
                  screen=self.screen,
                  game=self,
                  agent_image=self.agent_image,
                  field=self.field_rect,
                  init_position=(3, 5),
                  init_direction=(1, 1),
                  max_speed=1.8,
                  waypoints=[self.waypoints['start'], self.waypoints['stop']]))

        self.agents.add(
            Agent(agent_id=2,
                  screen=self.screen,
                  game=self,
                  agent_image=self.agent_image,
                  field=self.field_rect,
                  init_position=(2, 2),
                  init_direction=(1, 1),
                  max_speed=1.14,
                  waypoints=[self.waypoints['start'], self.waypoints['stop']]))

    def simulation_update(self):
        for agent in self.agents:
            agent.update(0.1)
            self.controller.drive_single_step(agent, delta_time=0.1)
            agent.draw()
        self.draw()

    def _process_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    self.paused = not self.paused
                elif event.key == pygame.K_g:
                    if pygame.key.get_mods() & pygame.KMOD_CTRL:
                        self.options[
                            'draw_grid'] = not self.options['draw_grid']
                elif event.key == pygame.K_PLUS or event.key == pygame.K_EQUALS:
                    #self.zoom_factor += 0.1
                    self.initialize_screen()
                    self.setup_grid()
                elif event.key == pygame.K_MINUS:
                    #self.zoom_factor -= 0.1
                    self.initialize_screen()
                    self.setup_grid()
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                pass
            elif event.type == VIDEORESIZE:
                self._old_screen = self.SCREEN_WIDTH, self.SCREEN_HEIGHT
                self.SCREEN_WIDTH, self.SCREEN_HEIGHT = event.dict['size']

                self.offset = self.SCREEN_WIDTH - self._old_screen[
                    0], self.SCREEN_HEIGHT - self._old_screen[1]
                #self.FIELD_LIMITS = self.FIELD_LIMITS[0]+self.offset[0], self.FIELD_LIMITS[1]+self.offset[1], \
                #                    self.FIELD_LIMITS[2], self.FIELD_LIMITS[3]

                #fx = (self.SCREEN_WIDTH / 2) - (self.FIELD_SIZE[0] / 2)
                #fy = (self.SCREEN_HEIGHT / 2) - (self.FIELD_SIZE[1] / 2)
                #self.FIELD_LIMITS = fx, fy, self.FIELD_LIMITS[2], self.FIELD_LIMITS[3]

                self.initialize_screen()
                self.setup_grid()

    _total_time = 0

    def run(self):
        # initialize modules
        pygame.init()

        while True:
            self.time_passed = self.clock.tick()

            # self._total_time += self.time_passed
            # if self._total_time < 1000:
            #     continue

            # handle any events
            self._process_events()

            if not self.paused:
                self.simulation_timer.update(self.time_passed)

            # update the game surface
            pygame.display.flip()

    def add_agents(self, agent_dict):
        for agent in agent_dict:
            dx, dy = float(agent['dx']), float(agent['dy'])
            x, y = float(agent['x']), float(agent['y'])
            num = int(agent['n'])
            a_type = int(agent['type'])

            # spawn an agent in a random direction and position(within dx, dy)
            direction = (randint(-1, 1), randint(-1, 1))
            position = random_position(x, y, dx, dy)
            waypoints = [awp['id'] for awp in agent['addwaypoint']]

            rd = 0.3

            for _ in xrange(num):
                self.agents.add(
                    Agent(agent_id=self._agent_count,
                          atype=a_type,
                          screen=self.screen,
                          game=self,
                          agent_image=self.agent_image,
                          field=self.field_rect,
                          init_position=position,
                          init_direction=direction,
                          max_speed=normalvariate(1.34, 0.26),
                          radius=rd,
                          waypoints=[self.waypoints[wp] for wp in waypoints]))
                self._agent_count += 1

        # we are done here
        # TODO - move the velocity stuff to a neat function
        # TODO - find a suitable fatness distribution

    def add_waypoints(self, waypoint_dict):
        for waypoint in waypoint_dict:
            w_id = waypoint['id']
            radius = float(waypoint['radius'])
            wtype = waypoint['type']
            x, y = float(waypoint['x']), float(waypoint['y'])
            self.waypoints.update({
                w_id:
                Waypoint(screen=self.screen,
                         wid=w_id,
                         wtype=wtype,
                         position=(x, y),
                         radius=radius)
            })

    def add_obstacles(self, obstacle_dict):
        for obstacle in obstacle_dict:
            o_id = obstacle['id']
            p1 = float(obstacle['p1'])
            p2 = float(obstacle['p2'])
            p3 = float(obstacle['p3'])
            p4 = float(obstacle['p4'])
            o_type = obstacle['type'].title()
            self.obstacles.append(
                Obstacle(screen=self.screen,
                         oid=o_id,
                         otype=o_type,
                         params=(p1, p2, p3, p4)))

    def quit(self):
        sys.exit()
Exemple #22
0
from utils import Box

from skimage.feature import hog

DATA_DIR = './images'
BOX_SIZE = Box(h=100, w=66).scale(2)

WINDOW_STEP = 20
SCALES = [0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2]

CV_FOLDS = 5


def features_extract_fn(img):
    return hog(img,
               orientations=16,
               pixels_per_cell=(32, 32),
               cells_per_block=(3, 3),
               block_norm='L2-Hys')
def get_region_boxes(img,
                     pad=10,
                     erode_iters=3,
                     min_box_width=50,
                     min_aspect=0.7,
                     min_box_width_rel=0.1,
                     approx_factor=0.06,
                     bin_thresh=5,
                     min_box_height=20,
                     debug=False):

    norm_img_src = preprocess_image(img, bin_thresh, False, debug)
    # pad to make clear edges
    src_img = cv2.copyMakeBorder(img,
                                 pad,
                                 pad,
                                 pad,
                                 pad,
                                 cv2.BORDER_CONSTANT,
                                 value=(0, ))
    if debug:
        cv2.imshow('orig image with black borders', src_img)  # andrey
        cv2.waitKey(0)
    norm_img = cv2.copyMakeBorder(norm_img_src,
                                  pad,
                                  pad,
                                  pad,
                                  pad,
                                  cv2.BORDER_CONSTANT,
                                  value=(0, ))
    if debug:
        cv2.imshow('bw image with black borders', norm_img)  # andrey
        cv2.waitKey(0)

    kernel = np.ones(shape=(3, 3))
    norm_img = cv2.erode(norm_img, kernel, iterations=erode_iters)
    if debug:
        cv2.imshow('bw image after erosion', norm_img)  # andrey
        cv2.waitKey(0)
    norm_img = cv2.dilate(norm_img, kernel, iterations=erode_iters)
    if debug:
        cv2.imshow('bw image after closing', norm_img)  # andrey
        cv2.waitKey(0)

    #kernel = np.ones(shape=(3, 11))
    #norm_img = cv2.erode(norm_img, kernel, iterations=erode_iters)
    #if debug:
    #    cv2.imshow('bw image after erosion', norm_img)  # andrey
    #    cv2.waitKey(0)
    #norm_img = cv2.dilate(norm_img, kernel, iterations=erode_iters)
    #if debug:
    #    cv2.imshow('bw image after closing', norm_img)  # andrey
    #    cv2.waitKey(0)


#
#kernel = np.ones(shape=(11, 3))
#norm_img = cv2.erode(norm_img, kernel, iterations=erode_iters)
#if debug:
#    cv2.imshow('bw image after erosion', norm_img)  # andrey
#    cv2.waitKey(0)
#norm_img = cv2.dilate(norm_img, kernel, iterations=erode_iters)
#if debug:
#    cv2.imshow('bw image after closing', norm_img)  # andrey
#    cv2.waitKey(0)

    regs = src_img.copy()
    cnts = cv2.findContours(norm_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    #cnts = cv2.findContours(norm_img, cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)

    # box_offset = 2 if erode_iters == 0 else 0
    box_offset = 0
    approx_factor_vec = np.array([0.02, 0.07])

    boxes = []
    for approx_factor in approx_factor_vec:
        for c in cnts[1]:
            p = cv2.arcLength(c, True)
            if p >= (min_box_width + min_box_height):
                approx = cv2.approxPolyDP(c, approx_factor * p, True)
                len_check = len(approx)
                if 4 <= len(approx) <= 8:
                    (x, y, w, h) = cv2.boundingRect(approx)
                    aspect = w / float(h)
                    hl_color = (255, 255, 0)
                    if aspect > min_aspect and w > min_box_width_rel * img.shape[
                            1] and w > min_box_width and h > min_box_height:
                        box = Box(
                            max(0, x - pad + box_offset),
                            max(0, y - pad + box_offset),
                            min(img.shape[1] - 1, x - pad + w - box_offset),
                            min(img.shape[0] - 1, y - pad + h - box_offset))
                        box.img_data = img[box.y1:box.y2, box.x1:box.x2]
                        boxes.append(box)
                        hl_color = (255, 0, 0)
                        cv2.rectangle(regs, (x, y), (x + w, y + h), hl_color,
                                      2)  # andrey
                        if debug:
                            cv2.imshow('image with bounding box',
                                       regs)  # andrey
                            cv2.waitKey(0)
                else:
                    cv2.drawContours(regs, [approx], 0, (0, 255, 0),
                                     2)  # andrey
                    if debug:
                        cv2.imshow('image with contours', regs)  # andrey
                        cv2.waitKey(0)
        #show(regs)

    return [src_img, norm_img, regs], boxes
def main(args):
    print(f'Source region extraction tool version {__version__}')
    a = ArgumentParser()
    a.add_argument(
        'input',
        help=
        'figure image file or image folder path or semicolon separated list of files or meta json lines file'
    )
    a.add_argument(
        '--demo',
        help='highlight source region on input images and save separately',
        default=False,
        action='store_true')
    a.add_argument('-out', help='source regions output dir', default='out')
    a.add_argument('-meta_out',
                   help='source regions output JSONL file',
                   default='regions.json')
    args = a.parse_args(args)
    demo_dir = args.out + '/demo'
    print('Building a list of source files...')
    if os.path.exists(demo_dir):
        shutil.rmtree(demo_dir, ignore_errors=True)
    if args.demo:
        os.makedirs(demo_dir + '/', exist_ok=True)
    if args.out:
        if os.path.exists(args.out):
            shutil.rmtree(args.out, ignore_errors=True)
        try:
            os.makedirs(args.out, exist_ok=True)
            if args.demo:
                os.makedirs(demo_dir + '/', exist_ok=True)  # andrey
        except:
            pass

    #if (args.input[-1]!='\\'):
    articles = get_articles(args.input)
    file_mapping = get_file_mapping(articles)
    #else:
    #    file_mapping = {}
    #    for (dirpath, dirnames, filenames) in os.walk(args.input):
    #        for fnam in filenames:
    #            file_mapping[args.input+fnam] = ArticleImage(id=1,chain_id='0',filename=args.input+fnam,title='',page=1,idx_on_page=1,regions=[])
    #        break
    if len(file_mapping) == 0:
        print('No files found in specified sources')
        exit(-1)
    reg_id = 0
    for i, filename in enumerate(file_mapping.keys()):
        src_img = cv2.imread(filename)
        if src_img is None:
            print(f'Error reading file, skipping: {filename}')
            continue
        cur_id = 1
        # extract with default settings
        boxes, boxes2, boxes3, boxes3a, boxes4 = [], [], [], [], []
        PerformDebug = False
        annotations, boxes = get_region_boxes(src_img,
                                              bin_thresh=5,
                                              debug=PerformDebug)
        cur_id = annotate_boxes(cur_id, boxes, (255, 0, 0))
        # preset 2 to extract bordered regions
        annotations2, boxes2 = get_region_boxes(src_img,
                                                erode_iters=0,
                                                bin_thresh=50,
                                                debug=PerformDebug)
        cur_id = annotate_boxes(cur_id, boxes2, (0, 255, 0))
        # preset 3 with another threshold
        annotations3, boxes3 = get_region_boxes(src_img,
                                                erode_iters=0,
                                                bin_thresh=100,
                                                debug=PerformDebug)
        cur_id = annotate_boxes(cur_id, boxes3, (0, 0, 255))
        # preset 3a with another threshold
        annotations3a, boxes3a = get_region_boxes(src_img,
                                                  erode_iters=0,
                                                  bin_thresh=150,
                                                  debug=PerformDebug)
        cur_id = annotate_boxes(cur_id, boxes3a, (0, 0, 255))
        # preset 4 - low threshold no morph
        annotations4, boxes4 = get_region_boxes(src_img,
                                                erode_iters=0,
                                                debug=PerformDebug)
        cur_id = annotate_boxes(cur_id, boxes4, (255, 0, 255))
        #boxes = filter_boxes(boxes + boxes2 + boxes3 + boxes3a + boxes4)
        all_boxes = boxes + boxes2 + boxes3 + boxes3a + boxes4
        # Check the number of all boxes
        if len(all_boxes) == 1:  # add the entire image as a box
            box = Box(0, 0, src_img.shape[1] - 1, src_img.shape[0] - 1)
            box.img_data = src_img
            all_boxes.append(box)
        PerformDebug = False
        updated_boxes = filter_boxes_updated(all_boxes,
                                             src_img,
                                             debug=PerformDebug)
        # boxes = boxes + boxes2 + boxes3
        if len(updated_boxes) == 0:
            print(
                f'Warning: {filename} no source regions detected, assuming single source region'
            )
            box = Box(0,
                      0,
                      src_img.shape[1] - 1,
                      src_img.shape[0] - 1,
                      id=cur_id)
            box.img_data = src_img
            updated_boxes.append(box)

        # remove borders from regions
        print(f'{filename} number of source regions: {len(updated_boxes)}')
        for b in updated_boxes:
            src_reg = b.img_data
            assert src_reg.shape[:2] == b.img_data.shape[:2]
            # crop borders on normalized reg (white/black borders)

            PerformDebug = False
            x1, x2, y1, y2 = crop_border(preprocess_image(b.img_data,
                                                          150,
                                                          otsu=True),
                                         src_reg,
                                         debug=PerformDebug)
            sr = src_reg[y1:y2, x1:x2]
            # sr = src_img[b.y1:b.y2, b.x1:b.x2]
            reg_path = os.path.join(
                args.out,
                '.'.join(os.path.basename(filename).split('.')[:-1]) + '_' +
                'R' + str(b.id) + '.png')
            article_image = file_mapping[filename]
            article_image.regions.append(
                Region(id=reg_id,
                       chain_id=article_image.chain_id,
                       filename=os.path.abspath(reg_path),
                       box=(b.x1, b.y1, b.x2, b.y2),
                       matches=[],
                       title=os.path.basename(reg_path)))
            reg_id += 1
            #cv2.imshow('subimage', sr)  # andrey
            #cv2.waitKey(0)
            cv2.imwrite(reg_path, sr)

        if args.demo:
            ref = src_img.copy()
            for b in updated_boxes:
                cv2.rectangle(ref, (b.x1, b.y1), (b.x2, b.y2),
                              color=(b.meta if b.meta is not None else
                                     (255, 128, 100)),
                              thickness=2)
            ResultImagePathToSave = os.path.join(
                demo_dir,
                '.'.join(os.path.basename(filename).split('.')[:-1]) + '.png')
            cv2.imwrite(ResultImagePathToSave, ref)
            cv2.imshow('image with bounding box', ref)  # andrey
            cv2.waitKey(0)
        progress.report_progress(i + 1, len(file_mapping),
                                 'Extracting regions')
        #show(ref_imgs=annotations, title=f'{filename}')
        #show(ref_imgs=annotations2, title=f'{filename} pass 2')
        #show(ref_imgs=annotations3, title=f'{filename} pass 3')
        #show(ref_imgs=annotations4, title=f'{filename} pass 4')
    with open(args.meta_out, mode='w') as meta_file:
        for a in articles:
            meta_file.write(a.toJSON() + os.linesep)
Exemple #25
0
        cv2.rectangle(image, (box[0],box[1]), (box[2], box[3]), (255,0,0), 1)
    color = (0,255,0) if text == "Live" else (0, 0, 255)
    cv2.putText(image, text, (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 2.0, color, lineType=cv2.LINE_AA) 

def crop_boxes(image, box):
    img = image[box[1]:box[3], box[0]:box[2]]
    return img

while True:
    ret1, frame1 = cap1.read()
    ret2, frame2 = cap2.read()
    if ret1 and ret2:
        boxes1 = face_detector.DetectFaces(frame1)
        boxes2 = face_detector.DetectFaces(frame2)
        if boxes1 and boxes2:
            exp_box1 = Box(boxes1[0][0], boxes1[0][1], boxes1[0][2]-boxes1[0][0], boxes1[0][3]-boxes1[0][1]).ExpandBox(1.5)
            exp_box2 = Box(boxes2[0][0], boxes2[0][1], boxes2[0][2]-boxes2[0][0], boxes2[0][3]-boxes2[0][1]).ExpandBox(1.5)
            sqr_box1 = exp_box1.SquareBox(1)
            sqr_box2 = exp_box2.SquareBox(1)
            crop1,_,_,_,_ = SmartCrop(frame1, sqr_box1)
            crop2,_,_,_,_ = SmartCrop(frame2, sqr_box2)

            crop1 = cv2.cvtColor(crop1, cv2.COLOR_BGR2GRAY)
            crop2 = cv2.cvtColor(crop2, cv2.COLOR_BGR2GRAY)
            crop1 = Resize(crop1, dst_size, dst_size)
            crop2 = Resize(crop2, dst_size, dst_size)

            resize_coef1 = dst_size / sqr_box1.width
            resize_coef2 = dst_size / sqr_box2.width
            resized_width = int(max(resize_coef1 * exp_box1.width, resize_coef2 * exp_box2.width))
    def __call__(self, data, label, gt):
        #-----------------------------------------------------------------------
        # Check whether to sample or not
        #-----------------------------------------------------------------------
        if not self.sample:
            return data, label, gt

        #-----------------------------------------------------------------------
        # Retry sampling a couple of times
        #-----------------------------------------------------------------------
        source_boxes = anchors2array(
            gt.boxes, gt.imgsize)  # get abs value(xmin,xmax,ymin,ymax)
        box = None
        box_arr = None
        for _ in range(self.max_trials):
            #-------------------------------------------------------------------
            # Sample a bounding box
            #-------------------------------------------------------------------
            # min_scale=0.3, max_scale=1.0,
            # min_aspect_ratio=0.5, max_aspect_ratio=2.0,
            scale = random.uniform(self.min_scale, self.max_scale)
            aspect_ratio = random.uniform(self.min_aspect_ratio,
                                          self.max_aspect_ratio)

            # make sure width and height will not be larger than 1
            aspect_ratio = max(aspect_ratio, scale**2)
            aspect_ratio = min(aspect_ratio, 1 / (scale**2))

            width = scale * sqrt(aspect_ratio)
            height = scale / sqrt(aspect_ratio)
            cx = 0.5 * width + random.uniform(0, 1 - width)
            cy = 0.5 * height + random.uniform(0, 1 - height)
            center = Point(cx, cy)
            size = Size(width, height)

            #-------------------------------------------------------------------
            # Check if the box satisfies the jaccard overlap constraint
            #-------------------------------------------------------------------
            box_arr = np.array(prop2abs(center, size, gt.imgsize))
            overlap = compute_overlap(box_arr, source_boxes, 0)
            if overlap.best and overlap.best.score >= self.min_jaccard_overlap:
                box = Box(None, None, center, size)
                break

        if box is None:
            return None

        #-----------------------------------------------------------------------
        # Crop the box and adjust the ground truth
        #-----------------------------------------------------------------------
        new_size = Size(box_arr[1] - box_arr[0], box_arr[3] - box_arr[2])
        w_off = -box_arr[0]
        h_off = -box_arr[2]

        data = data.crop(
            (box_arr[0], box_arr[2], box_arr[1], box_arr[3])
        )  # gt와 gt근처의 가상의 anchor를 잡은뒤, iou 0.1, 0.3, 0.5, 0.7, 0.9 이상이면 그 가상의 anchor부분을 crop하고 gt 좌표도 같이 변경
        # 즉 일부로 gt와 iou 연관있는 그림부분을 crop함
        gt = transform_gt(gt, new_size, h_off, w_off)

        return data, label, gt  # change gt and image_size
Exemple #27
0
class Simulation(object):
    """ 
    The main simulation entry point 
    """

    # basic defaults
    SCREEN_WIDTH, SCREEN_HEIGHT = 700, 700
    GRID_SIZE = 20, 20
    FIELD_SIZE = 500, 500
    FIELD_LIMITS = 0, 0, 600, 600
    field_bgcolor = SIM_COLORS['white']

    def __init__(self, params=None):
        pygame.init()

        if params is not None:
            self.SCREEN_HEIGHT, self.SCREEN_WIDTH = int(float(params['display']['height']) * SCALE), \
                                                    int(float(params['display']['width']) * SCALE)
            self.FIELD_LIMITS = int(float(params['field_top_left_x']) * SCALE), \
                                int(float(params['field_top_left_y']) * SCALE), \
                                int(float(params['field_bottom_right_x']) * SCALE), \
                                int(float(params['field_bottom_right_y']) * SCALE)
            self.FIELD_SIZE = self.FIELD_LIMITS[2] - self.FIELD_LIMITS[0], self.FIELD_LIMITS[3] - self.FIELD_LIMITS[1]
            self.GRID_SIZE = int(float(params['cell']['width']) * SCALE), int(float(params['cell']['height']) * SCALE)

        # zoom and centering
        self.offset = 0, 0
        self.zoom_factor = 1.0
        self._old_screen = self.SCREEN_WIDTH, self.SCREEN_HEIGHT

        # setup the screen and the box field of play
        self.initialize_screen()

        # agents
        self.agents = pygame.sprite.Group()
        self.agent_image = pygame.image.load('assets/blueagent.bmp').convert_alpha()
        self.controller = SocialForceController(self)
        # self.controller = RandomController(self)

        # time related items
        self.clock = pygame.time.Clock()
        self.paused = False
        self.simulation_timer = Timer(10, self.simulation_update)

        # create the grid
        self.setup_grid()

        # additional options (remove this)
        self.options = dict(draw_grid=True)

        # setup objects (waypoints, obstacles)
        self.waypoints = dict()
        self.obstacles = []
        self._agent_count = 0

        # initialize the time
        self.time_passed = 0


    def initialize_screen(self):
        self.screen = pygame.display.set_mode((self.SCREEN_WIDTH, self.SCREEN_HEIGHT),
                                              HWSURFACE | DOUBLEBUF | RESIZABLE, 32)
        self.field_rect_outer = Rect(self.FIELD_LIMITS[0],
                                     self.FIELD_LIMITS[1],
                                     int(self.FIELD_SIZE[0]*self.zoom_factor),
                                     int(self.FIELD_SIZE[1]*self.zoom_factor))

        self.field_box = Box(surface=self.screen,
            rect=self.field_rect_outer, 
            background_color=self.field_bgcolor
        )

        self.field_rect = self.field_box.get_internal_rect()

    def setup_grid(self):
        self.grid_nrows = self.FIELD_SIZE[1] / int(self.GRID_SIZE[0]*self.zoom_factor)
        self.grid_ncols = self.FIELD_SIZE[0] / int(self.GRID_SIZE[1]*self.zoom_factor)

    def get_agent_neighbors(self, agent, dist_range):
        neighbors = []
        for other in self.agents:
            if not agent.id == other.id:
                dist = agent.position.get_distance(other.position)
                if dist <= dist_range:
                    neighbors.append(other)

        return neighbors

    def draw_grid(self):
        for y in range(self.grid_nrows + 1):
            pygame.draw.line(
                self.screen,
                SIM_COLORS['light gray'],
                (self.field_rect.left, self.field_rect.top + y * int(self.GRID_SIZE[1]*self.zoom_factor) - 1),
                (self.field_rect.right - 1, self.field_rect.top + y * int(self.GRID_SIZE[1]*self.zoom_factor) - 1))
        
        for x in range(self.grid_ncols + 1):
            pygame.draw.line(
                self.screen,
                SIM_COLORS['light gray'],
                (self.field_rect.left + x * int(self.GRID_SIZE[0]*self.zoom_factor) - 1, self.field_rect.top),
                (self.field_rect.left + x * int(self.GRID_SIZE[0]*self.zoom_factor) - 1, self.field_rect.bottom - 1))

    def xy2coord(self, pos):
        """ Convert a (x, y) pair to a (nrow, ncol) coordinate
        """
        x, y = (pos[0] - self.field_rect.left, pos[1] - self.field_rect.top)
        return int(y) / self.GRID_SIZE[1], int(x) / self.GRID_SIZE[0]
    
    def coord2xy_mid(self, coord):
        """ Convert a (nrow, ncol) coordinate to a (x, y) pair,
            where x,y is the middle of the square at the coord
        """
        nrow, ncol = coord
        return (
            self.field_rect.left + ncol * self.GRID_SIZE[0] + self.GRID_SIZE[0] / 2,
            self.field_rect.top + nrow * self.GRID_SIZE[1] + self.GRID_SIZE[1] / 2)

    def draw_background(self):
        pygame.draw.rect(self.screen, SIM_COLORS['light gray'], [0, 0, self.SCREEN_WIDTH, self.SCREEN_HEIGHT])

    def draw(self):
        self.draw_background()
        self.field_box.draw()
        
        if self.options['draw_grid']:
            self.draw_grid()
                
        for waypoint in self.waypoints:
            self.waypoints[waypoint].draw()

        for obstacle in self.obstacles:
            obstacle.draw()

        for agent in self.agents:
            agent.draw()

    def demo_populate_scene(self):
        # agents
        self.agents.add(
                Agent(  agent_id = 0,
                    screen = self.screen,
                    game = self,
                    agent_image = self.agent_image,
                    field = self.field_rect,
                    init_position = ( 3, 1),
                    init_direction = (1, 1),
                    max_speed = 1.8,
                    waypoints = [self.waypoints['stop'], self.waypoints['start']]
                    )
            )
        self.agents.add(
                Agent(  agent_id = 1,
                    screen = self.screen,
                    game = self,
                    agent_image = self.agent_image,
                    field = self.field_rect,
                    init_position = ( 3, 5),
                    init_direction = (1, 1),
                    max_speed = 1.8,
                    waypoints = [self.waypoints['start'], self.waypoints['stop']]
                    )
            )

        self.agents.add(
                Agent(  agent_id = 2,
                    screen = self.screen,
                    game = self,
                    agent_image = self.agent_image,
                    field = self.field_rect,
                    init_position = ( 2, 2),
                    init_direction = (1, 1),
                    max_speed = 1.14,
                    waypoints = [self.waypoints['start'], self.waypoints['stop']]
                    )
            )

    def simulation_update(self):
        for agent in self.agents:
            agent.update(0.1)
            self.controller.drive_single_step(agent, delta_time=0.1)
            agent.draw()
        self.draw()

    def _process_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    self.paused = not self.paused
                elif event.key == pygame.K_g:
                    if pygame.key.get_mods() & pygame.KMOD_CTRL:
                        self.options['draw_grid'] = not self.options['draw_grid']
                elif event.key == pygame.K_PLUS or event.key == pygame.K_EQUALS:
                    #self.zoom_factor += 0.1
                    self.initialize_screen()
                    self.setup_grid()
                elif event.key == pygame.K_MINUS:
                    #self.zoom_factor -= 0.1
                    self.initialize_screen()
                    self.setup_grid()
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                pass
            elif event.type == VIDEORESIZE:
                self._old_screen = self.SCREEN_WIDTH, self.SCREEN_HEIGHT
                self.SCREEN_WIDTH, self.SCREEN_HEIGHT = event.dict['size']

                self.offset = self.SCREEN_WIDTH - self._old_screen[0], self.SCREEN_HEIGHT - self._old_screen[1]
                #self.FIELD_LIMITS = self.FIELD_LIMITS[0]+self.offset[0], self.FIELD_LIMITS[1]+self.offset[1], \
                #                    self.FIELD_LIMITS[2], self.FIELD_LIMITS[3]

                #fx = (self.SCREEN_WIDTH / 2) - (self.FIELD_SIZE[0] / 2)
                #fy = (self.SCREEN_HEIGHT / 2) - (self.FIELD_SIZE[1] / 2)
                #self.FIELD_LIMITS = fx, fy, self.FIELD_LIMITS[2], self.FIELD_LIMITS[3]

                self.initialize_screen()
                self.setup_grid()

    _total_time = 0

    def run(self):
        # initialize modules
        pygame.init()

        while True:
            self.time_passed = self.clock.tick()

            # self._total_time += self.time_passed
            # if self._total_time < 1000:
            #     continue
            
            # handle any events
            self._process_events()
            
            if not self.paused:     
                self.simulation_timer.update(self.time_passed)
            
            # update the game surface
            pygame.display.flip()

    def add_agents(self, agent_dict):
        for agent in agent_dict:
            dx, dy = float(agent['dx']), float(agent['dy'])
            x, y = float(agent['x']), float(agent['y'])
            num = int(agent['n'])
            a_type = int(agent['type'])

            # spawn an agent in a random direction and position(within dx, dy)
            direction = (randint(-1, 1), randint(-1, 1))
            position = random_position(x, y, dx, dy)
            waypoints = [awp['id'] for awp in agent['addwaypoint']]

            rd = 0.3

            for _ in xrange(num):
                self.agents.add(Agent(
                        agent_id = self._agent_count,
                        atype = a_type,
                        screen = self.screen,
                        game = self,
                        agent_image = self.agent_image,
                        field = self.field_rect,
                        init_position = position,
                        init_direction = direction,
                        max_speed = normalvariate(1.34, 0.26),
                        radius = rd,
                        waypoints = [self.waypoints[wp] for wp in waypoints]
                    ))
                self._agent_count += 1

        # we are done here
        # TODO - move the velocity stuff to a neat function
        # TODO - find a suitable fatness distribution
    
    def add_waypoints(self, waypoint_dict):
        for waypoint in waypoint_dict:
            w_id = waypoint['id']
            radius = float(waypoint['radius'])
            wtype = waypoint['type']
            x, y = float(waypoint['x']), float(waypoint['y'])
            self.waypoints.update({w_id : Waypoint(screen=self.screen, wid=w_id, wtype=wtype, position=(x, y), radius=radius)})

    def add_obstacles(self, obstacle_dict):
        for obstacle in obstacle_dict:
            o_id = obstacle['id']
            p1 = float(obstacle['p1'])
            p2 = float(obstacle['p2'])
            p3 = float(obstacle['p3'])
            p4 = float(obstacle['p4'])
            o_type = obstacle['type'].title()
            self.obstacles.append(Obstacle(screen=self.screen, oid=o_id, otype=o_type, params=(p1, p2, p3, p4)))

    def quit(self):
        sys.exit()