Forum

Author Topic: Python scripts collection?  (Read 88047 times)

bisenberger

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • Digital Mapping & Graphics
Re: Python scripts collection?
« Reply #15 on: January 25, 2016, 03:17:10 PM »
Hello Bill,

Python API reference can be found here:
http://www.agisoft.com/downloads/user-manuals/

The options for the dense cloud quality are the following:
PhotoScan.Quality.UltraQuality
PhotoScan.Quality.HighQuality
PhotoScan.Quality.MediumQuality
PhotoScan.Quality.LowQuality
PhotoScan.Quality.LowestQuality
Thanks Alexey
Digital Mapping & Graphics LLC
https://digital-mapping.net/

bisenberger

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • Digital Mapping & Graphics
Re: Python scripts collection?
« Reply #16 on: January 25, 2016, 03:36:55 PM »
I'm getting the following error when I run Split in chunks.py:

2016-01-25 06:24:47 Traceback (most recent call last):
2016-01-25 06:24:47   File "E:/Photoscan/scripts/Split in chunks.py", line 80, in <lambda>
2016-01-25 06:24:47     proc_split = lambda : self.splitChunks()
2016-01-25 06:24:47   File "E:/Photoscan/scripts/Split in chunks.py", line 159, in splitChunks
2016-01-25 06:24:47     doc.addChunk(new_chunk)
2016-01-25 06:24:47 TypeError: addChunk() takes no arguments (1 given)
>>>

PhotoScan version 1.2.3
Digital Mapping & Graphics LLC
https://digital-mapping.net/

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Python scripts collection?
« Reply #17 on: January 25, 2016, 03:54:46 PM »
Hello Bill,

You need to comment that line - doc.addChunk(new_chunk), as chunk.copy() operation automatically creates chunk duplicate in the document.
Best regards,
Alexey Pasumansky,
Agisoft LLC

gatsri

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
Re: Python scripts collection?
« Reply #18 on: February 01, 2016, 09:33:46 AM »
Dear Alexey

Can you please poste the actual "split in chuncs"-Script. for me it does not work with comment that line..:-/

Thank you

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Python scripts collection?
« Reply #19 on: February 01, 2016, 11:00:48 AM »
Hello ristag,

Which version of PhotoScan you are using? If you are no 1.2, then it should work without commenting or uncommenting anything.
Best regards,
Alexey Pasumansky,
Agisoft LLC

bisenberger

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • Digital Mapping & Graphics
Re: Python scripts collection?
« Reply #20 on: March 10, 2016, 09:32:58 PM »
Hello Bill,

Python API reference can be found here:
http://www.agisoft.com/downloads/user-manuals/

The options for the dense cloud quality are the following:
PhotoScan.Quality.UltraQuality
PhotoScan.Quality.HighQuality
PhotoScan.Quality.MediumQuality
PhotoScan.Quality.LowQuality
PhotoScan.Quality.LowestQuality
http://wiki.agisoft.com/wiki/Split_in_chunks.py
Also handy variables for modifying the Split_in_chunks script:
PhotoScan.FilterMode.AggressiveFiltering
PhotoScan.FilterMode.ModerateFiltering
PhotoScan.FilterMode.MildFiltering
PhotoScan.FilterMode.NoFiltering
« Last Edit: March 10, 2016, 09:39:37 PM by bisenberger »
Digital Mapping & Graphics LLC
https://digital-mapping.net/

enocsanz

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Python scripts collection?
« Reply #21 on: May 11, 2016, 03:01:37 PM »
Error

jpvega

  • Newbie
  • *
  • Posts: 10
    • View Profile

Ryan Fox

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Python scripts collection?
« Reply #23 on: June 24, 2017, 12:19:45 AM »
Is there still interest in a repository of scripts?  I'd be willing to maintain it.  I set up a repo here: https://github.com/FoxRow/Agisoft-Scripting

