AlvaroCavalcante / auto_annotate

Labeling is boring. Use this tool to speed up your next object detection project!
https://medium.com/p/acf410a600b8#9e0e-aaa30a9f4b7a
Apache License 2.0
155 stars 33 forks source link

How to save the output labels with the original image names #1

Closed qqaadir closed 4 years ago

qqaadir commented 4 years ago

Dear Alvaro,

Thank you for your hard work on this. I tested this, its very useful in overcoming the time-consuming task of labeling. Could you please give me some suggestion on how can I retain the original names for the output images and labels. Currently, I am getting images_1 ... images_N in in results folder and images_1 ... images_N in xml folder. Another thing is that, output labels contains the original image size not the reduced size. For example, If original image size is m x n, the output labels also show m x n and not the reduced size. Could you please take a look? Thank you.

AlvaroCavalcante commented 4 years ago

Hello Qadar How are you?

I'm glad that i could help you, can you please tell me more about the problem that are you trying to solve? i think i didn't understand very well...

it's been a while that i don't made any change on this project, so i don't remeber very well the context, sorry.

About the images and xml names, it's easy to change by your preference, but it's important that they have the same name, because the xml needs to refer to the image file.

About the resolution i need more details as i said, but you tried to check your results in LabelImage your some similar software ? In my tests the predicted labels fits very well in the image, because it uses the model prediction coordinates not the resolution itself.

Regards!

qqaadir commented 4 years ago

@AlvaroCavalcante

Here is an example output label

<?xml version="1.0"?>

-<annotation>

<filename>image_1.jpg</filename>

-<size>

<width>1920</width>

<height>1080</height>

<depth>3</depth>

</size>

-<object>

<name>vehicle</name>

<pose>Unspecified</pose>

<truncated>0</truncated>

<difficult>0</difficult>

-<bndbox>

<xmin>927.3096084594727</xmin>

<ymin>677.9193806648254</ymin>

<xmax>1066.5935897827148</xmax>

<ymax>789.0206408500671</ymax>

</bndbox>

</object>

</annotation>

and the one marked by me manually

<?xml version="1.0"?>

-<annotation>

<folder>images</folder>

<filename>FILE1.jpg</filename>

<path>C\Users\images\FILE1.jpg</path>

-<source>

<database>Unknown</database>

</source>

-<size>

<width>1920</width>

<height>1080</height>

<depth>3</depth>

</size>

<segmented>0</segmented>

-<object>

<name>vehicle</name>

<pose>Unspecified</pose>

<truncated>0</truncated>

<difficult>0</difficult>

-<bndbox>

<xmin>928</xmin>

<ymin>669</ymin>

<xmax>1103</xmax>

<ymax>819</ymax>

</bndbox>

</object>

</annotation>

I tested it on16 images for a test, it gave me 13 labels and 16 output images, three of the images were not assigned any labels. Results directory contain images as image_1 ... image_16 and the xml directory contains labels as image_1... image_13. The images that were not labeled are image_2, image_3, and image_14. First thing I want to do is keep the original name as FILE2.jpg for both labels and images.
Second thing labels should be written as image_1, image_4, ...image_13, image_15, image_16. Images names which are not labelled should not included in xml folder. It is difficult to test in image labelImage without names consistency. Please let me know if I was able to clarify some points. I am happy to further clarify. Thank you for quick response.

qqaadir commented 4 years ago

@AlvaroCavalcante

Could you please help with fixing image label names ? I need to modify generate_xml.py file. Every time an image/label is written the following part of the code generates a name like image_1... which is used as xml file name.

def get_file_name(self):
        xml_path = r"C/Users/data/auto_annotate/xml"
        directory = os.path.basename(xml_path)
        file_list = os.listdir(directory)
        if len(file_list) == 0:
            return 1
        else:
            return len(file_list) + 1
def gerenate_basic_structure(self):
        file_name = "image" + "_" + str(self.get_file_name())

