easyidp.metashape.Metashape#
- class easyidp.metashape.Metashape(project_path=None, chunk_id=None, raw_img_folder=None, check_img_existance=True)#
the object for each chunk in Metashape 3D reconstruction project
- __init__(project_path=None, chunk_id=None, raw_img_folder=None, check_img_existance=True)#
The method to initialize the Metashape class
- パラメータ:
project_path (str, optional) -- The metashape project file to open, like "xxxx.psx",, by default None, means create an empty class
chunk_id (int or str, optional) -- The chunk id or name(label) want to open, by default None, open the first chunk.
raw_img_folder (str, optional) -- the original UAV image folder, by default None
check_img_existance (bool) -- Ignore the missing photos when set to False, suitable for testing project with just a few images, to avoid the 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
Or you can create an empty class and then open project:
>>> 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
注意
One metashape project may have several chunks, and each
easyidp.Metashape
project could only handle with only one chunk at once.The arrow before ID shows which chunk has been opened
<'multichunk.psx' easyidp.Metashape object with 2 active chunks> id label ---- ------------ -> 1 multiple_bbb 2 miltiple_aaa
Methods
__init__
([project_path, chunk_id, ...])The method to initialize the Metashape class
back2raw
(roi[, save_folder])Projects several GIS coordintates ROIs (polygons) to all images
back2raw_crs
(points_xyz[, ignore, log])Projs one GIS coordintates ROI (polygon) to all images
change_photo_folder
(raw_img_folder[, ...])Change the folder path of raw images
get_photo_position
([to_crs, refresh])Get all photos' center geo position (on given CRS)
open_chunk
(chunk_id[, project_path])switch to the other chunk, or chunk in a new project
open_project
(project_path[, chunk_id])Open a new 3D reconstructin project to overwritting current project.
A function to check the original photo path
show_roi_on_img
(img_dict, roi_name[, img_name])Visualize the specific backward projection results for given roi on the given image.
sort_img_by_distance
(img_dict_all, roi[, ...])Advanced wrapper of sorting back2raw img_dict results by distance from photo to roi
Attributes
crs
the geographic coordinates (often the same as the export DOM and DSM),
<class 'pyproj.crs.crs.CRS'>
dom
The output digitial orthomosaic map (DOM),
easyidp.GeoTiff
dsm
The output digitial surface map (DSM),
easyidp.GeoTiff
pcd
The output point cloud,
easyidp.PointCloud
the folder contains the metashape project (.psx) files
the metashape project (file) name.
the chunk that be picked as for easyidp (this class, only deal with one chunk in metashape project)
the folder that contains the origial images
project / chunk name
project meta information
whether this project is activated, (often for Metashape),
<class 'bool'>
the container for all sensors in this project (camera model),
<class 'easyidp.Container'>
, a dict-like object consisted bySensor
the container for all photos used in this project (images),
<class 'easyidp.Container'>
, a dict-like object consisted byPhoto
- back2raw(roi, save_folder=None, **kwargs)#
Projects several GIS coordintates ROIs (polygons) to all images
- パラメータ:
roi (easyidp.ROI | dict) -- the <ROI> object created by easyidp.ROI() or dictionary
save_folder (str, optional) -- the folder to save json files and parts of ROI on raw images, by default None
ignore (str | None, optional) --
Whether tolerate small parts outside image, check
easyidp.reconstruct.Sensor.in_img_boundary()
for more details.None
: strickly in image area;x
: only y (vertical) in image area, x can outside image;y
: only x (horizontal) in image area, y can outside image.
log (bool, optional) -- whether print log for debugging, by default False
サンプル
Data prepare
>>> 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)
Then using this function to do backward projection:
>>> 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()` }
- back2raw_crs(points_xyz, ignore=None, log=False)#
Projs one GIS coordintates ROI (polygon) to all images
- パラメータ:
points_hv (ndarray (nx3)) -- The 3D coordinates of polygon vertexm, in CRS coordinates
ignore (str | None, optional) --
Whether tolerate small parts outside image, check
easyidp.reconstruct.Sensor.in_img_boundary()
for more details.None
: strickly in image area;x
: only y (vertical) in image area, x can outside image;y
: only x (horizontal) in image area, y can outside image.
log (bool, optional) -- whether print log for debugging, by default False
- 戻り値:
a dictionary that key = img_name and values= pixel coordinate
- 戻り値の型:
dict,
サンプル
Data preparation
>>> 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] ... ])
..caution:: specifying the CRS of metashape project (
ms.crs = dsm.crs
) is required before doing backward projection calculationThen use this function to find the previous ROI positions on the raw images:
>>> 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]])
- change_photo_folder(raw_img_folder, check_img_existance=True)#
Change the folder path of raw images
- パラメータ:
raw_img_folder (str | dict) --
The new folder path contains raw image folder.
- If type == str :
replace the root string directly.
- if type == dict(not implemented)
e.g. {'path/to/flight1/': 'new/path/to/flight1', }
check_img_existance (bool) -- Ignore the missing photos when set to False, suitable for testing project with just a few images, to avoid the FileNotFoundError
- chunk_id#
the chunk that be picked as for easyidp (this class, only deal with one chunk in metashape project)
- enabled#
whether this project is activated, (often for Metashape),
<class 'bool'>
- get_photo_position(to_crs=None, refresh=False)#
Get all photos' center geo position (on given CRS)
- パラメータ:
to_crs (pyproj.CRS, optional) -- Transformed to another geo coordinate, by default None, the project.crs
refresh (bool, optional) --
False
: Use cached results (if have), by defaultTrue
: recalculate the photo position
- 戻り値:
The dictionary contains "photo.label": [x, y, z] coordinates
- 戻り値の型:
dict
サンプル
Data prepare
>>> 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)
Then use this function to get the photo position in 3D world:
>>> out = ms.get_photo_position() { 'DJI_0422': array([139.54053245, 35.73458169, 130.09433649]), 'DJI_0423': array([139.54053337, 35.73458315, 129.93437641]), ... }
注意
by default, if not specifying the CRS of metashape project, it will return in default CRS (epsg: 4326) -> (lon, lat, height), if need turn to the same coordinate like DOM/DSM, please specify the CRS first
>>> 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#
project / chunk name
- meta#
project meta information
- open_chunk(chunk_id, project_path=None)#
switch to the other chunk, or chunk in a new project
- パラメータ:
chunk_id (int or str) -- The chunk id or name(label) want to open
project_path (str, optional) -- The new metashape project file to open, like "xxxx.psx",, by default None, means swtich inside current metashape project
サンプル
Data prepare
>>> 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
Then switch from chunk 1 to chunk 4, by id or by label:
>>> 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)#
Open a new 3D reconstructin project to overwritting current project.
- パラメータ:
project_path (str, optional) -- The pix4d project file to open, like "xxxx.psx", or "xxxx" without suffix.
chunk_id (int or str, optional) -- The chunk id or name(label) want to open, by default None, open the first chunk.
サンプル
>>> 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#
the container for all photos used in this project (images),
<class 'easyidp.Container'>
, a dict-like object consisted byPhoto
- 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 bySensor
- show_photo_folder()#
A function to check the original photo path
- show_roi_on_img(img_dict, roi_name, img_name=None, **kwargs)#
Visualize the specific backward projection results for given roi on the given image.
- パラメータ:
img_dict (dict) -- The backward results from back2raw()
roi_name (str) -- The roi name to show
img_name (str) -- the image file name, by default None, plotting all available images
corrected_poly_coord (np.ndarray, optional) -- the corrected 2D polygon pixel coordiante on the image (if have), by default None
title (str, optional) -- The image title displayed on the top, by default None ->
ROI [roi_name] on [img_name]
save_as (str, optional) -- file path to save the output figure, by default None
show (bool, optional) -- whether display (in jupyter notebook) or popup (in command line) the figure, by default False
color (str, optional) -- the polygon line color, by default 'red'
alpha (float, optional) -- the polygon transparency, by default 0.5
dpi (int, optional) -- the dpi of produced figure, by default 72
サンプル
>>> img_dict_ms = roi.back2raw(ms)
Check the "N1W1" ROI on image "DJI_0479.JPG":
>>> ms.show_roi_on_img(img_dict_ms, "N1W1", "DJI_0479")
Check the "N1W1" ROI on all available images:
>>> ms.show_roi_on_img(img_dict_ms, "N1W1")
For more details, please check in this example
- sort_img_by_distance(img_dict_all, roi, distance_thresh=None, num=None, save_folder=None)#
Advanced wrapper of sorting back2raw img_dict results by distance from photo to roi
- パラメータ:
img_dict_all (dict) -- All output dict of roi.back2raw(...) e.g. img_dict = roi.back2raw(...) -> img_dict
roi (idp.ROI) -- Your roi variable
num (None or int) -- Keep the closest {x} images
distance_thresh (None or float) -- Keep the images closer than this distance to ROI.
save_folder (str, optional) -- the folder to save json files and parts of ROI on raw images, by default None
- 戻り値:
the same structure as output of roi.back2raw(...)
- 戻り値の型:
dict
サンプル
In the previous
back2raw()
results :>>> 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()` }
The image are in chaos order, in most application cases, probable only 1-3 closest images (to ROI in real world) are required, so this function is provided to sort/filter out.
In the following example, it filtered 3 images whose distance from camera to ROI in real world smaller than 10m:
>>> 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]]) } }
Or pick the closest one image:
>>> 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]]) } }
You can use
list(dict.keys())[0]
to get the image name automatically to iterate each plot: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]