I can pull in the scripts already in http://wiki.agisoft.com/wiki/Python.  If we get a critical mass, it would be nice to release it as a companion package on PyPI.  I don't see any license on the scripts already in the wiki, does maybe someone from Agisoft know their provenance?  I'd like to have a coherent license for the repository in that case.

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Python scripts collection?
« Reply #24 on: October 17, 2017, 07:51:27 PM »
Hello all,

We have moved the scripts from Wiki to GitHub repository, so that it should be easier to contribute for the community:
https://github.com/agisoft-llc/photoscan-scripts
Best regards,
Alexey Pasumansky,
Agisoft LLC

SAV

  • Hero Member
  • *****
  • Posts: 710
    • View Profile
Re: Python scripts collection?
« Reply #25 on: November 01, 2017, 03:45:30 AM »
Good to see that it has been moved to GitHub.
 ;D

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Python scripts collection?
« Reply #26 on: November 01, 2017, 11:32:47 AM »
Now it should be easier for community to contribute.

We are also trying to update the collection with the commonly requested scripts.
Best regards,
Alexey Pasumansky,
Agisoft LLC

chrisodiachi

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Python scripts collection?
« Reply #27 on: February 14, 2019, 12:10:09 PM »
please can anyone be kind enough to assist me debug this script


# This is python script for Metashape Pro. Scripts repository: https://github.com/agisoft-llc/metashape-scripts

import Metashape
from PySide2 import QtGui, QtCore, QtWidgets

# Checking compatibility
compatible_major_version = "1.5"
found_major_version = ".".join(Metashape.app.version.split('.')[:2])
if found_major_version != compatible_major_version:
   raise Exception("Incompatible Metashape version: {} != {}".format(found_major_version, compatible_major_version))

QUALITY = {"1":  Metashape.UltraQuality,
         "2":  Metashape.HighQuality,
         "4":  Metashape.MediumQuality,
         "8":  Metashape.LowQuality,
         "16": Metashape.LowestQuality}

FILTERING = {"3": Metashape.NoFiltering,
          "0": Metashape.MildFiltering,
          "1": Metashape.ModerateFiltering,
          "2": Metashape.AggressiveFiltering}

MESH = {"Arbitrary": Metashape.SurfaceType.Arbitrary,
      "Height Field": Metashape.SurfaceType.HeightField}

DENSE = {"Ultra": Metashape.UltraQuality,
       "High": Metashape.HighQuality,
       "Medium": Metashape.MediumQuality,
       "Low": Metashape.LowQuality,
       "Lowest": Metashape.LowestQuality}


def isIdent(matrix):
   """
   Check if the matrix is identity matrix
   """
   for i in range(matrix.size[0]):
      for j in range(matrix.size[1]):
         if i == j:
            if matrix[i, j] != 1.0:
               return False
         elif matrix[i, j]:
            return False
   return True


