easyidp.metashape.Metashape

class easyidp.metashape.Metashape(project_path=None, chunk_id=None, raw_img_folder=None, check_img_existance=True)

Metashape 3D 重建项目中每个块的对象

__init__(project_path=None, chunk_id=None, raw_img_folder=None, check_img_existance=True)

初始化 Metashape 类的方法

参数:
  • project_path (str, optional) -- 要打开的 metashape 项目文件,例如 "xxxx.psx",默认值为 None,表示创建一个空类

  • chunk_id (int or str, optional) -- 要打开的块 ID 或名称(标签),默认值为 None,打开第一个块。

  • raw_img_folder (str, optional) -- 原始无人机图像文件夹,默认值为 None

  • check_img_existance (bool) -- 设置为 False 时忽略丢失的照片,适用于仅有少量图像的测试项目,以避免 FileNotFoundError

示例

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

Then open the demo Metashape project:

>>> ms = idp.Metashape(test_data.metashape.lotus_psx)
<'Lotus.psx' easyidp.Metashape object with 1 active chunks>

  id  label
----  -------
-> 0  Chunk 1

或者您可以创建一个空类,然后打开项目:

>>> ms = idp.Metashape()
>>> ms.open_project(test_data.metashape.lotus_psx)
<'Lotus.psx' easyidp.Metashape object with 1 active chunks>

id  label
----  -------
-> 0  Chunk 1

小心

一个 Metashape 项目可能有多个块,每个 easyidp.Metashape 项目一次只能处理一个块。

ID 前的箭头显示哪个块已被打开

<'multichunk.psx' easyidp.Metashape object with 2 active chunks>

  id  label
----  ------------
-> 1  multiple_bbb
   2  miltiple_aaa

Methods

__init__([project_path, chunk_id, ...])

初始化 Metashape 类的方法

back2raw(roi[, save_folder])

Projects ROIs to raw images using batch matrix operations.

back2raw_crs(points_xyz[, ignore, log])

将一个 GIS 坐标 ROI(多边形)投影到所有图像上

back2raw_old(roi[, save_folder])

将多个 GIS 坐标 ROI(多边形)投影到所有图像上

change_photo_folder(raw_img_folder[, ...])

Change the folder path of raw images

get_photo_position([to_crs, refresh])

获取所有照片的中心地理位置(在给定的 CRS 上)

open_chunk(chunk_id[, project_path])

切换到其他块,或新项目中的块

open_project(project_path[, chunk_id])

打开一个新的 3D 重建项目以覆盖当前项目。

show_photo_folder()

检查原始照片路径的功能

show_roi_on_img(img_dict, roi_name[, img_name])

在给定图像上可视化给定 ROI 的特定反向投影结果。

sort_img_by_distance(img_dict_all, roi[, ...])

按照片到 ROI 的距离排序 back2raw img_dict 结果的高级包装器

Attributes

crs

the geographic coordinates (often the same as the export DOM and DSM), <class 'pyproj.crs.crs.CRS'>

dom

输出的数字正射影像图 (DOM),easyidp.GeoTiff

dsm

输出的数字表面模型 (DSM),easyidp.GeoTiff

pcd

输出的点云,easyidp.PointCloud

project_folder

the folder contains the metashape project (.psx) files

project_name

the metashape project (file) name.

chunk_id

被选为easyidp的块(本类只处理Metashape项目中的一个块)

raw_img_folder

the folder that contains the origial images

label

项目 / 块名称

meta

项目元信息

enabled

该项目是否被激活,(通常用于Metashape),<class 'bool'>

sensors

the container for all sensors in this project (camera model), <class 'easyidp.Container'>, a dict-like object consisted by Sensor

photos

该项目中所有照片的容器(图像),<class 'easyidp.Container'>,由 Photo 组成的类字典对象

back2raw(roi, save_folder=None, **kwargs) dict

Projects ROIs to raw images using batch matrix operations.

This is an optimized version of back2raw() using vectorized numpy operations (einsum) for significant speedup (typically 10-30x).

参数:
  • roi (easyidp.ROI | dict) -- The ROI object or dictionary with polygon coordinates. Each ROI should have shape (n_vertices, 3) with CRS coordinates.

  • save_folder (str, optional) -- Folder to save output JSON and PNG files, by default None.

  • ignore (str | None, optional) -- Currently not implemented in batch version.

  • log (bool, optional) -- Currently not implemented in batch version.

返回:

Same structure as back2raw(): {roi_name: {photo_name: pixel_coords (n, 2)}}

返回类型:

dict

备注

  • Uses point deduplication to minimize redundant calculations.

  • Batch processes all photos simultaneously using einsum.

  • Groups photos by sensor for efficient batch calibration.

示例

