Skip to content

Commit

Permalink
Doc update and data folder
Browse files Browse the repository at this point in the history
  • Loading branch information
Qberto committed Oct 20, 2017
1 parent b87b08d commit 7dbb0da
Show file tree
Hide file tree
Showing 7 changed files with 1,820 additions and 5 deletions.
37 changes: 37 additions & 0 deletions 2_xml_to_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
import glob
import pandas as pd
import xml.etree.ElementTree as ET


def xml_to_csv(path):
xml_list = []
for xml_file in glob.glob(path + '/*.xml'):
tree = ET.parse(xml_file)
root = tree.getroot()
for member in root.findall('object'):
value = (root.find('filename').text,
int(root.find('size')[0].text),
int(root.find('size')[1].text),
member[0].text,
int(member[4][0].text),
int(member[4][1].text),
int(member[4][2].text),
int(member[4][3].text)
)
xml_list.append(value)
column_name = ['filename', 'width', 'height', 'class', 'xmin', 'ymin', 'xmax', 'ymax']
xml_df = pd.DataFrame(xml_list, columns=column_name)
return xml_df


def main():
for directory in ['train', 'test']:
image_path = os.path.join(os.getcwd(), 'images/{0}'.format(directory))
print("Processing images at {0}...".format(directory))
xml_df = xml_to_csv(image_path)
print(xml_df)
xml_df.to_csv('data/{0}_labels.csv'.format(directory), index=None)
print('Successfully converted xml to csv.\n')