Could you please suggest on how can I modify it to include original files names in variable filename instead of image_1... ? In your article in medium, you mentioned the following part of the code is testing if image was annotated and new_xml is not set to False then generate xml file.

if new_xml != False: #this statement prevents to call the class with # we don't have predictions in the image. xml = generate_xml.GenerateXml(array_position, im_width, im_height, class_name)xml.gerenate_basic_structure()

Is there a way to get image file name here which was passed originally in this script and use that name in generate_basic_structure()?

I appreciate your help.

AlvaroCavalcante commented 4 years ago

@qqaadir i've create a branch called "file_name" where i've made some changes to use the original file name when creating the xml files, this may resolve your problem i think. The if statement is used to prevent to call de xml class when the model don't predict anything, but i think using the original file name will overcome this problem.

Please test new branch and give a feedback, because i actually didn't have much time to test, but i think it's working :)

qqaadir commented 4 years ago

@AlvaroCavalcante Thanks a lot, I will test it and let you know.

qqaadir commented 4 years ago

@AlvaroCavalcante I took the exact code given in this branch. Now it does not produce multiple xml files, but just one xml file with name auto_annotate-file_name.xml.

AlvaroCavalcante commented 4 years ago

This is strange, lets discover why it's happening.

The main change is in the detection_images.py, here: file_name = image.filename.split('/')[2].split('.')[0]

This line must take your image name, you can add a print(file_name) to see if this is getting your image name correctly.

After that, we just pass this name as a parameter in the visualization_utils.py and the generate_xml.py. self.file_name = file_name

you can print this global variable file_name in the init of the GenerateXml Class to see if it's correct.

All the process is the same, but the xml files must be equals to your images names.

Let me know the results :)

qqaadir commented 4 years ago

@AlvaroCavalcante I tried changing things in split and ended hardcoding. The following line works well file_name = image.filename.split('/')[-1].split('/')[0][7:].split('.')[0]

I now have same names of image and xml files. Thanks a lot for being responsive.
Before we close this thread, could you please give me an advise how I can improve my labeling results based on your experiences. I am working on low light condition, night time driving data and usually objects of interest are smaller size.

AlvaroCavalcante commented 4 years ago

Very nice friend, it was a pleasure to help you! The labeling results is 100% based on the precision of your trained model, so you need to optime your model. It's nice that you can use the new laballed data to retrain your model and try to get a better precision. I dont know wich model are you using for training, but for smaller size objects of interest the faster R-CNN is a good choice. You can also try to use the kaggle notebook to train your model using TPU, it's considerably faster than a GPU.

qqaadir commented 4 years ago

I am using ssd inception coco from the model zoo repo. I heard about faster R-CNN a lot, i will try it. For model training, I use gpu based system. I will checkout tpu from kaggle. Thanks for this valuable feedback.

qqaadir commented 4 years ago

@AlvaroCavalcante Just an update to you, in generate_xml.py the following part of the code


 ET.SubElement(bndBox, "xmin").text = str(i['xmin'])
 ET.SubElement(bndBox, "ymin").text = str(i['ymin'])
 ET.SubElement(bndBox, "xmax").text = str(i['xmax'])
 ET.SubElement(bndBox, "ymax").text = str(i['ymax'])

should be changed to this

 ET.SubElement(bndBox, "xmin").text = str(round(i['xmin']))
 ET.SubElement(bndBox, "ymin").text = str(round(i['ymin']))
 ET.SubElement(bndBox, "xmax").text = str(round(i['xmax']))
 ET.SubElement(bndBox, "ymax").text = str(round(i['ymax']))

because labelImage somehow does not work on float values. After I rounded bounding box values, it worked fine.

AlvaroCavalcante commented 4 years ago

@qqaadir interesting, i remember that i tested my results when i was developing this algorithm and it was working well in labelImage, but since last year the software could receive some update maybe! Thanks a lot for your help! I'll test and change the code :)