>>> import easyidp as idp
>>> ms = idp.Metashape(project_path)
>>> roi = idp.ROI(shapefile_path)
>>> roi.get_z_from_dsm(dsm_path)
>>>
>>> # Optimized batch processing
>>> out = ms.back2raw(roi)
>>> # Same output structure as ms.back2raw(roi)

参见

back2raw

Original implementation (non-optimized).

back2raw_crs(points_xyz, ignore=None, log=False)

将一个 GIS 坐标 ROI(多边形)投影到所有图像上

参数:
  • points_hv (ndarray (nx3)) -- 多边形顶点的3D坐标,CRS坐标

  • ignore (str | None, optional) -- 是否容忍图像外的小部分,详见 easyidp.reconstruct.Sensor.in_img_boundary()。 - None:严格在图像区域内; - x:仅y(垂直)在图像区域内,x可以在图像外; - y:仅x(水平)在图像区域内,y可以在图像外。

  • log (bool, optional) -- 是否打印日志以进行调试,默认值为False

返回:

一个字典,键=图像名称,值=像素坐标

返回类型:

dict,

示例

数据准备

>>> import easyidp as idp

>>> ms = idp.Metashape(test_data.metashape.lotus_psx)
>>> dsm = idp.GeoTiff(test_data.metashape.lotus_dsm)
>>> ms.crs = dsm.crs

>>> plot =  np.array([   # N1E1 plot geo coordinate
...     [ 368020.2974959 , 3955511.61264302,      97.56272272],
...     [ 368022.24288365, 3955512.02973983,      97.56272272],
...     [ 368022.65361232, 3955510.07798313,      97.56272272],
...     [ 368020.69867274, 3955509.66725421,      97.56272272],
...     [ 368020.2974959 , 3955511.61264302,      97.56272272]
... ])

