# Compatibility - PhotoScan Professional 1.1.0 # exports orthophoto in planar projection defined by vector (azimuth from XZ plane) and Z axes. # script version 1.4 # Written and provided by Agisoft LLC import PhotoScan, math from PySide import QtCore, QtGui def vect(a, b): result = PhotoScan.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 ExportDlg(QtGui.QDialog): def __init__ (self, parent): QtGui.QDialog.__init__(self, parent) chunk = doc.chunk self.supported_types = ["jpg", "tif", "png"] self.blending_types =["mosaic", "average"] self.setWindowTitle("Export orthophoto in planar projection") self.btnQuit = QtGui.QPushButton("&Exit") self.btnQuit.setFixedSize(150,50) self.btnP1 = QtGui.QPushButton("&Export") self.btnP1.setFixedSize(150,50) self.resTxt = QtGui.QLabel() self.resTxt.setText("Export resolution (m):") self.resTxt.setFixedSize(150, 25) self.rotTxt = QtGui.QLabel() self.rotTxt.setText("Azimuth rotation (deg):") self.rotTxt.setFixedSize(150, 25) self.blendTxt = QtGui.QLabel() self.blendTxt.setText("Blending mode:") self.blendTxt.setFixedSize(150, 25) self.rotEdt = QtGui.QLineEdit() self.rotEdt.setPlaceholderText("type in rotation angle, e.g 30.5") self.rotEdt.setFixedSize(150, 25) self.resEdt = QtGui.QLineEdit() self.resEdt.setPlaceholderText("type in export resolution, e.g 0.01") self.resEdt.setFixedSize(150, 25) self.blendCmb = QtGui.QComboBox() #texture type values self.blendCmb.setFixedSize(150, 25) for type in self.blending_types: self.blendCmb.addItem(type) layout = QtGui.QGridLayout() #creating layout layout.setSpacing(10) layout.addWidget(self.resTxt, 0, 0) layout.addWidget(self.resEdt, 0, 1) layout.addWidget(self.rotTxt, 1, 0) layout.addWidget(self.rotEdt, 1, 1) layout.addWidget(self.blendTxt, 0, 2) layout.addWidget(self.blendCmb, 1, 2) layout.addWidget(self.btnP1, 2, 1) layout.addWidget(self.btnQuit, 2, 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 T = chunk.transform.matrix try: d_x = d_y = float(self.resEdt.text()) except(ValueError): PhotoScan.app.messageBox("Incorrect export resolution! Please use point delimiter.\n") print("Script aborted.") return 0 try: zrot = float(self.rotEdt.text()) except(ValueError): PhotoScan.app.messageBox("Incorrect rotation angle input! Please use point delimiter.\n") print("Script aborted.") return 0 #type = "jpg" path = PhotoScan.app.getSaveFileName("Specify orthophoto export path and filename:") if not path: PhotoScan.app.messageBox("File not specified.\n") print("Script aborted.") return 0 print("Script started.") self.btnP1.setDisabled(True) self.btnQuit.setDisabled(True) zrot = zrot * math.pi / 180. E, F = math.cos(zrot), math.sin(zrot) zm = PhotoScan.Matrix( [[E,-F,0,0],[F,E,0,0],[0,0,1,0],[0,0,0,1]] ) v_t = T * PhotoScan.Vector( [0,0,0,1] ) v_t.size = 3 if chunk.crs: m = chunk.crs.localframe(v_t) else: m = PhotoScan.Matrix().diag([1,1,1,1]) m = m #* T horizontal = m.inv() * zm * PhotoScan.Vector([1, 0, 0, 0]) horizontal.size = 3 vertical = m.inv() * PhotoScan.Vector([0, 0, 1, 0]) vertical.size = 3 normal = vect(vertical, horizontal) vertical.size = 4 vertical.w = 0 horizontal.size = 4 horizontal.w = 0 normal.size = 4 normal.w = 0 proj = PhotoScan.Matrix ([horizontal, vertical, -normal, PhotoScan.Vector([0,0,0,1])]) front = PhotoScan.Matrix([[1.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, -1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]]) filename = path.rsplit("/", 1)[1] try: type = filename.rsplit(".", 1)[1] if type.lower() not in self.supported_types: type = "jpg" path = path + "." + type except(IndexError): type = "jpg" path = path + "." + type blending_modes = {} blending_modes["mosaic"] = PhotoScan.BlendingMode.MosaicBlending blending_modes["average"] = PhotoScan.BlendingMode.AverageBlending blending = blending_modes[self.blendCmb.currentText()] chunk.exportOrthophoto(path, type, blending, projection = proj, dx = d_x, dy = d_y) self.btnP1.setDisabled(False) self.btnQuit.setDisabled(False) PhotoScan.app.update() print("Script finished.") PhotoScan.app.messageBox("Orthophoto exported to:\n" + path) return 1 def main(): global doc doc = PhotoScan.app.document app = QtGui.QApplication.instance() parent = app.activeWindow() dlg = ExportDlg(parent) PhotoScan.app.addMenuItem("Custom menu/Export orthophoto in rotated plane", main)