|
10 | 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
11 | 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | 12 | # See the License for the specific language governing permissions and |
13 | | -# limitations under the License.grep -q Copyright $i |
| 13 | +# limitations under the License. |
14 | 14 | import tensorflow as tf |
15 | 15 |
|
| 16 | +from keras_cv.utils import bbox |
16 | 17 |
|
17 | | -def fill_rectangle( |
18 | | - image, center_width, center_height, half_width, half_height, fill=None |
19 | | -): |
20 | | - """Fill a rectangle in a given image using the value provided in replace. |
| 18 | + |
| 19 | +def rectangle_masks(mask_shape, corners): |
| 20 | + """Computes positional masks of rectangles in images |
21 | 21 |
|
22 | 22 | Args: |
23 | | - image: the starting image to fill the rectangle on. |
24 | | - center_width: the X center of the rectangle to fill |
25 | | - center_height: the Y center of the rectangle to fill |
26 | | - half_width: 1/2 the width of the resulting rectangle |
27 | | - half_height: 1/2 the height of the resulting rectangle |
28 | | - fill: A tensor with same shape as image. Values at rectangle |
29 | | - position are used as fill. |
| 23 | + mask_shape: shape of the masks as [batch_size, height, width]. |
| 24 | + corners: rectangle coordinates in corners format. |
| 25 | +
|
30 | 26 | Returns: |
31 | | - image: the modified image with the chosen rectangle filled. |
| 27 | + boolean masks with True at rectangle positions. |
32 | 28 | """ |
33 | | - image_shape = tf.shape(image) |
34 | | - image_height = image_shape[0] |
35 | | - image_width = image_shape[1] |
36 | | - |
37 | | - lower_pad = tf.maximum(0, center_height - half_height) |
38 | | - upper_pad = tf.maximum(0, image_height - center_height - half_height) |
39 | | - left_pad = tf.maximum(0, center_width - half_width) |
40 | | - right_pad = tf.maximum(0, image_width - center_width - half_width) |
41 | | - |
42 | | - shape = [ |
43 | | - image_height - (lower_pad + upper_pad), |
44 | | - image_width - (left_pad + right_pad), |
45 | | - ] |
46 | | - padding_dims = [[lower_pad, upper_pad], [left_pad, right_pad]] |
47 | | - mask = tf.pad(tf.zeros(shape, dtype=image.dtype), padding_dims, constant_values=1) |
48 | | - mask = tf.expand_dims(mask, -1) |
49 | | - |
50 | | - image = tf.where(tf.equal(mask, 0), fill, image) |
51 | | - return image |
| 29 | + # add broadcasting axes |
| 30 | + corners = corners[..., tf.newaxis, tf.newaxis] |
| 31 | + |
| 32 | + # split coordinates |
| 33 | + x0 = corners[:, 0] |
| 34 | + y0 = corners[:, 1] |
| 35 | + x1 = corners[:, 2] |
| 36 | + y1 = corners[:, 3] |
| 37 | + |
| 38 | + # repeat height and width |
| 39 | + batch_size, height, width = mask_shape |
| 40 | + x0_rep = tf.repeat(x0, height, axis=1) |
| 41 | + y0_rep = tf.repeat(y0, width, axis=2) |
| 42 | + x1_rep = tf.repeat(x1, height, axis=1) |
| 43 | + y1_rep = tf.repeat(y1, width, axis=2) |
| 44 | + |
| 45 | + # range grid |
| 46 | + range_row = tf.range(0, height, dtype=corners.dtype) |
| 47 | + range_col = tf.range(0, width, dtype=corners.dtype) |
| 48 | + range_row = tf.repeat(range_row[tf.newaxis, :, tf.newaxis], batch_size, 0) |
| 49 | + range_col = tf.repeat(range_col[tf.newaxis, tf.newaxis, :], batch_size, 0) |
| 50 | + |
| 51 | + # boolean masks |
| 52 | + mask_x0 = tf.less_equal(x0_rep, range_col) |
| 53 | + mask_y0 = tf.less_equal(y0_rep, range_row) |
| 54 | + mask_x1 = tf.less(range_col, x1_rep) |
| 55 | + mask_y1 = tf.less(range_row, y1_rep) |
| 56 | + |
| 57 | + masks = mask_x0 & mask_y0 & mask_x1 & mask_y1 |
| 58 | + |
| 59 | + return masks |
| 60 | + |
| 61 | + |
| 62 | +def fill_rectangle(images, center_x, center_y, width, height, fill): |
| 63 | + """Fill rectangles with fill value into images. |
| 64 | +
|
| 65 | + Args: |
| 66 | + images: Tensor of images to fill rectangles into. |
| 67 | + center_x: Tensor of positions of the rectangle centers on the x-axis. |
| 68 | + center_y: Tensor f positions of the rectangle centers on the y-axis. |
| 69 | + width: Tensor of widths of the rectangles |
| 70 | + height: Tensor of heights of the rectangles |
| 71 | + fill: Tensor with same shape as images to get rectangle fill from. |
| 72 | + Returns: |
| 73 | + images with filled rectangles. |
| 74 | + """ |
| 75 | + images_shape = tf.shape(images) |
| 76 | + batch_size = images_shape[0] |
| 77 | + images_height = images_shape[1] |
| 78 | + images_width = images_shape[2] |
| 79 | + |
| 80 | + xywh = tf.stack([center_x, center_y, width, height], axis=1) |
| 81 | + xywh = tf.cast(xywh, tf.float32) |
| 82 | + corners = bbox.xywh_to_corners(xywh) |
| 83 | + |
| 84 | + masks_shape = (batch_size, images_height, images_width) |
| 85 | + is_patch_mask = rectangle_masks(masks_shape, corners) |
| 86 | + is_patch_mask = tf.expand_dims(is_patch_mask, -1) |
| 87 | + |
| 88 | + images = tf.where(tf.equal(is_patch_mask, True), fill, images) |
| 89 | + return images |
0 commit comments