//  [python]
def worker(gpu_id, images, det_net, result_queue):
    os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id)
    # 1. preprocess img
    img_plac = tf.placeholder(dtype=tf.uint8, shape=[None, None, 3])  # is RGB. not BGR
    img_batch = tf.cast(img_plac, tf.float32)

    if cfgs.NET_NAME in ['resnet152_v1d', 'resnet101_v1d', 'resnet50_v1d']:
        img_batch = (img_batch / 255 - tf.constant(cfgs.PIXEL_MEAN_)) / tf.constant(cfgs.PIXEL_STD)
    else:
        img_batch = img_batch - tf.constant(cfgs.PIXEL_MEAN)

    img_batch = tf.expand_dims(img_batch, axis=0)

    detection_boxes, detection_scores, detection_category = det_net.build_whole_detection_network(
        input_img_batch=img_batch,
        gtboxes_batch_h=None,
        gtboxes_batch_r=None,
        gpu_id=0)

    init_op = tf.group(
        tf.global_variables_initializer(),
        tf.local_variables_initializer()
    )

    restorer, restore_ckpt = det_net.get_restorer()

    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True

    with tf.Session(config=config) as sess:
        sess.run(init_op)
        if not restorer is None:
            restorer.restore(sess, restore_ckpt)
            print('restore model %d ...' % gpu_id)
        for a_img in images:
            raw_img = cv2.imread(a_img)
            raw_h, raw_w = raw_img.shape[0], raw_img.shape[1]

            det_boxes_r_all, det_scores_r_all, det_category_r_all = [], [], []

            img_short_side_len_list = cfgs.IMG_SHORT_SIDE_LEN if isinstance(cfgs.IMG_SHORT_SIDE_LEN, list) else [
                cfgs.IMG_SHORT_SIDE_LEN]
            img_short_side_len_list = [img_short_side_len_list[0]] if not args.multi_scale else img_short_side_len_list

            for short_size in img_short_side_len_list:
                max_len = cfgs.IMG_MAX_LENGTH
                if raw_h < raw_w:
                    new_h, new_w = short_size, min(int(short_size * float(raw_w) / raw_h), max_len)
                else:
                    new_h, new_w = min(int(short_size * float(raw_h) / raw_w), max_len), short_size
                img_resize = cv2.resize(raw_img, (new_w, new_h))

                resized_img, detected_boxes, detected_scores, detected_categories = \
                    sess.run(
                        [img_batch, detection_boxes, detection_scores, detection_category],
                        feed_dict={img_plac: img_resize[:, :, ::-1]}
                    )

                detected_indices = detected_scores >= cfgs.VIS_SCORE
                detected_scores = detected_scores[detected_indices]
                detected_boxes = detected_boxes[detected_indices]
                detected_categories = detected_categories[detected_indices]

                if detected_boxes.shape[0] == 0:
                    continue
                resized_h, resized_w = resized_img.shape[1], resized_img.shape[2]
                detected_boxes = forward_convert(detected_boxes, False)
                detected_boxes[:, 0::2] *= (raw_w / resized_w)
                detected_boxes[:, 1::2] *= (raw_h / resized_h)
                # detected_boxes = backward_convert(detected_boxes, False)

                det_boxes_r_all.extend(detected_boxes)
                det_scores_r_all.extend(detected_scores)
                det_category_r_all.extend(detected_categories)
            det_boxes_r_all = np.array(det_boxes_r_all)
            det_scores_r_all = np.array(det_scores_r_all)
            det_category_r_all = np.array(det_category_r_all)

            box_res_rotate_ = []
            label_res_rotate_ = []
            score_res_rotate_ = []

            if det_scores_r_all.shape[0] != 0:
                for sub_class in range(1, cfgs.CLASS_NUM + 1):
                    index = np.where(det_category_r_all == sub_class)[0]
                    if len(index) == 0:
                        continue
                    tmp_boxes_r = det_boxes_r_all[index]
                    tmp_label_r = det_category_r_all[index]
                    tmp_score_r = det_scores_r_all[index]

                    tmp_boxes_r_ = backward_convert(tmp_boxes_r, False)

                    try:
                        inx = nms_rotate.nms_rotate_cpu(boxes=np.array(tmp_boxes_r_),
                                                        scores=np.array(tmp_score_r),
                                                        iou_threshold=cfgs.NMS_IOU_THRESHOLD,
                                                        max_output_size=5000)
                    except:
                        tmp_boxes_r_ = np.array(tmp_boxes_r_)
                        tmp = np.zeros([tmp_boxes_r_.shape[0], tmp_boxes_r_.shape[1] + 1])
                        tmp[:, 0:-1] = tmp_boxes_r_
                        tmp[:, -1] = np.array(tmp_score_r)
                        # Note: the IoU of two same rectangles is 0, which is calculated by rotate_gpu_nms
                        jitter = np.zeros([tmp_boxes_r_.shape[0], tmp_boxes_r_.shape[1] + 1])
                        jitter[:, 0] += np.random.rand(tmp_boxes_r_.shape[0], ) / 1000
                        inx = rotate_gpu_nms(np.array(tmp, np.float32) + np.array(jitter, np.float32),
                                             float(cfgs.NMS_IOU_THRESHOLD), 0)

                    box_res_rotate_.extend(np.array(tmp_boxes_r)[inx])
                    score_res_rotate_.extend(np.array(tmp_score_r)[inx])
                    label_res_rotate_.extend(np.array(tmp_label_r)[inx])

            box_res_rotate_ = np.array(box_res_rotate_)
            score_res_rotate_ = np.array(score_res_rotate_)
            label_res_rotate_ = np.array(label_res_rotate_)

            result_dict = {'scales': [1, 1], 'boxes': box_res_rotate_,
                           'scores': score_res_rotate_, 'labels': label_res_rotate_,
                           'image_id': a_img}
            result_queue.put_nowait(result_dict)