Skip to content

Commit 8349eaf

Browse files
author
Jonathan Huang
authored
Merge pull request #2827 from tombstone/documentation
Add dataset tools, pretrained models and documentatinos for open imag…
2 parents 676a4f7 + 560fae8 commit 8349eaf

15 files changed

+977
-5
lines changed

research/object_detection/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ Song Y, Guadarrama S, Murphy K, CVPR 2017
2121
\[[link](https://arxiv.org/abs/1611.10012)\]\[[bibtex](
2222
https://scholar.googleusercontent.com/scholar.bib?q=info:l291WsrB-hQJ:scholar.google.com/&output=citation&scisig=AAGBfm0AAAAAWUIIlnPZ_L9jxvPwcC49kDlELtaeIyU-&scisf=4&ct=citation&cd=-1&hl=en&scfhb=1)\]
2323

24+
<p align="center">
25+
<img src="g3doc/img/tf-od-api-logo.png" width=140 height=195>
26+
</p>
27+
2428
## Maintainers
2529

2630
* Jonathan Huang, github: [jch1](https://github.com/jch1)
@@ -59,6 +63,10 @@ Extras:
5963
Defining your own model architecture</a><br>
6064
* <a href='g3doc/using_your_own_dataset.md'>
6165
Bringing in your own dataset</a><br>
66+
* <a href='g3doc/oid_inference_and_evaluation.md'>
67+
Inference and evaluation on the Open Images dataset</a><br>
68+
* <a href='g3doc/evaluation_protocols.md'>
69+
Supported object detection evaluation protocols</a><br>
6270

6371
## Getting Help
6472

@@ -71,8 +79,21 @@ tensorflow/models Github
7179
[issue tracker](https://github.com/tensorflow/models/issues), prefixing the
7280
issue name with "object_detection".
7381

82+
83+
7484
## Release information
7585

86+
### November 17, 2017
87+
88+
As a part of the Open Images V3 release we have released:
89+
90+
* An implementation of the Open Images evaluation metric and the [protocol](g3doc/evaluation_protocols.md#open-images).
91+
* Additional tools to separate inference of detection and evaluation (see [this tutorial](g3doc/oid_inference_and_evaluation.md)).
92+
* A new detection model trained on the Open Images V2 data release (see [Open Images model](g3doc/detection_model_zoo.md#open-images-models)).
93+
94+
See more information on the [Open Images website](https://github.com/openimages/dataset)!
95+
96+
<b>Thanks to contributors</b>: Stefan Popov, Alina Kuznetsova
7697

7798
### November 6, 2017
7899

@@ -107,6 +128,7 @@ you to try out other detection models!
107128

108129
<b>Thanks to contributors</b>: Jonathan Huang, Andrew Harp
109130

131+
110132
### June 15, 2017
111133

112134
In addition to our base Tensorflow detection model definitions, this
@@ -130,3 +152,4 @@ release includes:
130152
<b>Thanks to contributors</b>: Jonathan Huang, Vivek Rathod, Derek Chow,
131153
Chen Sun, Menglong Zhu, Matthew Tang, Anoop Korattikara, Alireza Fathi, Ian Fischer, Zbigniew Wojna, Yang Song, Sergio Guadarrama, Jasper Uijlings,
132154
Viacheslav Kovalevskyi, Kevin Murphy
155+

research/object_detection/dataset_tools/BUILD

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,26 @@ py_library(
8282
"//tensorflow_models/object_detection/utils:dataset_util",
8383
],
8484
)
85+
86+
py_test(
87+
name = "oid_tfrecord_creation_test",
88+
srcs = ["oid_tfrecord_creation_test.py"],
89+
deps = [
90+
":oid_tfrecord_creation",
91+
"//third_party/py/contextlib2",
92+
"//third_party/py/pandas",
93+
"//third_party/py/tensorflow",
94+
],
95+
)
96+
97+
py_binary(
98+
name = "create_oid_tf_record",
99+
srcs = ["create_oid_tf_record.py"],
100+
deps = [
101+
":oid_tfrecord_creation",
102+
"//third_party/py/contextlib2",
103+
"//third_party/py/pandas",
104+
"//tensorflow",
105+
"//tensorflow_models/object_detection/utils:label_map_util",
106+
],
107+
)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ==============================================================================
15+
r"""Creates TFRecords of Open Images dataset for object detection.
16+
17+
Example usage:
18+
./create_oid_tf_record \
19+
--input_annotations_csv=/path/to/input/annotations-human-bbox.csv \
20+
--input_images_directory=/path/to/input/image_pixels_directory \
21+
--input_label_map=/path/to/input/labels_bbox_545.labelmap \
22+
--output_tf_record_path_prefix=/path/to/output/prefix.tfrecord
23+
24+
CSVs with bounding box annotations and image metadata (including the image URLs)
25+
can be downloaded from the Open Images GitHub repository:
26+
https://github.com/openimages/dataset
27+
28+
This script will include every image found in the input_images_directory in the
29+
output TFRecord, even if the image has no corresponding bounding box annotations
30+
in the input_annotations_csv.
31+
"""
32+
from __future__ import absolute_import
33+
from __future__ import division
34+
from __future__ import print_function
35+
36+
import os
37+
38+
import contextlib2
39+
import pandas as pd
40+
import tensorflow as tf
41+
42+
from object_detection.dataset_tools import oid_tfrecord_creation
43+
from object_detection.utils import label_map_util
44+
45+
tf.flags.DEFINE_string('input_annotations_csv', None,
46+
'Path to CSV containing image bounding box annotations')
47+
tf.flags.DEFINE_string('input_images_directory', None,
48+
'Directory containing the image pixels '
49+
'downloaded from the OpenImages GitHub repository.')
50+
tf.flags.DEFINE_string('input_label_map', None, 'Path to the label map proto')
51+
tf.flags.DEFINE_string(
52+
'output_tf_record_path_prefix', None,
53+
'Path to the output TFRecord. The shard index and the number of shards '
54+
'will be appended for each output shard.')
55+
tf.flags.DEFINE_integer('num_shards', 100, 'Number of TFRecord shards')
56+
57+
FLAGS = tf.flags.FLAGS
58+
59+
60+
def main(_):
61+
tf.logging.set_verbosity(tf.logging.INFO)
62+
63+
required_flags = [
64+
'input_annotations_csv', 'input_images_directory', 'input_label_map',
65+
'output_tf_record_path_prefix'
66+
]
67+
for flag_name in required_flags:
68+
if not getattr(FLAGS, flag_name):
69+
raise ValueError('Flag --{} is required'.format(flag_name))
70+
71+
label_map = label_map_util.get_label_map_dict(FLAGS.input_label_map)
72+
all_annotations = pd.read_csv(FLAGS.input_annotations_csv)
73+
all_images = tf.gfile.Glob(
74+
os.path.join(FLAGS.input_images_directory, '*.jpg'))
75+
all_image_ids = [os.path.splitext(os.path.basename(v))[0] for v in all_images]
76+
all_image_ids = pd.DataFrame({'ImageID': all_image_ids})
77+
all_annotations = pd.concat([all_annotations, all_image_ids])
78+
79+
tf.logging.log(tf.logging.INFO, 'Found %d images...', len(all_image_ids))
80+
81+
with contextlib2.ExitStack() as tf_record_close_stack:
82+
output_tfrecords = oid_tfrecord_creation.open_sharded_output_tfrecords(
83+
tf_record_close_stack, FLAGS.output_tf_record_path_prefix,
84+
FLAGS.num_shards)
85+
86+
for counter, image_data in enumerate(all_annotations.groupby('ImageID')):
87+
tf.logging.log_every_n(tf.logging.INFO, 'Processed %d images...', 1000,
88+
counter)
89+
90+
image_id, image_annotations = image_data
91+
# In OID image file names are formed by appending ".jpg" to the image ID.
92+
image_path = os.path.join(FLAGS.input_images_directory, image_id + '.jpg')
93+
with tf.gfile.Open(image_path) as image_file:
94+
encoded_image = image_file.read()
95+
96+
tf_example = oid_tfrecord_creation.tf_example_from_annotations_data_frame(
97+
image_annotations, label_map, encoded_image)
98+
if tf_example:
99+
shard_idx = long(image_id, 16) % FLAGS.num_shards
100+
output_tfrecords[shard_idx].write(tf_example.SerializeToString())
101+
102+
103+
if __name__ == '__main__':
104+
tf.app.run()
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ==============================================================================
15+
r"""Utilities for creating TFRecords of TF examples for the Open Images dataset.
16+
"""
17+
from __future__ import absolute_import
18+
from __future__ import division
19+
from __future__ import print_function
20+
21+
import tensorflow as tf
22+
23+
from object_detection.core import standard_fields
24+
from object_detection.utils import dataset_util
25+
26+
27+
def tf_example_from_annotations_data_frame(annotations_data_frame, label_map,
28+
encoded_image):
29+
"""Populates a TF Example message with image annotations from a data frame.
30+
31+
Args:
32+
annotations_data_frame: Data frame containing the annotations for a single
33+
image.
34+
label_map: String to integer label map.
35+
encoded_image: The encoded image string
36+
37+
Returns:
38+
The populated TF Example, if the label of at least one object is present in
39+
label_map. Otherwise, returns None.
40+
"""
41+
42+
filtered_data_frame = annotations_data_frame[
43+
annotations_data_frame.LabelName.isin(label_map)]
44+
45+
image_id = annotations_data_frame.ImageID.iloc[0]
46+
47+
feature_map = {
48+
standard_fields.TfExampleFields.object_bbox_ymin:
49+
dataset_util.float_list_feature(filtered_data_frame.YMin.as_matrix()),
50+
standard_fields.TfExampleFields.object_bbox_xmin:
51+
dataset_util.float_list_feature(filtered_data_frame.XMin.as_matrix()),
52+
standard_fields.TfExampleFields.object_bbox_ymax:
53+
dataset_util.float_list_feature(filtered_data_frame.YMax.as_matrix()),
54+
standard_fields.TfExampleFields.object_bbox_xmax:
55+
dataset_util.float_list_feature(filtered_data_frame.XMax.as_matrix()),
56+
standard_fields.TfExampleFields.object_class_text:
57+
dataset_util.bytes_list_feature(
58+
filtered_data_frame.LabelName.as_matrix()),
59+
standard_fields.TfExampleFields.object_class_label:
60+
dataset_util.int64_list_feature(
61+
filtered_data_frame.LabelName.map(lambda x: label_map[x])
62+
.as_matrix()),
63+
standard_fields.TfExampleFields.filename:
64+
dataset_util.bytes_feature('{}.jpg'.format(image_id)),
65+
standard_fields.TfExampleFields.source_id:
66+
dataset_util.bytes_feature(image_id),
67+
standard_fields.TfExampleFields.image_encoded:
68+
dataset_util.bytes_feature(encoded_image),
69+
}
70+
71+
if 'IsGroupOf' in filtered_data_frame.columns:
72+
feature_map[standard_fields.TfExampleFields.
73+
object_group_of] = dataset_util.int64_list_feature(
74+
filtered_data_frame.IsGroupOf.as_matrix().astype(int))
75+
if 'IsOccluded' in filtered_data_frame.columns:
76+
feature_map[standard_fields.TfExampleFields.
77+
object_occluded] = dataset_util.int64_list_feature(
78+
filtered_data_frame.IsOccluded.as_matrix().astype(int))
79+
if 'IsTruncated' in filtered_data_frame.columns:
80+
feature_map[standard_fields.TfExampleFields.
81+
object_truncated] = dataset_util.int64_list_feature(
82+
filtered_data_frame.IsTruncated.as_matrix().astype(int))
83+
if 'IsDepiction' in filtered_data_frame.columns:
84+
feature_map[standard_fields.TfExampleFields.
85+
object_depiction] = dataset_util.int64_list_feature(
86+
filtered_data_frame.IsDepiction.as_matrix().astype(int))
87+
88+
return tf.train.Example(features=tf.train.Features(feature=feature_map))
89+
90+
91+
def open_sharded_output_tfrecords(exit_stack, base_path, num_shards):
92+
"""Opens all TFRecord shards for writing and adds them to an exit stack.
93+
94+
Args:
95+
exit_stack: A context2.ExitStack used to automatically closed the TFRecords
96+
opened in this function.
97+
base_path: The base path for all shards
98+
num_shards: The number of shards
99+
100+
Returns:
101+
The list of opened TFRecords. Position k in the list corresponds to shard k.
102+
"""
103+
tf_record_output_filenames = [
104+
'{}-{:05d}-of-{:05d}'.format(base_path, idx, num_shards)
105+
for idx in xrange(num_shards)
106+
]
107+
108+
tfrecords = [
109+
exit_stack.enter_context(tf.python_io.TFRecordWriter(file_name))
110+
for file_name in tf_record_output_filenames
111+
]
112+
113+
return tfrecords

0 commit comments

Comments
 (0)