4

I used labelImg to create some bounding boxes around items of interest on a TIF image. I am wondering if I can convert those XML bounding boxes into shapefiles? I've looked at a few other posts for converting xml to shp or even csv to shp, but those posts are all dealing with lat/lon coordinates. Unfortunately, I have xmin, ymin, xmax, ymax values that seem to be specifically attached to the image/tif that I drew them on.

So I am confused on how I could convert to a shapefile when the xml does not have any georeference information. I could add the georeference information because my image/tif contains it, but I am still not working with lat/lon coordinates. Perhaps I could convert the mins/maxs into lat/lon?

Any suggestions on how I might approach this problem?

enter image description here

Edits:

I found this solution that someone has posted. I however am using a .tif for an image and they are using a .jpg. I am unaware if that will screw up the encoded parameter? The code is running, but I do get the printed error: error in labelme conversion: 'NoneType' object has no attribute 'shape'. The "data_test.json" is saved, but only contains {}`.

Edits 2:

enter image description here

2
  • what is the unit in bnbbox? – Mazu_R Jan 21 at 19:58
  • Are xmin, ymin, xmax, ymax pixel coordinates? – Kadir Şahbaz Jan 21 at 20:21
6

You can use rasterio for getting geo-coordinates from pixel coordinates, and pyshp (shapefile) for creating a shapefile.

import rasterio
import shapefile # -> pyshp module
import xml.etree.ElementTree as ET

# get pixel coordinates from XML
root = ET.parse('/path/to/file.xml').getroot()
xmin = float(root.findall('object/bndbox/xmin')[0].text)
ymin = float(root.findall('object/bndbox/ymin')[0].text)
xmax = float(root.findall('object/bndbox/xmax')[0].text)
ymax = float(root.findall('object/bndbox/ymax')[0].text)

tif_file = '/path/to/tif_file.tif' # georeferenced TIFF
shp_path = '/path/to/shapefile' # don't add extension

# open georeferenced tif file
with rasterio.open(tif_file) as image:
    ## get vertices of the bounding box
    # geocoordinates from pixel coordinates
    p1 = image.xy(xmin, ymin)
    p2 = image.xy(xmax, ymin) 
    p3 = image.xy(xmax, ymax) 
    p4 = image.xy(xmin, ymax) 

    # save shapefile containing one bounding box shape
    w = shapefile.Writer(shp_path + '.shp')
    w.field("name", "C") # pyshp needs at least one field
    w.poly([[p1, p2, p3, p4]]) # generate bbox polygon
    w.record('bbox')
    w.close()
    
    # generate .PRJ file
    crs_wkt = image.crs.to_wkt()
    prj = open(shp_path + '.prj', "w")
    prj.write(crs_wkt)
    prj.close()

enter image description here

6
  • I am continuing to run into an error: NoneType object has no attribute 'to_wkt'. Also, does this code work for multiple bounding boxes within an xml file? – Zman3 Jan 22 at 17:14
  • Are you sure the tif file is georeferenced? If image.crs returns nothing or None, the tif file is not georeferenced. – Kadir Şahbaz Jan 22 at 17:16
  • image.crs returns nothing. I apologize, I thought it was georeferenced. – Zman3 Jan 22 at 17:27
  • I assumed the tif was georeferenced because when I opened it up in Label Img with the corresponding xml, the bounding box would show. So somehow they are tied together. – Zman3 Jan 22 at 17:40
  • I've attached a picture of the information I have in my tif – Zman3 Jan 22 at 17:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.