Извлечь прямоугольные коробки с прокладкой - PullRequest
0 голосов
/ 14 марта 2019

Я пытаюсь извлечь значения из двухмерного тензора в нескольких прямоугольных областях. Я хочу обрезать прямоугольные области, устанавливая все значения за пределами поля на ноль.

Например, из изображения 9 x 9 я хочу получить два отдельных изображения со значениями в двух прямоугольных красных прямоугольниках, а остальные значения установить в ноль. Есть ли удобный способ сделать это с помощью нарезки тензорного потока? extract values inside rectangles

Один из способов подойти к этому - определить массив масок, равный 1 внутри поля и 0 снаружи, и умножить его на входной массив. Но это требует циклического изменения количества блоков, каждый раз меняя, какие значения маски установлены на 0. Существует ли более быстрый и эффективный способ сделать это без использования циклов for? Существует ли эквивалент функции обрезки и замены в тензорном потоке? Вот код, который у меня есть с циклом for. Ценю любой вклад по этому вопросу. Спасибо

import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.patches as patches

tf.reset_default_graph()

size = 9 # size of input image
num_boxes = 2 # number of rectangular boxes


def get_cutout(X, bboxs):
    """Returns copies of X with values only inside bboxs"""
    out = []
    for i in range(num_boxes):
        bbox = bboxs[i] # get rectangular box coordinates
        Y = tf.Variable(np.zeros((size, size)), dtype=tf.float32) # define temporary mask
        # set values of mask inside box to 1
        t = [Y[bbox[0]:bbox[2], bbox[2]:bbox[3]].assign(
            tf.ones((bbox[2]-bbox[0], bbox[3]-bbox[2])))]
        with tf.control_dependencies(t):
            mask = tf.identity(Y) 
        out.append(X * mask) # get values inside rectangular box
    return out, X

#define a 9x9 input image X and convert to tensor
in_x = np.eye(size)
in_x[0:3]=np.random.rand(3,9)
X = tf.constant(in_x , dtype=tf.float32)

bboxs = tf.placeholder(tf.int32, [None, 4]) # placeholder for rectangular box

X_outs = get_cutout(X, bboxs)

# coordintes of box ((bottom left x, bottom left y, top right x, top right y))
in_bbox = [[1,3,3,6], [4,3,7,8]] 
feed_dict = {bboxs: in_bbox}

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    x_out= sess.run(X_outs, feed_dict=feed_dict)

# plot results
vmin = np.min(x_out[2])
vmax = np.max(x_out[2])
fig, ax = plt.subplots(nrows=1, ncols=1+len(in_bbox),figsize=(10,2))
im = ax[0].imshow(x_out[2], vmin=vmin, vmax=vmax, origin='lower')
plt.colorbar(im, ax=ax[0])
ax[0].set_title("input X")
for i, bbox in enumerate(in_bbox):
    bottom_left = (bbox[2]-0.5, bbox[0]-0.5)
    width = bbox[3]-bbox[2]
    height = bbox[2]- bbox[0]
    rect = patches.Rectangle(bottom_left, width, height,
                             linewidth=1,edgecolor='r',facecolor='none')
    ax[0].add_patch(rect)
    ax[i+1].set_title("extract values in box {}".format(i+1))
    im = ax[i + 1].imshow(x_out[0][i], vmin=vmin, vmax=vmax, origin='lower')
    plt.colorbar(im,ax=ax[i+1])

Ответы [ 2 ]

0 голосов
/ 15 марта 2019

Спасибо за эту действительно замечательную функцию @edkevekeh.Мне пришлось немного изменить его, чтобы заставить его делать то, что я хочу.Во-первых, я не мог перебирать блоки, которые являются объектами Tensor.Кроме того, размер обрезки определяется коробкой и не всегда 3х3.Кроме того, tf.boolean_mask возвращает обрезку, но я хочу сохранить обрезку, но заменить ее за пределами нуля. Поэтому я заменил tf.boolean_mask умножением.

В моем случае num_boxes может быть большим,поэтому я хотел знать, существует ли более эффективный способ, чем цикл for, угадайте, нет.Моя модифицированная версия решения @ edkevekeh, если кому-то еще это нужно.

def extract_with_padding(image, boxes):
    """
    boxes: tensor of shape [num_boxes, 4]. 
          boxes are the coordinates of the extracted part
          box is an array [y1, x1, y2, x2] 
          where [y1, x1] (respectively [y2, x2]) are the coordinates 
          of the top left (respectively bottom right ) part of the image
    image: tensor containing the initial image
    """
    extracted = []
    shape = tf.shape(image)
    for i in range(boxes.shape[0]):
        b = boxes[i]
        crop = tf.ones([b[2] - b[0], b[3] - b[1]])
        mask = tf.pad(crop, [[b[0], shape[0] - b[2]], [b[1] , shape[1] - b[3]]])
        extracted.append(image*mask)
    return extracted 
0 голосов
/ 14 марта 2019

Маска может быть создана с помощью tf.pad.

 crop = tf.ones([3, 3])
 # "before_axis_x" how many padding will be added before cropping zone over the axis x
 # "after_axis_x" how many padding will be added after cropping zone over the axis x
 mask = tf.pad(crop, [[before_axis_0, after_axis_0], [before_axis_1, after_axis_1]]

 tf.mask(image, mask) # creates the extracted image

Чтобы иметь то же поведение, что и tf.image.crop_and_resize, вот функция, которая будет принимать массив ящиков и будет возвращать массив извлеченных изображений с отступами.

def extract_with_padding(image, boxes):
  """
   boxes: tensor of shape [num_boxes, 4]. 
          boxes are the coordinates of the extracted part
          box is an array [y1, x1, y2, x2] 
          where [y1, x1] (respectively [y2, x2]) are the coordinates 
          of the top left (respectively bottom right ) part of the image
   image: tensor containing the initial image
  """
  extracted = []
  shape = tf.shape(image)
  for b in boxes:
    crop = tf.ones([3, 3])

    mask = tf.pad(crop, [[b[0], shape[0] - b[2]], [b[1] , shape[1] - b[3]]])
    extracted.append(tf.boolean_mask(image, mask))

  return extracted
...