main()
98 changes: 98 additions & 0 deletions 3_generate_tfrecord.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""
Usage:
# From tensorflow/models/
# Create train data:
python generate_tfrecord.py --csv_input=data/train_labels.csv --output_path=train.record
# Create test data:
python generate_tfrecord.py --csv_input=data/test_labels.csv --output_path=test.record
"""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

import os
import io
import pandas as pd
import tensorflow as tf

from PIL import Image
from object_detection.utils import dataset_util
from collections import namedtuple, OrderedDict

flags = tf.app.flags
flags.DEFINE_string('csv_input', '', 'Path to the CSV input')
flags.DEFINE_string('output_path', '', 'Path to output TFRecord')
FLAGS = flags.FLAGS


# TO-DO replace this with label map
def class_text_to_int(row_label):
if row_label == 'cafo':
return 1
else:
None


def split(df, group):
data = namedtuple('data', ['filename', 'object'])
gb = df.groupby(group)
return [data(filename, gb.get_group(x)) for filename, x in zip(gb.groups.keys(), gb.groups)]


def create_tf_example(group, path):
with tf.gfile.GFile(os.path.join(path, '{}'.format(group.filename)), 'rb') as fid:
encoded_jpg = fid.read()
encoded_jpg_io = io.BytesIO(encoded_jpg)
image = Image.open(encoded_jpg_io)
width, height = image.size

filename = group.filename.encode('utf8')
image_format = b'jpg'
xmins = []
xmaxs = []
ymins = []
ymaxs = []
classes_text = []
classes = []

for index, row in group.object.iterrows():
xmins.append(row['xmin'] / width)
xmaxs.append(row['xmax'] / width)
ymins.append(row['ymin'] / height)
ymaxs.append(row['ymax'] / height)
classes_text.append(row['class'].encode('utf8'))
classes.append(class_text_to_int(row['class']))

tf_example = tf.train.Example(features=tf.train.Features(feature={
'image/height': dataset_util.int64_feature(height),
'image/width': dataset_util.int64_feature(width),
'image/filename': dataset_util.bytes_feature(filename),
'image/source_id': dataset_util.bytes_feature(filename),
'image/encoded': dataset_util.bytes_feature(encoded_jpg),
'image/format': dataset_util.bytes_feature(image_format),
'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),
'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),
'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),
'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),
'image/object/class/text': dataset_util.bytes_list_feature(classes_text),
'image/object/class/label': dataset_util.int64_list_feature(classes),
}))
return tf_example


def main(_):
writer = tf.python_io.TFRecordWriter(FLAGS.output_path)
path = os.path.join(os.getcwd(), 'images/test')
examples = pd.read_csv(FLAGS.csv_input)
grouped = split(examples, 'filename')
for group in grouped:
tf_example = create_tf_example(group, path)
writer.write(tf_example.SerializeToString())

writer.close()
output_path = os.path.join(os.getcwd(), FLAGS.output_path)
print('Successfully created the TFRecords: {}'.format(output_path))


if __name__ == '__main__':
tf.app.run()
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,45 @@ Description: Using [LabelImg](https://github.com/tzutalin/labelImg), we can crea

Once installed (you can get it with git clone https://github.com/tzutalin/labelImg), labelImg is pointed at the directory of our exported images from step 1. A lengthy process ensues: we must iterate on each image and using our own Neural Network (our eyes and noggins!) we must annotate where the CAFO sites are in each image.

Example:

![Extracted CAFO Image](https://github.com/Qberto/ML_ObjectDetection_CAFO/blob/master/doc/img/img_106_2000.jpg)
Example Extracted CAFO Image Labeled for Test/Train Split:

![Labeled for Test/Train Split](https://github.com/Qberto/ML_ObjectDetection_CAFO/blob/master/doc/img/img_106_2000_labeled.jpg)

This is a simple but repetitive process. It takes some time but the more images you have and the more detailed the labeling, the better the model can be trained for detection of these sites in any location.

This is a simple but repetitive process. It takes some time but the more images you have and the more detailed the labeling, the better the model can be trained for detection of these sites in any location. Sip on some coffee, put on a [nice Machine Learning podcast](https://twimlai.com/), and start labeling away!

Alternatively, if you would like to use our labeled images, you can use the images and xmls found in the images/test and images/train folders.

## Step 3: Split labeled images into train/test samples

Goal: The Convolutional Neural Network will use a subset of our labeled images to train a model, and a separate subset to check how well it's doing at detecting CAFO sites. We need to split our labeled images into these subsets before we start training the model.

Description: Once all your labeled images are ready, you should see xml files corresponding to each labeled image. We need to split our entire folder of images and corresponding xmls into training and testing subsets. For this model, I used a roughly 70% Train / 30% Test split (503 images for training, and 208 images for testing).

For now, this is done manually. In an upcoming version of this repo, the test/split will be configured and done automatically.

## Step 4: Generate TF Records from the train/test splits

Goal: We need to create TFRecord files that we need to train an object detection model in TensorFlow.

Description: A few format changes must occur: First, we convert the XML files from all the images in the train and test folders into singular CSV files. Second, we convert the singular CSV files into TFRecord files. We'll use a few scripts to perform the conversions:

1. [XML to CSV](https://github.com/Qberto/ML_ObjectDetection_CAFO/2_xml_to_csv.py)

2. [Generate TFRecord](https://github.com/Qberto/ML_ObjectDetection_CAFO/3_generate_tfrecord.py)

Each script is currently provided as is, so please review each file and make the appropriate changes to reference your own directories and workspace. A future version of this repo will contain a more appropriate process to handle relative paths and more seamless transition of labeled images to TFRecords.

The first script should generate two CSV files: "test_labels.csv" and "train_labels.csv". Please take a second to confirm that each of these files contain data; the data should correspond to geometry for bounding boxes from step 3.

The 3_generate_tfrecord.py script then reads these and generates the TFRecord files. Please note, at this stage you should have TensorFlow installed on your system and the following repository available (https://github.com/tensorflow/models/tree/master/research). To execute this script for the test and train subsets, create a data folder in your workspace and run the following commands from your prompt:

python 3_generate_tfrecord.py --csv_input=data/train_labels.csv --output_path=data/train.record
python 3_generate_tfrecord.py --csv_input=data/test_labels.csv --output_path=data/test.record

You should now see the train.record and test.record in your data folder.

For reference, you may take a look at the data folder in this repository to see what your singular CSVs and TFRecord files should look like.

## Step 5: Set up a configuration file containing CNN hyperparameters

## Step 6: Train
Expand Down
Binary file added data/test.record
Binary file not shown.
Loading

0 comments on commit 7dbb0da

Please sign in to comment.