class SplitDlg(QtWidgets.QDialog):

   def __init__(self, parent):

      QtWidgets.QDialog.__init__(self, parent)
      self.setWindowTitle("Split in chunks")

      self.gridX = 2
      self.gridY = 2
      self.gridWidth = 198
      self.gridHeight = 198

      self.spinX = QtWidgets.QSpinBox()
      self.spinX.setMinimum(1)
      self.spinX.setValue(2)
      self.spinX.setMaximum(20)
      self.spinX.setFixedSize(75, 25)
      self.spinY = QtWidgets.QSpinBox()
      self.spinY.setMinimum(1)
      self.spinY.setValue(2)
      self.spinY.setMaximum(20)
      self.spinY.setFixedSize(75, 25)

      self.chkMesh = QtWidgets.QCheckBox("Build Mesh")
      self.chkMesh.setFixedSize(100, 50)
      self.chkMesh.setToolTip("Generates mesh for each cell in grid")

      self.meshBox = QtWidgets.QComboBox()
      for element in MESH.keys():
         self.meshBox.addItem(element)
      self.meshBox.setFixedSize(100, 25)

      self.chkDense = QtWidgets.QCheckBox("Build Dense Cloud")
      self.chkDense.setFixedSize(120, 50)
      self.chkDense.setWhatsThis("Builds dense cloud for each cell in grid")

      self.denseBox = QtWidgets.QComboBox()
      for element in DENSE.keys():
         self.denseBox.addItem(element)
      self.denseBox.setFixedSize(100, 25)

      self.chkMerge = QtWidgets.QCheckBox("Merge Back")
      self.chkMerge.setFixedSize(90, 50)
      self.chkMerge.setToolTip("Merges back the processing products formed in the individual cells")

      self.chkSave = QtWidgets.QCheckBox("Autosave")
      self.chkSave.setFixedSize(90, 50)
      self.chkSave.setToolTip("Autosaves the project after each operation")

      self.txtOvp = QtWidgets.QLabel()
      self.txtOvp.setText("Overlap (%):")
      self.txtOvp.setFixedSize(90, 25)

      self.edtOvp = QtWidgets.QLineEdit()
      self.edtOvp.setPlaceholderText("0")
      self.edtOvp.setFixedSize(50, 25)

      self.btnQuit = QtWidgets.QPushButton("Close")
      self.btnQuit.setFixedSize(90, 50)

      self.btnP1 = QtWidgets.QPushButton("Split")
      self.btnP1.setFixedSize(90, 50)

      self.grid = QtWidgets.QLabel(" ")
      self.grid.resize(self.gridWidth, self.gridHeight)
      tempPixmap = QtGui.QPixmap(self.gridWidth, self.gridHeight)
      tempImage = tempPixmap.toImage()

      for y in range(self.gridHeight):
         for x in range(self.gridWidth):

            if not (x and y) or (x == self.gridWidth - 1) or (y == self.gridHeight - 1):
               tempImage.setPixel(x, y, QtGui.qRgb(0, 0, 0))
            elif (x == self.gridWidth / 2) or (y == self.gridHeight / 2):
               tempImage.setPixel(x, y, QtGui.qRgb(0, 0, 0))

            else:
               tempImage.setPixel(x, y, QtGui.qRgb(255, 255, 255))

      tempPixmap = tempPixmap.fromImage(tempImage)
      self.grid.setPixmap(tempPixmap)
      self.grid.show()

      layout = QtWidgets.QGridLayout()  # creating layout
      layout.addWidget(self.spinX, 1, 0)
      layout.addWidget(self.spinY, 1, 1, QtCore.Qt.AlignRight)

      layout.addWidget(self.chkDense, 0, 2)
      layout.addWidget(self.chkMesh, 0, 3)
      layout.addWidget(self.chkMerge, 0, 4)

      layout.addWidget(self.meshBox, 1, 3, QtCore.Qt.AlignTop)
      layout.addWidget(self.denseBox, 1, 2, QtCore.Qt.AlignTop)

      layout.addWidget(self.chkSave, 3, 2)
      layout.addWidget(self.btnP1, 3, 3)
      layout.addWidget(self.btnQuit, 3, 4)

      layout.addWidget(self.txtOvp, 0, 0, QtCore.Qt.AlignRight)
      layout.addWidget(self.edtOvp, 0, 1, QtCore.Qt.AlignLeft)

      layout.addWidget(self.grid, 2, 0, 2, 2)
      # layout.setAlignment(QtCore.Qt.AlignTop)
      self.setLayout(layout)

      proc_split = lambda: self.splitChunks()

      self.spinX.valueChanged.connect(self.updateGrid)
      self.spinY.valueChanged.connect(self.updateGrid)

      QtCore.QObject.connect(self.btnP1, QtCore.SIGNAL("clicked()"), proc_split)
      QtCore.QObject.connect(self.btnQuit, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("reject()"))

      self.exec()

   def updateGrid(self):
      """
      Draw new grid
      """

      self.gridX = self.spinX.value()
      self.gridY = self.spinY.value()

      tempPixmap = QtGui.QPixmap(self.gridWidth, self.gridHeight)
      tempImage = tempPixmap.toImage()
      tempImage.fill(QtGui.qRgb(240, 240, 240))

      for y in range(int(self.gridHeight / self.gridY) * self.gridY):
         for x in range(int(self.gridWidth / self.gridX) * self.gridX):
            if not (x and y) or (x == self.gridWidth - 1) or (y == self.gridHeight - 1):
               tempImage.setPixel(x, y, QtGui.qRgb(0, 0, 0))
            elif y > int(self.gridHeight / self.gridY) * self.gridY:
               tempImage.setPixel(x, y, QtGui.qRgb(240, 240, 240))
            elif x > int(self.gridWidth / self.gridX) * self.gridX:
               tempImage.setPixel(x, y, QtGui.qRgb(240, 240, 240))
            else:
               tempImage.setPixel(x, y, QtGui.qRgb(255, 255, 255))

      for y in range(0, int(self.gridHeight / self.gridY + 1) * self.gridY, int(self.gridHeight / self.gridY)):
         for x in range(int(self.gridWidth / self.gridX) * self.gridX):
            tempImage.setPixel(x, y, QtGui.qRgb(0, 0, 0))

      for x in range(0, int(self.gridWidth / self.gridX + 1) * self.gridX, int(self.gridWidth / self.gridX)):
         for y in range(int(self.gridHeight / self.gridY) * self.gridY):
            tempImage.setPixel(x, y, QtGui.qRgb(0, 0, 0))

      tempPixmap = tempPixmap.fromImage(tempImage)
      self.grid.setPixmap(tempPixmap)
      self.grid.show()

      return True

   def splitChunks(self):

      self.gridX = self.spinX.value()
      self.gridY = self.spinY.value()
      partsX = self.gridX
      partsY = self.gridY

      print("Script started...")

      buildMesh = self.chkMesh.isChecked()
      buildDense = self.chkDense.isChecked()
      mergeBack = self.chkMerge.isChecked()
      autosave = self.chkSave.isChecked()

      quality = DENSE[self.denseBox.currentText()]
      mesh_mode = MESH[self.meshBox.currentText()]

      doc = Metashape.app.document
      chunk = doc.chunk

      if not chunk.transform.translation.norm():
         chunk.transform.matrix = chunk.transform.matrix
      elif chunk.transform.scale == 1:
         chunk.transform.matrix = chunk.transform.matrix
      elif isIdent(chunk.transform.rotation):
         chunk.transform.matrix = chunk.transform.matrix

      region = chunk.region
      r_center = region.center
      r_rotate = region.rot
      r_size = region.size

      x_scale = r_size.x / partsX
      y_scale = r_size.y / partsY
      z_scale = r_size.z

      offset = r_center - r_rotate * r_size / 2.
      
      chunk_labels = [ichunk.label for ichunk in PhotoScan.app.document.chunks]
      if  "Chunk " + str(i) + "_" + str(j) in chunk_labels:
         continue
      
      for j in range(1, partsY + 1):  # creating new chunks and adjusting bounding box
         for i in range(1, partsX + 1):
            if not buildDense:
               new_chunk = chunk.copy(items=[Metashape.DataSource.DenseCloudData, Metashape.DataSource.DepthMapsData])
            else:
               new_chunk = chunk.copy(items=[])
            new_chunk.label = "Chunk " + str(i) + "_" + str(j)
            if new_chunk.model:
               new_chunk.model.clear()

            new_region = Metashape.Region()
            new_rot = r_rotate
            new_center = Metashape.Vector([(i - 0.5) * x_scale, (j - 0.5) * y_scale, 0.5 * z_scale])
            new_center = offset + new_rot * new_center
            new_size = Metashape.Vector([x_scale, y_scale, z_scale])

            if self.edtOvp.text().isdigit():
               new_region.size = new_size * (1 + float(self.edtOvp.text()) / 100)
            else:
               new_region.size = new_size

            new_region.center = new_center
            new_region.rot = new_rot

            new_chunk.region = new_region

            Metashape.app.update()

            if autosave:
               doc.save()

            if buildDense:
               if new_chunk.depth_maps:
                  reuse_depth = True
                  if new_chunk.depth_maps.meta['depth/depth_downscale']:
                     quality = QUALITY[new_chunk.depth_maps.meta['depth/depth_downscale']]
                  if new_chunk.depth_maps.meta['depth/depth_filter_mode']:
                     filtering = FILTERING[new_chunk.depth_maps.meta['depth/depth_filter_mode']]
                  try:
                     new_chunk.buildDepthMaps(quality=quality, filter=filtering, reuse_depth=reuse_depth)
                     new_chunk.buildDenseCloud(max_neighbors=100)  # keep_depth=False
                  except RuntimeError:
                     print("Can't build dense cloud for " + chunk.label)

               else:
                  reuse_depth = False
                  try:
                     new_chunk.buildDepthMaps(quality=quality,
                                        filter=Metashape.FilterMode.ModerateFiltering, reuse_depth=reuse_depth)
                     new_chunk.buildDenseCloud(max_neighbors=100)  # keep_depth=False
                  except RuntimeError:
                     print("Can't build dense cloud for " + chunk.label)

               if autosave:
                  doc.save()

            if buildMesh:
               if new_chunk.dense_cloud:
                  try:
                     new_chunk.buildModel(surface=mesh_mode,
                                     source=Metashape.DataSource.DenseCloudData,
                                     interpolation=Metashape.Interpolation.EnabledInterpolation,
                                     face_count=Metashape.FaceCount.HighFaceCount)
                  except RuntimeError:
                     print("Can't build mesh for " + chunk.label)
               else:
                  try:
                     new_chunk.buildModel(surface=mesh_mode,
                                     source=Metashape.DataSource.PointCloudData,
                                     interpolation=Metashape.Interpolation.EnabledInterpolation,
                                     face_count=Metashape.FaceCount.HighFaceCount)
                  except RuntimeError:
                     print("Can't build mesh for " + chunk.label)
               if autosave:
                  doc.save()

            if not buildDense:
               if new_chunk.dense_cloud:
                  new_chunk.dense_cloud.clear()
            if new_chunk.depth_maps:
               new_chunk.depth_maps.clear()
            # new_chunk = None

      if mergeBack:
         for i in range(1, len(doc.chunks)):
            chunk = doc.chunks
            chunk.remove(chunk.cameras)
         doc.chunks[0].model = None  # hiding the mesh of the original chunk, just for case
         doc.mergeChunks(doc.chunks,
                     merge_dense_clouds=True, merge_models=True, merge_markers=True)  # merging all smaller chunks into single one

         doc.remove(doc.chunks[1:-1])  # removing smaller chunks.
         if autosave:
            doc.save()

      if autosave:
         doc.save()

      print("Script finished!")
      return True


