Use rasterio to calculate physical actual distance between two points in tif file

Assume that there is a picture in tif format containing geographical coordinate information and its corresponding ordinary picture in jpg or png format, as
shown in the following figure:
geographic information map

insert image description here
The first one is a geographic information map in tif format, and the second one is an ordinary jpg picture converted after downsampling according to a certain ratio

How to calculate the actual distance between any two points in a jpg image?
For example, calculate the length of the bridge in the middle of the graph, that is, the distance between the two endpoints of the bridge

In the tif image, if we know the latitude and longitude of the point, we can use the geodesic function in the geopy package to calculate the distance between two points.
The code is as follows

from geopy.distance import geodesic
distance = geodesic((lat1,lon1), (lat2,lon2)).meters

Where lat1, lon1 are the latitude and longitude of the first point

So the key to the problem is how to find the latitude and longitude corresponding to the point in the jpg image.
To achieve this goal, you need to go through 3 steps.

step one

Find the ratio of the point in the jpg to the width and height of the picture relative to the picture.
The code is as follows:

import cv2 as cv
image = cv.imread('example.jpg')
h, w, c = image.shape
# 选取两个点
pick1_x, pick1_y = 2022, 2160
pick2_x, pick2_y = 1902, 2160
pick1_x_ratio, pick1_y_ratio = pick1_x/w, pick1_y/h
pick2_x_ratio, pick2_y_ratio = pick2_x/w, pick2_y/h

step two

Find the row and column in the tif graph corresponding to the two points according to the ratio.
The code is as follows:

import rasterio
with rasterio.open(tif_file) as src:
	tmp_height = src.height  # 数据高度
    tmp_width = src.width  # 数据宽度
    pick1_col, pick1_row = int(pick1_x_ratio*tmp_width), int(pick1_y_ratio*tmp_height)
    pick2_col, pick2_row = int(pick2_x_ratio*tmp_width), int(pick2_y_ratio*tmp_height)

step three

The code to convert row and column numbers into coordinates expressed in Map units
is as follows:

with rasterio.open(tif_file) as src:
	pick1_lon_map, pick1_lat_map = src.xy(pick1_row, pick1_col)
    pick2_lon_map, pick2_lat_map = src.xy(pick2_row, pick2_col)

step four

Convert map unit coordinates to decimal degrees (Decimal Degrees) coordinates.
Note the coordinate system used here.
The code is as follows:

import pyproj
import rasterio
with rasterio.open(tif_file) as src:
	# 定义源坐标系统和目标坐标系统(这里以 EPSG:4326 作为目标坐标系统,即 WGS84 经纬度坐标系统)
	src_proj = pyproj.Proj(src.crs)  # src.crs为获取到的tif图中的源坐标系统
    dst_proj = pyproj.Proj(init='EPSG:4326')
    print("picked points 坐标转换")
    pick1_long, pick1_latt = pyproj.transform(src_proj, dst_proj, pick1_lon_map, pick1_lat_map)
    pick2_long, pick2_latt = pyproj.transform(src_proj, dst_proj, pick2_lon_map, pick2_lat_map)

step five

Calculate the distance between two points according to the decimal coordinates.
The code is as follows:

from geopy.distance import geodesic
# 纬度在前,经度在后
distance = geodesic((pick1_latt, pick1_long), (pick2_latt, pick2_long)).meters
print(f"选取的两点之间的距离:{
      
      distance} meters")

The two points selected are the two endpoints of the bridge, so the final calculation results in a bridge length of 15.57 meters
insert image description here

The overall code is as follows:

import cv2 as cv
import rasterio
from geopy.distance import geodesic
import pyproj

# 打开图像文件
tif_file_path = 'path_to_tif_file'
jpg_file_path = 'path_to_jpg_file'

image = cv.imread(jpg_file_path)
h, w, c = image.shape

# 打开TIFF文件
with rasterio.open(tif_file_path) as src:
    # 选取桥头两个点
    pick1_x, pick1_y = 2022, 2160
    pick2_x, pick2_y = 1902, 2160

    tmp_height = src.height  # 数据高度,行数
    tmp_width = src.width  # 数据宽度,列数

    # step1 and step2: 计算两点所占比例及其在tif中对应的行列号
    pick1_col, pick1_row = int(pick1_x*tmp_width/w), int(pick1_y*tmp_height/h)
    pick2_col, pick2_row = int(pick2_x*tmp_width/w), int(pick2_y*tmp_height/h)
    
    # step3: 计算对应的地图单位坐标
    print("picked point 经纬度")
    pick1_lon, pick1_lat = src.xy(pick1_row, pick1_col)
    pick2_lon, pick2_lat = src.xy(pick2_row, pick2_col)
    print("pick1经纬度:", pick1_lon, ' ', pick1_lat)
    print("pick2经纬度:", pick2_lon, ' ', pick2_lat)


    # 定义源坐标与目标坐标系统(这里以 EPSG:4326 作为目标坐标系统,即 WGS84 经纬度坐标系统)
    src_proj = pyproj.Proj(src.crs)
    dst_proj = pyproj.Proj(init='EPSG:4326')

    # step 4: 将地图单位坐标转为十进制经纬度坐标
    print("picked points 坐标转换")
    pick1_long, pick1_latt = pyproj.transform(src_proj, dst_proj, pick1_lon, pick1_lat)
    pick2_long, pick2_latt = pyproj.transform(src_proj, dst_proj, pick2_lon, pick2_lat)
    print(f"第一个点经纬度:{
      
      pick1_long}  {
      
      pick1_latt}")
    print(f"第二个点经纬度:{
      
      pick2_long}  {
      
      pick2_latt}")

    # step5: 计算两点之间的距离
    distance = geodesic((pick1_latt, pick1_long), (pick2_latt, pick2_long)).meters
    print(f"选取的两点之间的距离:{
      
      distance} meters")

There is another conversion worthy of attention,
that is, the mutual conversion between row and column numbers and map unit coordinates.
The code is as follows:

import rasterio
with rasterio.open(tif_file) as src:
	# 行列号转地图单位坐标
	lon_map, lat_map = src.xy(row, col)
	# 地图单位坐标转行列号
	row, col = src.index(lon_map, lat_map)

Guess you like

Origin blog.csdn.net/JingpengSun/article/details/131234851