I have developed a semantic segmentation method to map certain objects in aerial imagery. Throughout this project I download pictures (4800x4800 pxs) where I know the min_x, min_y, max_x and max_y in world coordinates, e.g. (6.212454957892032, 51.58908266914109, 6.219403242107967, 51.59339941284951). Resolution is 10 cm per pixel.
To then segment the pictures I crop the large picture (4800x4800) into multiple pictures with a resolution of 320x320. To identify each of those cropped pictures I calculated its center coordinate as follows (from upper left to right then to south):
dlat = (side * 360) / (2 * np.pi * r) #dlat for 32m in degrees
side = 32
r = 6371000 #avg earth radius
minx = float(minx)
miny = float(miny)
maxx = float(maxx)
maxy = float(maxy)
identifier = (minx, miny, maxx, maxy)
# Takes a 4800x4800 image tile and returns a list of 320x320 pixel images
tile = np.array(tile)
images = []
coords = []
N = 0
S = 4800
W = 0
E = 4800
# y coordinate is dlat/2 degrees, i.e. 16 meters, south of the maximum y coordinate.
y_coord = maxy - dlat/2
while N < S:
W = 0
x_coord = minx + (((side * 360) / (2 * np.pi * r * np.cos(np.deg2rad(y_coord))))/2) #16 m to the middle
while W < E:
# The first image is taken from the upper left corner, we then slide from left
# to right and from top to bottom
images.append(tile[N:N + 320, W:W + 320])
coords.append((x_coord, y_coord))
x_coord += (((side * 360) / (2 * np.pi * r * np.cos(np.deg2rad(y_coord)))))
W = W + 320
N = N + 320
y_coord = y_coord - dlat
As I also use this approach to then convert the identified pixel polygons to real world coordinates I run into minor differences between the underlying map and the identified objects (10-20m difference) sometimes minor. So I ask myself what is wrong with my approach and where could I make it more efficient by using proper packages.
I actually did some research but it is rather confusing to me because I do not use GeoTIFF files or similar. I get a numpy array as output which I then rasterize with rasterio to retrieve the polygons in pixel coordinates. I convert these using the following function to real world coordinates (using the middle point of each picture as an identifier and fix point to calculate the other coordinates):
def centroid_coord(center_coord, distance_vector, size = 320):
'''
returns lat, lon of array centroid
:param center_coord: tuple of center coords, identifier of picture tile
:param distance_vector: tuple of distance vector, measured from center point in px
:param size: scaling factor for distance from center point in pixels (half the size of the segmented output (320)
:return: lat,lon array centroid
'''
dist_px_x, dist_px_y = distance_vector
x_center, y_center = center_coord
x_min = x_center - (((32 * 360) / (2 * np.pi * r * np.cos(np.deg2rad(y_center))))/2)
y_new = y_center + (side/size) * dist_px_y * (dlat/side)
x_new = x_min + (side/size) * ((size/2) + dist_px_x) * 360 * (1/(2 * np.pi * r * np.cos(np.deg2rad(y_new))))
return (x_new, y_new)
I think that this approach is not optimal and that there is a much more correct and efficient way using proper packages.
How can I do this?
Array: Binary array with a size (320,320) indicating where a certain object is or not. Using rasterio finding polygons of the objects in pixel coordinates. Output: Convert polygons in pixel coordinates to world coordinates using the identifier of the input image (center point) My problems:
- Is the center point calculation (world-coordinatewise) correct like this?
- Should I take the upper left corner point of the image to ease the process?
- How can I convert the polygons with pixel coordinates correctly to world coordinate polygons?