Forum

Author Topic: Python script to make shapes and assign to cameras to show on orthophoto  (Read 1744 times)

arpit.p

  • Newbie
  • *
  • Posts: 6
    • View Profile
I have a excel file where I have pixel cordinate for every image where I want to make a point on.
I am able to do this manually.
photo >> draw point >> label

after this the point show in photo and orthomosaic as well.

i want to do this through python script. I am able to make all the shapes but they are not assigned to particular cameras.
Can you help me with this..?

```
import Metashape
import xlrd
doc = Metashape.app.document
chunk = doc.chunk
#shape = chunk.shapes.addShape()
chunk.shapes = Metashape.Shapes()
excel_file = "C:/Users/admin/Desktop/testcount.xlsx"
workbook = xlrd.open_workbook(excel_file)
sheet = workbook.sheet_by_index(0)  # Assuming the coordinates are in the first sheet
for row in range(1, sheet.nrows):  # Start from row 1 to skip the header
    photo_name = sheet.cell_value(row, 1)  # Assuming the photo names are in the first column
    x = sheet.cell_value(row, 2)  # Assuming the X coordinates are in the second column
    y = sheet.cell_value(row, 3)  # Assuming the Y coordinates are in the third column
    photo = next((p for p in chunk.cameras if p.label == photo_name), None)
    if photo:
     print(photo)
     chunk.shapes.crs = chunk.crs
     shape = chunk.shapes.addShape()
     shape.geometry = Metashape.Geometry.Point([x,y])

Paulo

  • Hero Member
  • *****
  • Posts: 1273
    • View Profile
Hello,

what you get from the excel file are pixel coordinates of each point on its corresponding photo. So you need to transform these coordinates to the chunk.crs coordinates. To do this, use surface.pickPoint method to find the projected pixel coordinates on the reconstructed surface, either surface = chunk.model or surface = chunk.point_cloud

So point on surface would be:

 P = surface.pickPoint(photo.center,photo.unproject(ps.Vector((x,y)))) ; point P on surface corresponding to x,y pixel coordinates on photo in internal Coordinats

To get coordinates in chunk.crs coordinates you do:

chunk.crs.project(T.mulp(P)) where T = chunk.transform.matrix

So to add point to shapes you do:

shape.geometry = Metashape.Geometry.Point(chunk.crs.project(T.mulp(P)))

This hopefully will get you going...
« Last Edit: June 10, 2023, 01:48:58 PM by Paulo »
Best Regards,
Paul Pelletier,
Surveyor

arpit.p

  • Newbie
  • *
  • Posts: 6
    • View Profile
HI
Thanks For the reply.

Actually you're right And I found out getting projected pixel cordinates from model is having a shift from actual point.
So,
I have to add a marker in photo through script in every photo it comes, so it automatically regenerates the point in 3D.

```
Editing
125
2. Select Draw Point / Draw Polyline / Draw Polygon instrument from the toolbar.
3. Draw a point/polyline/polygon on the DEM/orthomosaic/model with a cursor. By default the shape
vertex will be put on the available surface, however, in Metashape is it possible to draw the shapes
on a given plane (for example, at a certain height). To set up the drawing plane, select polyline or
polygon shape with three or more vertices or three markers placed in 3D. Then right click on the
selection and choose Set Drawing Plane command from the context menu. To reset Drawing Plane
select the corresponding command from the context menu.
4. Double click on the last point to indicate the end of a polyline. To complete a polygon, place the end
point over the starting one.
5. Once the shape is drawn, a shape label will be added to the chunk data structure on the Workspace
pane. All shapes drawn on the same model (and on the corresponding DEM and orthomosaic) will
be shown under the same label on the Workspace pane.
6. The program will switch to a navigation mode once a shape is completed.
Drawing shapes in 3D (on the model) solves issues with building basements and other features which are
not visible on the orthomosaic. However, drawing on a model might not be accurate enough. For this case
Metashape offers possibility to draw a shape on source photos and automatically reconstruct it in 3D.
To automatically reconstruct a shape in 3D
1. Enable Attach markers option available in Markers submenu of Tools menu.
2. Open a photo in Photo view double clicking on the photo thumbnail in the Photo pane.
3. Select Draw Point / Draw Polyline / Draw Polygon instrument from the toolbar.
4. Draw a point/polyline/polygon on the photo with a cursor.
5. Double click on the last point to indicate the end of a polyline. To complete a polygon, place the end
point over the starting one. All the vertices will be indicated with markers.
6. Switch to Model view to see that the shape has been reconstructed in 3D automatically.
7. To refine the position of the shape, filter photos by shape using the corresponding command from the
shape context menu. The shape must be selected - to select a shape double click on it.
8. Inspect all the relevant photos to refine markers-vertices positions where necessary. The position of
the shape in 3D will automatically be refined.
```

Can you help me in making a script to this manual process mentioned in Metashape Manual.
« Last Edit: June 11, 2023, 11:49:47 AM by arpit.p »

arpit.p

  • Newbie
  • *
  • Posts: 6
    • View Profile
Hello,

what you get from the excel file are pixel coordinates of each point on its corresponding photo. So you need to transform these coordinates to the chunk.crs coordinates. To do this, use surface.pickPoint method to find the projected pixel coordinates on the reconstructed surface, either surface = chunk.model or surface = chunk.point_cloud

So point on surface would be:

 P = surface.pickPoint(photo.center,photo.unproject(ps.Vector((x,y)))) ; point P on surface corresponding to x,y pixel coordinates on photo in internal Coordinats

To get coordinates in chunk.crs coordinates you do:

chunk.crs.project(T.mulp(P)) where T = chunk.transform.matrix

So to add point to shapes you do:

shape.geometry = Metashape.Geometry.Point(chunk.crs.project(T.mulp(P)))

This hopefully will get you going...

Thanks!
These suggestions worked.
But There's a shift from the actual position of the pixels and feedback I'm getting after making the shape.
I read about it and I found I've to refine position from multiple position in which the shape exists.
Can you give me an example of this

Paulo

  • Hero Member
  • *****
  • Posts: 1273
    • View Profile
Hello arpit.p,

I would ask you what is the version you are using? 1.8 r 2.0? My procedure works with 2.0. What is the surface you have? point_cloud or model?

Attached example where I place a point in photo on top of barbecue chimney and where it lands on the point_cloud (dense_cloud in v. 1.8)...
Best Regards,
Paul Pelletier,
Surveyor

arpit.p

  • Newbie
  • *
  • Posts: 6
    • View Profile
Thanks Paulo!
Version - 1.8.3

The script works fine. But a little shift is there.
I've given the pixels of red point but actual point come with some shift.
I've noticed if the point is near to center then it's more accurate.

But If i select points manually anywhere, it does come very accurate.
« Last Edit: June 12, 2023, 08:03:04 AM by arpit.p »

Paulo

  • Hero Member
  • *****
  • Posts: 1273
    • View Profile
Hello,

Ok, if you are using 1.8 then to define the surface as dense_cloud (in 2.0 named point_cloud) then you must use
Code: [Select]
surface = chunk.dense_cloudas in 1.8 chunk.point_cloud defines the sparse point cloud or tie points and pickPoint will not be precise...

Try it it should give precise results...
Best Regards,
Paul Pelletier,
Surveyor

arpit.p

  • Newbie
  • *
  • Posts: 6
    • View Profile
Thanks !!
It worked.