..注意:: 在进行反向投影计算之前,需要指定Metashape项目的CRS(ms.crs = dsm.crs

然后使用此函数在原始图像上找到先前的ROI位置:

>>> out_dict = ms.back2raw_crs(plot)

>>> out_dict["DJI_0478"]
array([[   2.03352333, 1474.90817792],
       [  25.04572582, 1197.08827224],
       [ 311.99971438, 1214.81701547],
       [ 288.88669685, 1492.59824542],
       [   2.03352333, 1474.90817792]])
back2raw_old(roi, save_folder=None, **kwargs)

将多个 GIS 坐标 ROI(多边形)投影到所有图像上

参数:
  • roi (easyidp.ROI | dict) -- 由easyidp.ROI()或字典创建的<ROI>对象

  • save_folder (str, optional) -- 保存json文件和原始图像上ROI部分的文件夹,默认值为None

  • ignore (str | None, optional) -- 是否容忍图像外的小部分,详见 easyidp.reconstruct.Sensor.in_img_boundary()。 - None:严格在图像区域内; - x:仅y(垂直)在图像区域内,x可以在图像外; - y:仅x(水平)在图像区域内,y可以在图像外。

  • log (bool, optional) -- 是否打印日志以进行调试,默认值为False

示例

数据准备

>>> import easyidp as idp

>>> lotus = idp.data.Lotus()

>>> ms = idp.Metashape(project_path=lotus.metashape.project)

>>> roi = idp.ROI(lotus.shp, name_field=0)
[shp][proj] Use projection [WGS 84] for loaded shapefile [plots.shp]
Read shapefile [plots.shp]: 100%|███████████████| 112/112 [00:00<00:00, 2481.77it/s]
>>> roi = roi[0:2]

>>> roi.get_z_from_dsm(lotus.pix4d.dsm)

然后使用此函数进行反向投影:

>>> out_all = ms.back2raw(roi)
{
    'N1W1': {
        'DJI_0478.JPG':
            array([[  14.96726711, 1843.13937997],
                   [  38.0361733 , 1568.36113526],
                   [ 320.25420037, 1584.28772847],
                   [ 297.16110119, 1859.05913936],
                   [  14.96726711, 1843.13937997]])
        'DJI_0479':
            array([...])
        ...
    }
    'N1W2': {...}   # output of `back2raw_crs()`
}
change_photo_folder(raw_img_folder, check_img_existance=True)

Change the folder path of raw images

参数:
  • raw_img_folder (str | dict) -- 包含原始图像文件夹的新文件夹路径。如果类型== str:直接替换根字符串。如果类型== dict:(未实现)例如:{'path/to/flight1/': 'new/path/to/flight1', }

  • check_img_existance (bool) -- 设置为 False 时忽略丢失的照片,适用于仅有少量图像的测试项目,以避免 FileNotFoundError

chunk_id

被选为easyidp的块(本类只处理Metashape项目中的一个块)

enabled

该项目是否被激活,(通常用于Metashape),<class 'bool'>

get_photo_position(to_crs=None, refresh=False)

获取所有照片的中心地理位置(在给定的 CRS 上)

参数:
  • to_crs (pyproj.CRS, optional) -- 转换为另一个地理坐标,默认值为None,即项目的CRS

  • refresh (bool, optional) --

    • False:使用缓存的结果(如果有),默认值

    • True:重新计算照片位置

返回:

字典包含"photo.label":[x, y, z]坐标

返回类型:

dict

示例

数据准备

>>> import numpy as np
>>> np.set_printoptions(suppress=True)

>>> import easyidp as idp

>>> lotus = idp.data.Lotus()
>>> ms = idp.Metashape(project_path=lotus.metashape.project)

然后使用此函数获取照片在3D世界中的位置:

>>> out = ms.get_photo_position()
{
    'DJI_0422': array([139.54053245,  35.73458169, 130.09433649]),
    'DJI_0423': array([139.54053337,  35.73458315, 129.93437641]),
    ...
}

小心

默认情况下,如果未指定metashape项目的CRS,它将以默认CRS(epsg: 4326)返回 -> (经度, 纬度, 高度),如果需要转换为与DOM/DSM相同的坐标,请先指定CRS

>>> dom = idp.GeoTiff(lotus.metashape.dom)
>>> ms.crs = dom.crs

>>> out = ms.get_photo_position()
{
    'DJI_0422': array([ 368017.73174354, 3955492.1925972 ,     130.09433649]),
    'DJI_0423': array([ 368017.81717717, 3955492.35300323,     129.93437641]),
    ...
}
label

项目 / 块名称

meta

项目元信息

open_chunk(chunk_id, project_path=None)

切换到其他块,或新项目中的块

参数:
  • chunk_id (int or str) -- 要打开的块ID或名称(标签)

  • project_path (str, optional) -- 要打开的新Metashape项目文件,如“xxxx.psx”,默认值为None,表示在当前Metashape项目内切换

示例

数据准备

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> ms = idp.Metashape(test_data.metashape.multichunk_psx)
<'multichunk.psx' easyidp.Metashape object with 4 active chunks>

  id  label
----  --------------
-> 1  multiple_bbb
   2  multiple_aaa
   3  multiple_aaa_1
   4  multiple_aaa_2

然后通过ID或标签从块1切换到块4:

>>> ms.open_chunk('4')
# or
>>> ms.open_chunk('multiple_aaa_2')

>>> ms
<'multichunk.psx' easyidp.Metashape object with 4 active chunks>

  id  label
----  --------------
   1  multiple_bbb
   2  multiple_aaa
   3  multiple_aaa_1
-> 4  multiple_aaa_2
open_project(project_path, chunk_id=None)

打开一个新的 3D 重建项目以覆盖当前项目。

参数:
  • project_path (str, optional) -- 要打开的pix4d项目文件,如“xxxx.psx”,或不带后缀的“xxxx”。

  • chunk_id (int or str, optional) -- 要打开的块 ID 或名称(标签),默认值为 None,打开第一个块。

示例

>>> import easyidp as idp
>>> test_data = idp.data.TestData()

>>> ms = idp.Metashape()
<Empty easyidp.Metashape object>

>>> ms.open_project(test_data.metashape.lotus_psx)
<'Lotus.psx' easyidp.Metashape object with 1 active chunks>

  id  label
----  -------
-> 0  Chunk 1
photos

该项目中所有照片的容器(图像),<class 'easyidp.Container'>,由 Photo 组成的类字典对象

project_folder

the folder contains the metashape project (.psx) files

project_name

the metashape project (file) name.

raw_img_folder

the folder that contains the origial images

sensors

the container for all sensors in this project (camera model), <class 'easyidp.Container'>, a dict-like object consisted by Sensor

show_photo_folder()

检查原始照片路径的功能

show_roi_on_img(img_dict, roi_name, img_name=None, **kwargs)

在给定图像上可视化给定 ROI 的特定反向投影结果。

参数:
  • img_dict (dict) -- 来自back2raw()的反向结果

  • roi_name (str) -- 要显示的ROI名称

  • img_name (str) -- 图像文件名,默认值为None,绘制所有可用图像

  • corrected_poly_coord (np.ndarray, optional) -- 图像上校正的2D多边形像素坐标(如果有),默认值为None

  • title (str, optional) -- 显示在顶部的图像标题,默认值为None -> ROI [roi_name] on [img_name]

  • save_as (str, optional) -- 保存输出图形的文件路径,默认值为None

  • show (bool, optional) -- 是否显示(在jupyter notebook中)或弹出(在命令行中)图形,默认值为False

  • color (str, optional) -- 多边形线条颜色,默认值为'红色'

  • alpha (float, optional) -- 多边形透明度,默认值为0.5

  • dpi (int, optional) -- 生成图形的dpi,默认值为72

示例

>>> img_dict_ms = roi.back2raw(ms)

检查图像"DJI_0479.JPG"上的"N1W1" ROI:

>>> ms.show_roi_on_img(img_dict_ms, "N1W1", "DJI_0479")

检查所有可用图像上的"N1W1" ROI:

>>> ms.show_roi_on_img(img_dict_ms, "N1W1")

有关更多详细信息,请参见 此示例

sort_img_by_distance(img_dict_all, roi, distance_thresh=None, num=None, save_folder=None)

按照片到 ROI 的距离排序 back2raw img_dict 结果的高级包装器

参数:
  • img_dict_all (dict) -- roi.back2raw(...)的所有输出字典,例如 img_dict = roi.back2raw(...) -> img_dict

  • roi (idp.ROI) -- 您的ROI变量

  • num (None or int) -- 保留最近的{x}张图像

  • distance_thresh (None or float) -- 保留距离ROI比此距离更近的图像。

  • save_folder (str, optional) -- 保存json文件和原始图像上ROI部分的文件夹,默认值为None

返回:

与roi.back2raw(...)的输出结构相同

返回类型:

dict

示例

在之前的 back2raw() 结果中:

>>> out_all = ms.back2raw(roi)
{
    'N1W1': {
        'DJI_0478.JPG':
            array([[  14.96726711, 1843.13937997],
                   [  38.0361733 , 1568.36113526],
                   [ 320.25420037, 1584.28772847],
                   [ 297.16110119, 1859.05913936],
                   [  14.96726711, 1843.13937997]])
        'DJI_0479':
            array([...])
        ...
    }
    'N1W2': {...}   # output of `back2raw_crs()`
}

图像顺序混乱,在大多数应用情况下,可能只需要1-3张最接近(现实世界中的ROI)的图像,因此提供了此函数进行排序/过滤。

在以下示例中,它过滤了3张相机到现实世界中的ROI距离小于10米的图像:

>>> img_dict_sort = ms.sort_img_by_distance(
...     out_all, roi,
...     distance_thresh=10,  # distance threshold is 10m
...     num=3   # only keep 3 closest images
... )

>>> img_dict_sort
{
    'N1W1': {
        'DJI_0500': array([[1931.09279469, 2191.59919979],
                           [1939.92139124, 1930.65101348],
                           [2199.9439422 , 1939.32128527],
                           [2191.19230849, 2200.557026  ],
                           [1931.09279469, 2191.59919979]]),
        'DJI_0517': array([[2870.94915401, 2143.3570243 ],
                           [2596.8790503 , 2161.04730612],
                           [2578.87033498, 1886.89058023],
                           [2853.13891851, 1869.99769984],
                           [2870.94915401, 2143.3570243 ]]),
        'DJI_0518': array([[3129.43264924, 1984.91814896],
                           [2856.71879306, 2002.03817639],
                           [2838.71418138, 1730.00287388],
                           [3111.73360179, 1713.76233134],
                           [3129.43264924, 1984.91814896]])
    },
    'N1W2': {
        'DJI_0500': array([[2214.36789052, 2200.35979344],
                           [2221.8996575 , 1940.70687713],
                           [2479.9825464 , 1949.3909589 ],
                           [2472.52171907, 2209.40355333],
                           [2214.36789052, 2200.35979344]]),
        'DJI_0517': array([[2849.82108263, 1845.6733702 ],
                           [2577.37309441, 1863.60741328],
                           [2559.80046778, 1592.07656949],
                           [2832.52942622, 1574.92640413],
                           [2849.82108263, 1845.6733702 ]]),
        'DJI_0516': array([[2891.61686486, 2542.98979632],
                           [2616.06780032, 2559.41601014],
                           [2598.43900454, 2282.36641612],
                           [2874.23023492, 2266.71552931],
                           [2891.61686486, 2542.98979632]])
    }
}

或选择最近的一张图像:

>>> img_dict_sort = ms.sort_img_by_distance(
...     out_all, roi,
...     num=1   # only keep the closest images
... )

>>> img_dict_sort
{
    'N1W1': {
        'DJI_0500': array([[1931.09279469, 2191.59919979],
                           [1939.92139124, 1930.65101348],
                           [2199.9439422 , 1939.32128527],
                           [2191.19230849, 2200.557026  ],
                           [1931.09279469, 2191.59919979]])
    },
    'N1W2': {
        'DJI_0500': array([[2214.36789052, 2200.35979344],
                           [2221.8996575 , 1940.70687713],
                           [2479.9825464 , 1949.3909589 ],
                           [2472.52171907, 2209.40355333],
                           [2214.36789052, 2200.35979344]])
    }
}

您可以使用``list(dict.keys())[0]``自动获取图像名称以迭代每个绘图:

for plot_name, plot_value in img_dict_sort.items():
    img_name = list(plot_value.key())[0]

    coord = plot_value[img_name]
    # or
    coord = img_dict_sort[plot_name][img_name]