Generating RGB Image Data set for CNN Algorithm - Image Classification and Object Detection
Creating a image data set is one of the big challenges while you work on object detection algorithms. In this post, I am going to explain how you can create a proper image data set for training and testing by using python and OpenCV. We will create a python class that you can use for your further projects in order to create image data sets quickly.
Before you begin to implementing the codes in this post please be sure that you have the “OpenCV” and “numpy” installed in your environment (also os , xml which comes with the python installation). You also have to install LabelImg tool into your system. It is the tool that provides great opportunity to labeling objects and creating annotation files for the image files. Thanks to this tool you can save the object coordinates as pixel index in a XML file and you can label multiple object in single image.
I will be using “conda” virtual environment in this example. If you don’t have Anaconda in your system please go to this link and download it. After install the Anaconda you can create virtual environment with “conda”. Please visit this post to see instruction for creating “conda” environment.
Lets start how to install LabelImg. First please go to LabelImg github repository and clone the it to your working directory and go into that folder with command prompt.
> git clone https://github.com/tzutalin/labelImg.git
> cd labelImg
Please execute following commands after cloning the labelImg repository;
> conda install pyqt=5
> pyrcc5 -o libs/resources.py resources.qrc
> python labelImg.py
If the installation of required packages of labelImg is successful you will see this labelImg screen;
Before you start the creating annotation files you need take all your image files into same folder and create a new folder called ‘annots’ in the same directory that you have the images folder. So, your working directory should be looking like this;
workingDiretory
----images/
----0001.jpg
----0002.jpg
----...
----annots/
Just as advice, renaming all images with the id such as ‘0001.jpg , 0002.jpg …’ is more useful for clean process. Thank to that you can easily follow images and you do not get any errors because of the image names.
After you all done with the renaming image files and moving them into images folder, you are ready to start annotation. In this tutorial image annotation files created in “PascalVOC” format. Because of that first thing that you should do is making sure that the “PascalVOC” is selected at the left sidebar. Now, it is time to select the images from directory and changing annotation saving directory. Please click on the ‘Open Dir’ and select the images folder in your working directory. After that click on the “Change Save Dir” and select the folder that you have created for annotations (called ‘annots’).
Press ‘W’ and select the area that contains the object. After selection, a popup that includes class names will open. You can write the a class name for that object or select it from popup. Make sure that you are giving same class name for same object with sensitivity of upper and lower case. If you don’t need the predefined class names created by labelImg you can delete them thereby deleting all lines in the file “predefined_classes.txt” which is in the “demo” folder in “labelImg”.
After selecting the area that contains the object and typing the object’s class name correctly pres ‘CTRL+S’ or Save button. The XML file that contains object name, image path, bounding box coordinates and some additional information about image such as width and height will be saved into your saving directory (annots).
XML file’s will be names same as your image file. For instance; if your image file’s name is 0001.jpg XML file’s name is going to be 0001.xml. All images annotation files will be saved separately in the directory of annotations. And xml files looks like this;
<annotation>
<folder>images</folder>
<filename>0001.jpg</filename>
<path>path/to/image/0001.jpg</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>600</width>
<height>360</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>pizza</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>92</xmin>
<ymin>105</ymin>
<xmax>542</xmax>
<ymax>323</ymax>
</bndbox>
</object>
</annotation>
If you complete all the annotations of image files you can start creating python class that generates the training and testing datasets. For to do that, you can use “Jupyter Notebook” or you can just run python scripts on anaconda prompt in order to execute the python codes.
Let’s start coding,
First you need to understand how to parse XML files and access the data that you need for your dataset such as coordinates, object classes and filename. For to do not I am going to use xml.ElementTree module in python. Let’s sort the information that we must to take from annotation files.
- Image path
- File name
- Object name
- Object coordinates (xmin, ymin,xmax,ymax)
That’s all.
Just I mentioned before we are going to create a python class and this class that has modules for parsing xml file, adding image information and grabbing image arrays. Okay, first start creating python class and define the following methods;
add_image_info : This is the method for saving image information into class object such as image array, image path, image id, object id class name and class id.
parse_xml : This is the method for parsing xml files
get_image_arrays : this is the method for getting RGB pixel arrays in the image.
prepare_dataset : this is the method that generates train and test datasets.
In the __init__ method we need to define the variable that we are going to call after;
In this code example image_info array will contain the lists that has the information for each image and trainX, trainY, testX and testy will have the data set. Thanks to that we can call the data set from this class object.
Next method is adding image information the image information array. In this method we will grab the image file path, image RGB array, image id, object id, class name, class id and append the image information array as list.
Now, we have to create a method that can parse the XML. For to do that we are going to use ElementTree method from xml library. If you want get more information about parsing XML file with ElementTree please visit this post.
In this part of the class we will define the method that takes the parsed xml data and adds these data to the image info array. This method will take every object even those objects in the same image file and appends those to the image info array. I have used two for loop. The first loop takes annotation files and the second loop takes the every object in the annotation files and append the coordinate and details of object. Second loop contains the cropping action that crops the object according to object coordinates that have been taken from annotation file. After that object image is going to be resized to 32x32. You can change the resizing ratio if you want.
Last method is preparing data set. This method takes 3 parameter as path , class_object , test_size. Class object is a list that contains the class ids. Path is the directory of your annotation files. Test size is the number of test sample that is going to be used for testing.
With this last snippet of code we ready to create our class. Your codes should looks like this;
If you are done with all the code writing please save this class as createDataset.py in to your working directory. Then, open new python script in the same directory and follow the below. In this code snippet, first we import the class that have just created. After we are creating a list that contains the all classes. Make sure that you add all the classes that you annotated in the LabelImg. After that we define a dataset object by using our class and preparing data set buy using prepare_dataset method. And your train and test data set is ready to use.
# Import the python dataset class
from createDataset import createDataset# Define the objects in list with the id begins with 0
class_object = {0 : 'background' , 1 : 'objectClass1' ,
2 : 'objectClass2'}# Dataset object
train_set = createDataset()# Makes data ready for use
train_set.prepare_dataset('pizza/annots' , class_object, test_size=30)# Assing train and test data
(trainY , trainX) , (testY , testX ) = (train_set.trainY , train_set.trainX ) , (train_set.testY , train_set.testX )