最近遇到一个小问题:
如何将我在labelme上勾的Json 文件转变为shapefile呢?
这个问题困扰我的主要原因是labelme的json文件和我平常见到的json文件有点不太一样。labelme的json中的坐标是相对于其附属的图像的左上角原点的以像素为单位的距离(x,y),因此需要将它转变为地理坐标。这就需要用到其附属的图像的geotransform信息。
主要的解决思路就是:
1)根据附属图像提取地理位置信息
2)提取json中的shapes, 获取每一个point的坐标
3)根据关系将point的坐标变换为地理坐标
4)利用geopandas 创建矢量并导出
代码如下
import json
import geopandas as gpd
from shapely.geometry import Polygon
from osgeo import gdal
import glob
from tqdm import tqdm
# 批量读取 Labelme 导出的 JSON 文件
folder_path = 'your/folder/path'
json_paths = glob.glob(folder_path + '*.json')
json_paths
def labelme_json_to_shapefile(labelme_json_path, output_shapefile_path):
with open(labelme_json_path, 'r') as f:
data = json.load(f)
#读取跟json文件相关的影像信息
image_width = data['imageWidth']
image_height = data['imageHeight']
geometries = []
imagepath = folder_path + data['imagePath'].split('\\')[-1]
image = gdal.Open(imagepath)
geotrans = image.GetGeoTransform()
x0 = geotrans[0]
y0 = geotrans[3]
x_resolution = geotrans[1]
y_resolution = geotrans[5]
# 处理每个标注对象
for shape in data['shapes']:
label = shape['label']
points = shape['points']
# 将相对坐标转换为绝对坐标
polygon_coords = [(x0+point[0]*x_resolution, y0+point[1]*y_resolution) for point in points]
# 创建 shapely Polygon 对象
polygon = Polygon(polygon_coords)
# 添加到 geometries 列表中
geometries.append({'label': label, 'geometry': polygon})
# 创建 GeoDataFrame
gdf = gpd.GeoDataFrame(geometries, geometry='geometry')
gdf.crs = 'EPSG:32644'
gdf.to_file(output_shapefile_path, driver='ESRI Shapefile')
for json_path in tqdm(json_paths):
output_shp_path = 'your/folder/path'+json_path.split('\\')[-1].replace('.json', '.shp')
labelme_json_to_shapefile(json_path, output_shp_path)
'''
这里需要注意的是坐标系(EPSG)需要改成适合你自己的坐标系。
'''
结果如下,成功了~
欢迎关注我和我的公众号