BUG: GCP names are wrong in ODM Report
Hello, i have used gcp points in my process. The gcp names was like; ykn1 , ykn2, ykn3 … My GCP file is like that: +proj=tmerc +lat_0=0 +lon_0=27 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 518876.902 4453173.463 262.223 2451 542 100_0030_0001.JPG YKN6 518876.902 4453173.463 262.223 2598 1307 100_0030_0002.JPG YKN6 518838.142 4453136.888 258.616 2485 458 100_0030_0003.JPG YKN4 518876.902 4453173.463 262.223 2584 1917 100_0030_0003.JPG YKN6 518838.142 4453136.888 258.616 2461 1058 100_0030_0004.JPG YKN4 518876.902 4453173.463 262.223 2558 2535 100_0030_0004.JPG YKN6 518838.142 4453136.888 258.616 2436 1671 100_0030_0005.JPG YKN4 518876.902 4453173.463 262.223 2530 3166 100_0030_0005.JPG YKN6 518838.142 4453136.888 258.616 2409 2274 100_0030_0006.JPG YKN4 518735.306 4453072.649 259.396 200 1681 100_0030_0007.JPG YKN1 518838.142 4453136.888 258.616 2381 2881 100_0030_0007.JPG YKN4 518735.306 4453072.649 259.396 2785 182 100_0030_0008.JPG YKN1 518846.605 4453059.822 279.853 163 2406 100_0030_0008.JPG YKN2 ... So on
After the process, GCP names are shown different according to my GCP file. Like gcp0, gcp1, gcp2…

It makes a confusing situation. Thank you
Any progress with this bug ?
We haven't fixed it yet (PRs would be most welcome of course). 🙏
I worked on the bug and i find the solution. You can search the differences with 'CHANGED' key
Actually it is the bug of OpenSFM. The io.py file includes '_read_gcp_list_lines' function. I fixed the function like this:
def _read_gcp_list_lines(
lines: Iterable[str],
projection,
exif: Dict[str, Dict[str, Any]],
) -> List[pymap.GroundControlPoint]:
points = {}
for line in lines:
words = line.split(None) // CHANGED - split whole line just not for 5 column
easting, northing, alt, pixel_x, pixel_y = map(float, words[:5])
shot_id = words[5].strip()
key = (easting, northing, alt)
if key in points:
point = points[key]
else:
# Convert 3D coordinates
if np.isnan(alt):
alt = 0
has_altitude = False
else:
has_altitude = True
if projection is not None:
lon, lat = projection(easting, northing, inverse=True)
else:
lon, lat = easting, northing
point = pymap.GroundControlPoint()
// CHANGED - Added if else. If user defined name exists control.
if(len(words) > 6):
point.id = words[6].strip()
else:
point.id = "GCP-%d" % len(points)
point.lla = {"latitude": lat, "longitude": lon, "altitude": alt}
point.has_altitude = has_altitude
points[key] = point
# Convert 2D coordinates
d = exif[shot_id]
coordinates = features.normalized_image_coordinates(
np.array([[pixel_x, pixel_y]]), d["width"], d["height"]
)[0]
o = pymap.GroundControlPointObservation()
o.shot_id = shot_id
o.projection = coordinates
point.add_observation(o)
return list(points.values())
I will create a pr for OpenSFM.
Also it has to be changed types.py in openDM folder contains function with name 'georeference_with_gcp'. I changed the function like this:
def georeference_with_gcp(self, gcp_file, output_coords_file, output_gcp_file, output_model_txt_geo, rerun=False):
if not io.file_exists(output_coords_file) or not io.file_exists(output_gcp_file) or rerun:
gcp = GCPFile(gcp_file)
if gcp.exists():
if gcp.entries_count() == 0:
raise RuntimeError("This GCP file does not have any entries. Are the entries entered in the proper format?")
# Convert GCP file to a UTM projection since the rest of the pipeline
# does not handle other SRS well.
rejected_entries = []
// CHANGED - include_extras parameters set true
utm_gcp = GCPFile(gcp.create_utm_copy(output_gcp_file, filenames=[p.filename for p in self.photos], rejected_entries=rejected_entries, include_extras=True))
if not utm_gcp.exists():
raise RuntimeError("Could not project GCP file to UTM. Please double check your GCP file for mistakes.")
for re in rejected_entries:
log.ODM_WARNING("GCP line ignored (image not found): %s" % str(re))
if utm_gcp.entries_count() > 0:
log.ODM_INFO("%s GCP points will be used for georeferencing" % utm_gcp.entries_count())
else:
raise RuntimeError("A GCP file was provided, but no valid GCP entries could be used. Note that the GCP file is case sensitive (\".JPG\" is not the same as \".jpg\").")
self.gcp = utm_gcp
# Compute RTC offsets from GCP points
x_pos = [p.x for p in utm_gcp.iter_entries()]
y_pos = [p.y for p in utm_gcp.iter_entries()]
x_off, y_off = int(np.round(np.mean(x_pos))), int(np.round(np.mean(y_pos)))
# Create coords file, we'll be using this later
# during georeferencing
with open(output_coords_file, 'w') as f:
coords_header = gcp.wgs84_utm_zone()
f.write(coords_header + "\n")
f.write("{} {}\n".format(x_off, y_off))
log.ODM_INFO("Generated coords file from GCP: %s" % coords_header)
# Deprecated: This is mostly for backward compatibility and should be
# be removed at some point
shutil.copyfile(output_coords_file, output_model_txt_geo)
log.ODM_INFO("Wrote %s" % output_model_txt_geo)
else:
log.ODM_WARNING("GCP file does not exist: %s" % gcp_file)
return
else:
log.ODM_INFO("Coordinates file already exist: %s" % output_coords_file)
log.ODM_INFO("GCP file already exist: %s" % output_gcp_file)
self.gcp = GCPFile(output_gcp_file)
self.georef = ODM_GeoRef.FromCoordsFile(output_coords_file)
return self.georef
include_extras parameters set as true. Now it works fine.
I can create a pr for this but it must be applied with the OpenSFM changes.
and the result:

It works !
best regards
This is awesome! Yes a PR in OpenSfM would be the first step; you can also open it on our fork at https://github.com/OpenDroneMap/OpenSfM targeting the 288 branch if it takes too long.
Did this make it's way in? Looking at pull requests, I think maybe it didn't, but it's Friday, so I'm not sure if I can still spell my name.
I don't think it did.
Brought these changes with the latest version, thanks!