convert static method
- required TensorBuffer tensor,
- List<
int> valueIndex = const <int>[0, 1, 2, 3], - required int boundingBoxAxis,
- required BoundingBoxType boundingBoxType,
- required CoordinateType coordinateType,
- required int height,
- required int width,
Creates a list of bounding boxes from a TensorBuffer tensor
which represents bounding boxes.
valueIndex
denotes the order of the elements defined in each bounding box type. An empty
index list represent the default order of each bounding box type. For example, to denote
the default order of BOUNDARIES, {left, top, right, bottom}, the index should be {0, 1, 2,
3}. To denote the order {left, right, top, bottom}, the order should be {0, 2, 1, 3}.
The index list can be applied to all bounding box types to adjust the order of their
corresponding underlying elements.
boundingBoxAxis
specifies the index of the dimension that represents bounding box. The
size of that dimension is required to be 4. Index here starts from 0. For example, if the
tensor has shape 4x10, the axis for bounding boxes is likely to be 0. For shape 10x4, the
axis is likely to be 1 (or -1, equivalently).
boundingBoxType
defines how values should be converted into boxes. See BoundingBoxType
coordinateType
defines how values are interpreted to coordinates. See CoordinateType
height
is height of the image which the boxes belong to. Only has effects when coordinateType
is CoordinateType.RATIO
width
is width of the image which the boxes belong to. Only has effects when coordinateType
is CoordinateType.RATIO
Returns A list of bounding boxes List<Rect> that the tensor
represents. All dimensions except
boundingBoxAxis
will be collapsed with order kept. For example, given
tensor
with shape {1, 4, 10, 2} and boundingBoxAxis = 1
, The result will be a list
of 20 bounding boxes.
Throws ArgumentError if size of bounding box dimension (set by
boundingBoxAxis
) is not 4.
Throws ArgumentError if boundingBoxAxis
is not in {(-(D+1), D)} where
D
is the number of dimensions of the tensor
.
Throws ArgumentError if tensor
has data type other than
TfLiteType.float32
.
Implementation
static List<Rect> convert({
required TensorBuffer tensor,
List<int> valueIndex = const <int>[0, 1, 2, 3],
required int boundingBoxAxis,
required BoundingBoxType boundingBoxType,
required CoordinateType coordinateType,
required int height,
required int width,
}) {
List<int> shape = tensor.getShape();
SupportPreconditions.checkArgument(
boundingBoxAxis >= -shape.length && boundingBoxAxis < shape.length,
errorMessage:
"Axis $boundingBoxAxis is not in range (-(D+1), D), where D is the number of dimensions of input" +
" tensor (shape=$shape)",
);
if (boundingBoxAxis < 0) {
boundingBoxAxis = shape.length + boundingBoxAxis;
}
SupportPreconditions.checkArgument(
shape[boundingBoxAxis] == 4,
errorMessage:
"Size of bounding box dimBouBoxension $boundingBoxAxis is not 4. Got ${shape[boundingBoxAxis]} in shape $shape",
);
SupportPreconditions.checkArgument(
valueIndex.length == 4,
errorMessage:
"Bounding box index list length ${valueIndex.length} is not 4. Got index list $valueIndex",
);
SupportPreconditions.checkArgument(
tensor.getDataType() == TfLiteType.float32,
errorMessage:
"Bounding Boxes only create from FLOAT32 buffers. Got: ${tensor.getDataType()}");
// From Android Library
// Collapse dimensions to {a, 4, b}. So each bounding box could be represent as (i, j), and its
// four values are (i, k, j), where 0 <= k < 4. We can compute the 4 flattened index by
// i * 4b + k * b + j.
int a = 1;
for (int i = 0; i < boundingBoxAxis; i++) {
a *= shape[i];
}
int b = 1;
for (int i = boundingBoxAxis + 1; i < shape.length; i++) {
b *= shape[i];
}
List<Rect> boundingBoxList = [];
List<double> values = List.filled(4, 0);
List<double> doubleList = tensor.getDoubleList();
for (int i = 0; i < a; i++) {
for (int j = 0; j < b; j++) {
for (int k = 0; k < 4; k++) {
values[k] = doubleList.elementAt((i * 4 + k) * b + j);
}
boundingBoxList.add(_convertOneBoundingBox(values, boundingBoxType,
coordinateType, height, width, valueIndex));
}
}
return boundingBoxList;
}