def split_in_chunks():
   global doc
   doc = Metashape.app.documenthttps://www.sublimetext.com/2

   app = QtWidgets.QApplication.instance()
   parent = app.activeWindow()

   dlg = SplitDlg(parent)


label = "Custom menu/Split in chunks"
Metashape.app.addMenuItem(label, split_in_chunks)
print("To execute this script press {}".format(label))



it is the split in chunk script with 3 added lines above line 237 to resume the operation after a power failure. I cannot seem to debug it. Please help!!!!

bisenberger

  • Sr. Member
  • ****
  • Posts: 329
    • View Profile
    • Digital Mapping & Graphics
Re: Python scripts collection?
« Reply #28 on: April 17, 2020, 10:06:07 PM »
Python scripts for Metashape Pro
https://github.com/agisoft-llc/metashape-scripts


How to run Python script automatically on Metashape Professional start
https://agisoft.freshdesk.com/support/solutions/articles/31000133123-how-to-run-python-script-automatically-on-metashape-professional-start

Very useful  :), thanks.
Digital Mapping & Graphics LLC
https://digital-mapping.net/

Kjellis85

  • Full Member
  • ***
  • Posts: 220
  • Archaeological field supervisor
    • View Profile
    • Contact information at University of Tromsø
Re: Python scripts collection?
« Reply #29 on: March 09, 2021, 10:57:17 AM »
+1 great reasource!