1c8b59c046895fa5b6d79f73e0b5817330fcfbfc1A. Unique TensorFlower/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
3f3a77378b4c056e76691c5eba350a022c11e00d4Martin WickeLicensed under the Apache License, Version 2.0 (the "License");
4f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickeyou may not use this file except in compliance with the License.
5f3a77378b4c056e76691c5eba350a022c11e00d4Martin WickeYou may obtain a copy of the License at
6f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
7f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    http://www.apache.org/licenses/LICENSE-2.0
8f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
9f3a77378b4c056e76691c5eba350a022c11e00d4Martin WickeUnless required by applicable law or agreed to in writing, software
10f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickedistributed under the License is distributed on an "AS IS" BASIS,
11f3a77378b4c056e76691c5eba350a022c11e00d4Martin WickeWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f3a77378b4c056e76691c5eba350a022c11e00d4Martin WickeSee the License for the specific language governing permissions and
13f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickelimitations under the License.
14f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke==============================================================================*/
15f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// See docs in ../ops/image_ops.cc.
16fc53648e0c0f5110bfab75a02b9dc75260b913d3A. Unique TensorFlower#include <math.h>
17f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke#include "tensorflow/core/framework/op_kernel.h"
18f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke#include "tensorflow/core/framework/register_types.h"
19f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke#include "tensorflow/core/framework/tensor.h"
20f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke#include "tensorflow/core/framework/types.h"
21227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen#include "tensorflow/core/kernels/bounds_check.h"
22f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke#include "tensorflow/core/lib/random/simple_philox.h"
23f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke#include "tensorflow/core/util/guarded_philox_random.h"
24f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
25f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickeusing tensorflow::random::SimplePhilox;
26f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
275cae4a52edf9fe4951c51ee2352ca041e4ab9363Derek Murraynamespace tensorflow {
28f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickenamespace {
29f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
30f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// A simple Rectangle class that supplies intersection.
31f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickeclass Rectangle {
32f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke public:
33f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  Rectangle() { Set(0, 0, 0, 0); }
34f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  Rectangle(int xmin, int ymin, int xmax, int ymax) {
35f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    Set(xmin, ymin, xmax, ymax);
36f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
37f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
38f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  void Set(int xmin, int ymin, int xmax, int ymax) {
39f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    min_x_ = xmin;
40f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    min_y_ = ymin;
41f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    max_x_ = xmax;
42f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    max_y_ = ymax;
43f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
44f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
45f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  bool IsEmpty() const { return min_x_ > max_x_ || min_y_ > max_y_; }
46f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  float Area() const {
47f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    return static_cast<float>((max_x_ - min_x_) * (max_y_ - min_y_));
48f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
49f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
50f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  Rectangle Intersect(const Rectangle& r) const {
51f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int pmin_x = std::max(min_x_, r.min_x_);
52f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int pmin_y = std::max(min_y_, r.min_y_);
53f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int pmax_x = std::min(max_x_, r.max_x_);
54f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int pmax_y = std::min(max_y_, r.max_y_);
55f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
56f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    if (pmin_x > pmax_x || pmin_y > pmax_y) {
57f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      return Rectangle();
58f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    } else {
59f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      return Rectangle(pmin_x, pmin_y, pmax_x, pmax_y);
60f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    }
61f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
62f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
63f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  int min_x_;
64f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  int min_y_;
65f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  int max_x_;
66f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  int max_y_;
67f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke};
68f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
69f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// Determine if the supplied cropping box covers a sufficient fraction of the
70f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// the supplied bounding boxes.
71f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickebool SatisfiesOverlapConstraints(const Rectangle& crop,
72f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                 float minimum_object_covered,
73f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                 const std::vector<Rectangle>& bounding_boxes) {
74f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // Reject any bounding box which contains no pixels.
75f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  const float kMinArea = 1.0;
76f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (crop.Area() < kMinArea) {
77f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    return false;
78f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
79f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
80f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // Loop through all objects and determine if the proposed cropping box covers
81f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // a sufficient fraction of one of the supplied bounding boxes.
82f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  bool is_object_covered = false;
83f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  for (const auto& bbox : bounding_boxes) {
84f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const float object_area = bbox.Area();
85f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    if (object_area < kMinArea) {
86f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      continue;
87f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    }
88f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
89f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const float object_covered = crop.Intersect(bbox).Area() / object_area;
90f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
91f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    if (object_covered >= minimum_object_covered) {
92f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      is_object_covered = true;
93f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      break;
94f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    }
95f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
96f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  return is_object_covered;
97f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke}
98f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
99f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// Generate a random crop within the rectangle
100f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// (0, 0, original_width, original_height).
101f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// The minimum area of the crop will be between
102f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke//   min_relative_crop_area * orig_width * orig_height
103f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// and
104f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke//   max_relative_crop_area * orig_width * orig_height
105f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// such that its width = round(aspect_ratio * height).
106f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// The diameter of the generated rectangle will be uniformly distributed between
107f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// its minimum and maximum size. The center of the rectangle will be distributed
108f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// uniformly within the source rectangle. The function returns false if the
109f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke// rectangle could not be generated with the given constraints.
110f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wickebool GenerateRandomCrop(int original_width, int original_height,
111f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                        float min_relative_crop_area,
112f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                        float max_relative_crop_area, float aspect_ratio,
113f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                        SimplePhilox* random, Rectangle* crop_rect) {
114f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (max_relative_crop_area <= 0.0 || aspect_ratio <= 0.0 ||
115f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      original_width <= 0 || original_height <= 0 ||
116f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      min_relative_crop_area > max_relative_crop_area) {
117f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    return false;
118f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
119f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
120f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  const float min_area =
121f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      min_relative_crop_area * original_width * original_height;
122f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  const float max_area =
123f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      max_relative_crop_area * original_width * original_height;
124f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
125227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen  int height = static_cast<int>(lrintf(sqrt(min_area / aspect_ratio)));
126227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen  int max_height = static_cast<int>(lrintf(sqrt(max_area / aspect_ratio)));
127f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
128fc53648e0c0f5110bfab75a02b9dc75260b913d3A. Unique TensorFlower  if (lrintf(max_height * aspect_ratio) > original_width) {
129f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // We must find the smallest max_height satisfying
130f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // round(max_height * aspect_ratio) <= original_width:
131f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const float kEps = 0.0000001;
132fc53648e0c0f5110bfab75a02b9dc75260b913d3A. Unique TensorFlower    max_height = static_cast<int>((original_width + 0.5 - kEps) / aspect_ratio);
133f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
134f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
135f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (max_height > original_height) {
136f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    max_height = original_height;
137f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
138f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
139f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (height >= max_height) {
140f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    height = max_height;
141f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
142f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
143f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (height < max_height) {
144f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // We need to generate a random number in the closed range
145f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // [0, max_height - height].
146f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    height += random->Uniform(max_height - height + 1);
147f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
148227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen  int width = static_cast<int>(lrintf(height * aspect_ratio));
149f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  DCHECK_LE(width, original_width);
150f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
151f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // Let us not fail if rounding error causes the area to be
152f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // outside the constraints.
153f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // Try first with a slightly bigger rectangle first.
154f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  float area = static_cast<float>(width * height);
155f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (area < min_area) {
156f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    height += 1;
157227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    width = static_cast<int>(lrintf(height * aspect_ratio));
158f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    area = width * height;
159f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
160f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
161f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // Let us not fail if rounding error causes the area to be
162f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // outside the constraints.
163f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // Try first with a slightly smaller rectangle first.
164f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (area > max_area) {
165f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    height -= 1;
166227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    width = static_cast<int>(lrintf(height * aspect_ratio));
167f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    area = width * height;
168f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
169f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
170f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // Now, we explored all options to rectify small rounding errors.
171f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  // It seems the constraints can't be satisfied: return false.
172f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (area < min_area || area > max_area || width > original_width ||
173f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      height > original_height || width <= 0 || height <= 0) {
174f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    return false;
175f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
176f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
177f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  int y = 0;
178f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (height < original_height) {
179f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    y = random->Uniform(original_height - height);
180f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
181f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  int x = 0;
182f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  if (width < original_width) {
183f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    x = random->Uniform(original_width - width);
184f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
185f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
186f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  crop_rect->min_x_ = x;
187f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  crop_rect->min_y_ = y;
188f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  crop_rect->max_x_ = x + width;
189f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  crop_rect->max_y_ = y + height;
190f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  return true;
191f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke}
192f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke}  // namespace
193f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
194f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicketemplate <typename T>
195481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tangclass SampleDistortedBoundingBoxV2Op : public OpKernel {
196f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke public:
197481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang  explicit SampleDistortedBoundingBoxV2Op(OpKernelConstruction* context)
198f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      : OpKernel(context) {
199f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(context, generator_.Init(context));
200f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
201481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang    if (context->num_inputs() == 2) {
202481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang      OP_REQUIRES_OK(context, context->GetAttr("min_object_covered",
203481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                                               &min_object_covered_));
204481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang      OP_REQUIRES(
205481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang          context, min_object_covered_ >= 0,
206481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang          errors::InvalidArgument("Min object covered must be non-negative: ",
207481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                                  min_object_covered_));
208481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang    }
209f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
210f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(context, context->GetAttr("use_image_if_no_bounding_boxes",
211f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                             &use_image_if_no_bounding_boxes_));
212f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
213f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(
214f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        context, context->GetAttr("aspect_ratio_range", &aspect_ratio_range_));
215f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, aspect_ratio_range_.size() == 2,
216f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::InvalidArgument(
217f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    "Aspect ratio range field must specify 2 dimensions"));
218f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
219f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(
220f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        context, aspect_ratio_range_[0] > 0 && aspect_ratio_range_[1] > 0,
221f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        errors::InvalidArgument("Aspect ratio range must be non-negative: [",
222f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                aspect_ratio_range_[0], ", ",
223f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                aspect_ratio_range_[1], "]"));
224f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
225f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(context, context->GetAttr("area_range", &area_range_));
226f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(
227f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        context, area_range_.size() == 2,
228f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        errors::InvalidArgument("Area range field must specify 2 dimensions"));
229f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
230f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(
231f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        context, area_range_[0] > 0 && area_range_[1] > 0,
232f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        errors::InvalidArgument("Area range must be non-negative: [",
233f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                area_range_[0], ", ", area_range_[1], "]"));
234f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
235f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, area_range_[0] <= 1 && area_range_[1] <= 1,
236f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::InvalidArgument(
237f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    "Area range must be less then or equal to 1.0: [",
238f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    area_range_[0], ", ", area_range_[1], "]"));
239f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
240f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(context, context->GetAttr("max_attempts", &max_attempts_));
241f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, max_attempts_ > 0,
242f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::InvalidArgument("Max attempts must be non-negative: ",
243f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                        max_attempts_));
244f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
245f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
246f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  void Compute(OpKernelContext* context) override {
247f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const Tensor& image_size = context->input(0);
248f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
249f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, image_size.dims() == 1,
250f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::InvalidArgument("image_size must be 1-dimensional",
251f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                        image_size.shape().DebugString()));
252f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, image_size.dim_size(0) == 3,
253227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen                errors::InvalidArgument("image_size must contain 3 elements",
254f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                        image_size.shape().DebugString()));
255f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
256f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Note image_size_data(2) is the depth and unused.
257227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    const uint64 height_raw = internal::SubtleMustCopy(image_size.flat<T>()(0));
258227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    const uint64 width_raw = internal::SubtleMustCopy(image_size.flat<T>()(1));
259227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    OP_REQUIRES(context,
260227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen                FastBoundsCheck(height_raw, std::numeric_limits<int32>::max()),
261227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen                errors::InvalidArgument("image height cannot be >= int32 max"));
262227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    OP_REQUIRES(context,
263227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen                FastBoundsCheck(width_raw, std::numeric_limits<int32>::max()),
264227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen                errors::InvalidArgument("image width cannot be >= int32 max"));
265227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    const int32 height = static_cast<int32>(height_raw);
266227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. Andersen    const int32 width = static_cast<int32>(width_raw);
267f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
268f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Ensure that the supplied bounding boxes are sane and convert them to
269f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Rectangles.
270f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const Tensor& input_boxes = context->input(1);
271f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, input_boxes.dims() == 3,
272f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::InvalidArgument("input boxes must be 3-dimensional "
273f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                        "[batch, num_boxes, coords]: ",
274f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                        input_boxes.shape().DebugString()));
275f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, input_boxes.dim_size(input_boxes.dims() - 1) == 4,
276f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::InvalidArgument(
277f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    "bounding boxes must have shape [4] or [*, 4], got ",
278f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    input_boxes.shape().DebugString()));
279f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
280481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang    float min_object_covered_val = 0.0;
281481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang    if (context->num_inputs() == 3) {
282481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang      const Tensor& min_object_covered = context->input(2);
283481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang
284481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang      OP_REQUIRES(
285481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang          context, TensorShapeUtils::IsScalar(min_object_covered.shape()),
286481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang          errors::InvalidArgument("min_object_covered must be 0-D, got shape ",
287481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                                  min_object_covered.shape().DebugString()));
288481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang
289481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang      min_object_covered_val = min_object_covered.scalar<float>()();
290481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang
291481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang      OP_REQUIRES(
292481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang          context, min_object_covered_val >= 0,
293481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang          errors::InvalidArgument("Min object covered must be non-negative: ",
294481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                                  min_object_covered_val));
295481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang    } else {
296481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang      min_object_covered_val = min_object_covered_;
297481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang    }
298481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang
299f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    std::vector<Rectangle> bounding_boxes;
300f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    if (input_boxes.NumElements() > 0) {
301f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      TTypes<float>::ConstMatrix boxes = input_boxes.flat_inner_dims<float>();
302f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      for (int b = 0; b < boxes.dimension(0); ++b) {
303f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        for (int i = 0; i < 4; ++i) {
304f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke          OP_REQUIRES(
305f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke              context, boxes(b, i) >= 0.0 && boxes(b, i) <= 1.0,
306f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke              errors::InvalidArgument("All bounding box coordinates must "
307f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                      "be in [0.0, 1.0]: ",
308f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                      boxes(b, i)));
309f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        }
310f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
311fc53648e0c0f5110bfab75a02b9dc75260b913d3A. Unique TensorFlower        const int32 x_min = static_cast<int32>(boxes(b, 1) * width);
312fc53648e0c0f5110bfab75a02b9dc75260b913d3A. Unique TensorFlower        const int32 y_min = static_cast<int32>(boxes(b, 0) * height);
313fc53648e0c0f5110bfab75a02b9dc75260b913d3A. Unique TensorFlower        const int32 x_max = static_cast<int32>(boxes(b, 3) * width);
314fc53648e0c0f5110bfab75a02b9dc75260b913d3A. Unique TensorFlower        const int32 y_max = static_cast<int32>(boxes(b, 2) * height);
315f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
316f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        bounding_boxes.push_back(Rectangle(x_min, y_min, x_max, y_max));
317f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      }
318f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    }
319f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
320f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Insert the entire image if no bounding boxes are supplied.
321f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const Rectangle image_rect(0, 0, width, height);
3227280dafca161eb3413ea120d3dd07c63e5254e72A. Unique TensorFlower    if (bounding_boxes.empty()) {
323f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      OP_REQUIRES(context, use_image_if_no_bounding_boxes_,
324f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                  errors::InvalidArgument(
325f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                      "No bounding boxes provided as input. One must "
326f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                      "enable use_image_if_no_bounding_boxes if you wish "
327f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                      "to not provide any bounding boxes."));
328f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      bounding_boxes.push_back(image_rect);
329f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    }
330f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
331f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const float min_sample_area = area_range_[0];
332f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const float max_sample_area = area_range_[1];
333f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const float min_sample_aspect_ratio = aspect_ratio_range_[0];
334f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const float max_sample_aspect_ratio = aspect_ratio_range_[1];
335f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
336f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    auto local_gen = generator_.ReserveSamples32(4 * max_attempts_);
337f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    random::SimplePhilox random(&local_gen);
338f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
339f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    Rectangle crop_rect;
340f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    bool sample_generated = false;
341f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    for (int i = 0; i < max_attempts_; ++i) {
342f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      const float sample_aspect_ratio =
343f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke          random.RandFloat() *
344f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke              (max_sample_aspect_ratio - min_sample_aspect_ratio) +
345f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke          min_sample_aspect_ratio;
346f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
347f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      if (GenerateRandomCrop(width, height, min_sample_area, max_sample_area,
348f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                             sample_aspect_ratio, &random, &crop_rect)) {
349481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang        if (SatisfiesOverlapConstraints(crop_rect, min_object_covered_val,
350f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                                        bounding_boxes)) {
351f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke          sample_generated = true;
352f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke          break;
353f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        }
354f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      }
355f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    }
356f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
357f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    if (!sample_generated) {
358f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke      crop_rect = image_rect;
359f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    }
360f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
361f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Determine the cropping parameters from the bounding box.
362f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int target_width = crop_rect.max_x_ - crop_rect.min_x_;
363f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int target_height = crop_rect.max_y_ - crop_rect.min_y_;
364f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
365f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int offset_width = crop_rect.min_x_;
366f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    const int offset_height = crop_rect.min_y_;
367f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
368f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Ensure that the bounding box fits in the image dimensions.
369f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, width >= target_width + offset_width,
370f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::FailedPrecondition(
371f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    "width must be > target_width + offset_width: ", width,
372f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    "vs ", target_width, " + ", offset_width));
373f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES(context, height >= target_height + offset_height,
374f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                errors::FailedPrecondition(
375f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    "height must be >= target_height: height = ", height, "vs ",
376f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                    target_height, " + ", offset_height));
377f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
378f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Create two vectors, each 3 elements, to provide as arguments to Slice.
379f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // See Slice() operation for details.
380f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    Tensor* begin = nullptr;
381f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(context,
382f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                   context->allocate_output(0, TensorShape({3}), &begin));
383f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    Tensor* size = nullptr;
384f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(context,
385f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke                   context->allocate_output(1, TensorShape({3}), &size));
386f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    Tensor* bboxes = nullptr;
387f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    OP_REQUIRES_OK(
388f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        context, context->allocate_output(2, TensorShape({1, 1, 4}), &bboxes));
389f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
3909832df4e7acf093e2fccbb84c5362ee201ea4321fo    typename TTypes<T, 1>::Tensor begin_data(begin->tensor<T, 1>());
3919832df4e7acf093e2fccbb84c5362ee201ea4321fo    typename TTypes<T, 1>::Tensor size_data(size->tensor<T, 1>());
3929832df4e7acf093e2fccbb84c5362ee201ea4321fo    TTypes<float, 3>::Tensor bboxes_data = bboxes->tensor<float, 3>();
393f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
394fe60adfb9d46f662f6ee216db23409efdbbb20e2A. Unique TensorFlower    begin_data(0) = T(offset_height);
395fe60adfb9d46f662f6ee216db23409efdbbb20e2A. Unique TensorFlower    size_data(0) = T(target_height);
396f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
397fe60adfb9d46f662f6ee216db23409efdbbb20e2A. Unique TensorFlower    begin_data(1) = T(offset_width);
398fe60adfb9d46f662f6ee216db23409efdbbb20e2A. Unique TensorFlower    size_data(1) = T(target_width);
399f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
400f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    bboxes_data(0, 0, 0) =
401f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        static_cast<float>(crop_rect.min_y_) / static_cast<float>(height);
402f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    bboxes_data(0, 0, 1) =
403f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        static_cast<float>(crop_rect.min_x_) / static_cast<float>(width);
404f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    bboxes_data(0, 0, 2) =
405f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        static_cast<float>(crop_rect.max_y_) / static_cast<float>(height);
406f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    bboxes_data(0, 0, 3) =
407f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke        static_cast<float>(crop_rect.max_x_) / static_cast<float>(width);
408f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
409f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke    // Retain all of the channels.
410fe60adfb9d46f662f6ee216db23409efdbbb20e2A. Unique TensorFlower    begin_data(2) = T(0);
411fe60adfb9d46f662f6ee216db23409efdbbb20e2A. Unique TensorFlower    size_data(2) = T(-1);
412f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  }
413f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
414f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke private:
415f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  GuardedPhiloxRandom generator_;
416f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  int32 max_attempts_;
417f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  std::vector<float> area_range_;
418f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  std::vector<float> aspect_ratio_range_;
419f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  float min_object_covered_;
420f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke  bool use_image_if_no_bounding_boxes_;
421f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke};
422f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
423481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang#define REGISTER_KERNELS(type)                                  \
424481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang  REGISTER_KERNEL_BUILDER(Name("SampleDistortedBoundingBox")    \
425481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                              .Device(DEVICE_CPU)               \
426481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                              .TypeConstraint<type>("T"),       \
427481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                          SampleDistortedBoundingBoxV2Op<type>) \
428481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang  REGISTER_KERNEL_BUILDER(Name("SampleDistortedBoundingBoxV2")  \
429481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                              .Device(DEVICE_CPU)               \
430481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                              .TypeConstraint<type>("T"),       \
431481a4b4c8c773196943aa04cb19a3ccbeb8c8c38Yong Tang                          SampleDistortedBoundingBoxV2Op<type>)
432f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
433227e7db4b0d3d9ff8325b1f0f3a2ee1f91c8eb0cDavid G. AndersenTF_CALL_INTEGRAL_TYPES(REGISTER_KERNELS);
434f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke#undef REGISTER_KERNELS
435f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke
436f3a77378b4c056e76691c5eba350a022c11e00d4Martin Wicke}  // namespace tensorflow
437