Hi matt07lx,
as Marcel mentioned before we use the following script for Metashape 1.5.3. and it works fine.
We hope that it´s usefull for you.
Best regards,
Florian
"""
/********************************************************************************************************************
OPEX - Orthophotoexport (V. 2.0)
Content:
Processing code to exports orthophoto in planar projection defined by vektor (from three markers) and Z axes.
This code is mainly for exporting archaeological profiles; ready for importing in GIS.
Before using the script you need:
- A georeferenzed Model
- An "A" and "B" Profile Nail (Named "A" and "B" in Photoscan)
- A "Y" Point in Photoscan with the coordinates (X-coord from "A",Y-coord from "A", Z-coord from "A"+ a high number)
Compatibility - Metashape Professional 1.5.3
Version - 2.0
-------------------
written by : Alexey Pasumansky, AgiSoft LLC,
Marcel C. Hagner, ArchaeoBW GmbH
Florian Tubbesing, ArchaeoBW GmbH
copyright : 2019 ArchaeoBW GmbH
email : info@archaeobw.de
********************************************************************************************************************/
/*************************************************************************************
* This program is free software; you can redistribute it and/or modify it under *
* the terms of a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 *
* International License. *
* *
* Attribution - You must give a appropriate credit, provide a link to the license, *
* and indicate of changes were made. You may do so in any reasonable manner, but *
* not in any way that suggests the licensor endorses you or your use *
* *
* NonCommercial - You may not use the material for commercial purposes. *
* *
* ShareAlike - If you remix, transform, or build upon the material, you must *
* distribute your contributions under the same license as the original. *
*************************************************************************************/
"""
import os
import Metashape
from PySide2 import QtCore, QtWidgets
def getMarker(chunk, label):
for marker in chunk.markers:
if marker.label.upper() == label.upper():
return marker
return 0
def vect(a, b):
result = Metashape.Vector([a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y *b.x])
return result.normalized()
class ExportOFDlg(QtWidgets.QDialog):
def __init__ (self, parent):
QtWidgets.QDialog.__init__(self, parent)
chunk = doc.chunk
self.supported_types = ["jpg", "tif", "png"]
self.blending = Metashape.BlendingMode.AverageBlending
self.setWindowTitle("OPEX")
self.btnQuit = QtWidgets.QPushButton("&Exit")
self.btnQuit.setFixedSize(150,50)
self.btnP1 = QtWidgets.QPushButton("&Export")
self.btnP1.setFixedSize(150,50)
self.resTxt = QtWidgets.QLabel()
self.resTxt.setText("Export resolution (m):")
self.resTxt.setFixedSize(150, 25)
self.vectTxt = QtWidgets.QLabel()
self.vectTxt.setText("Horizontal vector:")
self.vectTxt.setFixedSize(150, 25)
self.vect2Txt = QtWidgets.QLabel()
self.vect2Txt.setText("Vertical vector:")
self.vect2Txt.setFixedSize(150, 25)
self.resEdt = QtWidgets.QLineEdit()
self.resEdt.setText("0.00025")
self.resEdt.setFixedSize(150, 25)
self.radioBtn_v = QtWidgets.QRadioButton("Vertical")
self.radioBtn_h = QtWidgets.QRadioButton("Horizontal")
self.radioBtn_v.setChecked(True)
self.radioBtn_h.setChecked(False)
self.llistV = [None, None]
self.llistV[0] = QtWidgets.QComboBox()
self.llistV[0].resize(150, 30)
self.llistV[1] = QtWidgets.QComboBox()
self.llistV[1].resize(150, 30)
self.llistH = [None, None]
self.llistH[0] = QtWidgets.QComboBox()
self.llistH[0].resize(150, 30)
self.llistH[1] = QtWidgets.QComboBox()
self.llistH[1].resize(150, 30)
self.radio = QtWidgets.QVBoxLayout()
self.radio.addWidget(self.radioBtn_v)
self.radio.addWidget(self.radioBtn_h)
for marker in chunk.markers:
for ilist in self.llistV:
ilist.addItem(marker.label)
for ilist in self.llistH:
ilist.addItem(marker.label)
layout = QtWidgets.QGridLayout() #creating layout
layout.setSpacing(10)
layout.addWidget(self.resTxt, 0, 0)
layout.addWidget(self.resEdt, 0, 1)
layout.addWidget(self.vectTxt, 1, 0)
layout.addWidget(self.vect2Txt, 2, 0)
layout.addWidget(self.llistH[0], 1, 1)
layout.addWidget(self.llistH[1], 1, 2)
layout.addWidget(self.llistV[0], 2, 1)
layout.addWidget(self.llistV[1], 2, 2)
layout.addLayout(self.radio, 3, 0)
layout.addWidget(self.btnP1, 3, 1)
layout.addWidget(self.btnQuit, 3, 2)
self.setLayout(layout)
proc_export = lambda : self.procExport()
QtCore.QObject.connect(self.btnP1, QtCore.SIGNAL("clicked()"), proc_export)
QtCore.QObject.connect(self.btnQuit, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("reject()"))
self.exec()
def procExport(self):
chunk = doc.chunk
path = Metashape.app.getExistingDirectory("Bitte wählen Sie den Ordner mit den gesammelten Geo-Cut-Modell aus")
crs = Metashape.app.getCoordinateSystem("Wählen Sie das Koordinatensystem für die Ausgabe aus.", )
filelist = os.listdir(path)
doclist = list()
for file in filelist:
if file[-3:].upper() == "PSX":
doclist.append(path + "\\" + file)
try:
d_x = d_y = float(self.resEdt.text())
except(ValueError):
Metashape.app.messageBox("Incorrect export resolution! Please use point delimiter.\n")
print("Script aborted.")
return 0
if self.llistV[0].currentIndex() == self.llistV[1].currentIndex():
Metashape.app.messageBox("Can't use the same marker for vector start and end.\n")
print("Script aborted.")
return 0
if self.llistH[0].currentIndex() == self.llistH[1].currentIndex():
Metashape.app.messageBox("Can't use the same marker for vector start and end.\n")
print("Script aborted.")
return 0
if len(chunk.markers) < 2:
Metashape.app.messageBox("No markers.\n")
print("Script aborted.")
return 0
print("Skript startet...")
type = "_OF.tif"
for doc_path in doclist:
#try:
doc_unlock = Metashape.Document()
doc_unlock.open(doc_path, read_only=True)
doc_unlock.read_only = False
doc.open(doc_path, read_only=False)
chunk = doc.chunk
chunk.crs=crs
T = chunk.transform.matrix
path = doc_path[:-4] + type
self.btnP1.setDisabled(True)
self.btnQuit.setDisabled(True)
m1 = getMarker(chunk, self.llistH[0].currentText())
m2 = getMarker(chunk, self.llistH[1].currentText())
horizontal = m2.position - m1.position
horizontal = T.mulv(horizontal)
m1 = getMarker(chunk, self.llistV[0].currentText())
m2 = getMarker(chunk, self.llistV[1].currentText())
vertical = m2.position - m1.position
vertical = T.mulv(vertical)
normal = vect(vertical, horizontal)
if self.radioBtn_h.isChecked():
vertical = vect(horizontal, normal)
horizontal = horizontal.normalized()
elif self.radioBtn_v.isChecked():
vertical = vertical.normalized()
horizontal = -vect(vertical, normal)
#horizontal, vertical = -vertical, -horizontal
else:
Metashape.app.messageBox("Fehler!Kann das OF nicht exportieren" + path)
print("Skript wird abgebrochen.")
continue
m = -1
for marker in chunk.markers:
m += 1
label = marker.label
if "A" in label:
a = m
R = Metashape.Matrix ([horizontal, vertical, -normal])
origin = T.mulp(chunk.markers[a].position)
A = m1.reference.location * Metashape.Vector([0,0,1]) #A ist der Höhenwert von m1
X = (-1) * R * origin
horizontal.size = 4
horizontal.w = X.x
vertical.size = 4
vertical.w = X.y + A # hier wird A hinzuaddiert
normal.size = 4
normal.w = -X.z
proj = Metashape.Matrix ([horizontal, vertical, -normal, Metashape.Vector([0,0,0,1])])
if doc.path[-3:].lower() != "psx": #saving in PSX required to build orthomosaic
doc.save(doc.path[:-3] + "psx")
chunk = doc.chunk
chunk.buildOrthomosaic(surface = Metashape.DataSource.ModelData, blending = self.blending, fill_holes=True, projection = proj, dx = d_x, dy = d_y)
doc.save()
chunk.exportOrthomosaic(path, dx = d_x, dy = d_y)
self.btnP1.setDisabled(False)
self.btnQuit.setDisabled(False)
Metashape.app.update()
#print("Orthofoto wird exportiert nach to:\n" + path)
#except:
#continue
print("Skript rum.Viele Grüße MP & FT")
print()
return 1
def main():
global doc
doc = Metashape.app.document
app = QtWidgets.QApplication.instance()
parent = app.activeWindow()
dlg = ExportOFDlg(parent)
Metashape.app.addMenuItem("ArchaeoBW Toolbox/Profile/OPEX/OPEX ab 1.5.3", main)