Forum

Author Topic: Script for exporting orthophotos using markers  (Read 37716 times)

_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Script for exporting orthophotos using markers
« on: June 23, 2015, 02:59:10 PM »
Hi everyone,

i'm looking for a script/code for exporting a single, "planar" orthophoto using 3 markers (A, B, Y), like you can see it on the attached screenshot (projection plane: markers).
These markers differ from chunk to chunk/ *.psz to *.psz, so i can't calculate a single matrix for the projection.
Can anyone help me?

Thanks!

« Last Edit: June 23, 2015, 03:01:33 PM by _mARCel_ »

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Script for exporting orthophotos using markers
« Reply #1 on: June 24, 2015, 03:16:12 PM »
Hello _mARCel_,

So in every chunk or project you'll have the same labels for the markers in the given combination, like shown on the screenshot?
Best regards,
Alexey Pasumansky,
Agisoft LLC

_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Re: Script for exporting orthophotos using markers
« Reply #2 on: June 25, 2015, 08:58:10 AM »
Hello Alexey,

yes, the labels are always exactly the same.   :)


_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Re: Script for exporting orthophotos using markers
« Reply #3 on: July 14, 2015, 10:11:27 AM »
Any ideas? I really need this script for my excavation:-) Thanks!

frank.stremke

  • Full Member
  • ***
  • Posts: 206
    • View Profile
Re: Script for exporting orthophotos using markers
« Reply #4 on: July 14, 2015, 11:16:06 AM »
would be very usefull indeed for images not referenced otherwise.
so one could use a fixed frame or angle on every smal scan and still get a nice ortho image without the manual rotating and such.
so maybe a feature like this could be implementet into the stock batch process export ortho image function
i just ran trough 200 scans all just with scale bars and it would have been very usefull and time saving
frank

nazg

  • Newbie
  • *
  • Posts: 6
    • View Profile
Re: Script for exporting orthophotos using markers
« Reply #5 on: August 03, 2015, 10:08:08 AM »
I would also be interested in such a script !

_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Re: Script for exporting orthophotos using markers
« Reply #6 on: August 10, 2015, 03:09:38 PM »
I still hope that someone can help me with this...

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Script for exporting orthophotos using markers
« Reply #7 on: August 10, 2015, 03:16:22 PM »
Hello _mARCel_,

Sorry, I've forgotten about this thread, will provide a script sample in a couple of days.
Best regards,
Alexey Pasumansky,
Agisoft LLC

_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Re: Script for exporting orthophotos using markers
« Reply #8 on: August 10, 2015, 03:23:05 PM »
Great! Thank you very much Alexey! ;D

_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Re: Script for exporting orthophotos using markers
« Reply #9 on: September 25, 2015, 08:06:01 AM »
Hello Alexey,
I wanted to ask if you're maybe done with the script. This would be great because I need it quite urgently.
Thanks a lot!

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Script for exporting orthophotos using markers
« Reply #10 on: September 25, 2015, 05:53:18 PM »
Hello Marcel,

Sorry for such a long delay. Please check the following script:

Code: [Select]
# Compatibility - PhotoScan Professional 1.1.6
# exports orthophoto in planar projection defined by vector (from two markers) and Z axes.
# script version 1.2

import os
import PhotoScan
from PySide import QtCore, QtGui

def getMarker(chunk, label):

for marker in chunk.markers:
if marker.label.upper() == label.upper():
return marker
return 0

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 = PhotoScan.MosaicBlending


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.vectTxt = QtGui.QLabel()
self.vectTxt.setText("Horizontal vector:")
self.vectTxt.setFixedSize(150, 25)

self.vect2Txt = QtGui.QLabel()
self.vect2Txt.setText("Vertical vector:")
self.vect2Txt.setFixedSize(150, 25)

self.resEdt = QtGui.QLineEdit()
self.resEdt.setPlaceholderText("type in export resolution, e.g 0.01")
self.resEdt.setFixedSize(150, 25)

self.radioBtn_v = QtGui.QRadioButton("Vertical")
self.radioBtn_h = QtGui.QRadioButton("Horizontal")
self.radioBtn_v.setChecked(True)
self.radioBtn_h.setChecked(False)

self.llistV = [None, None]

self.llistV[0] = QtGui.QComboBox()
self.llistV[0].resize(150, 30)
self.llistV[1] = QtGui.QComboBox()
self.llistV[1].resize(150, 30)

self.llistH = [None, None]

self.llistH[0] = QtGui.QComboBox()
self.llistH[0].resize(150, 30)
self.llistH[1] = QtGui.QComboBox()
self.llistH[1].resize(150, 30)


self.radio = QtGui.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 = QtGui.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 = PhotoScan.app.getExistingDirectory("Specify the folder with the projects:")
filelist = os.listdir(path)
doclist = list()
for file in filelist:
if file[-3:].upper() == "PSZ":
doclist.append(path + "\\" + file)


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

if self.llistV[0].currentIndex() == self.llistV[1].currentIndex():
PhotoScan.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():
PhotoScan.app.messageBox("Can't use the same marker for vector start and end.\n")
print("Script aborted.")
return 0

if len(chunk.markers) < 2:
PhotoScan.app.messageBox("No markers.\n")
print("Script aborted.")
return 0

print("Script started.")

type = "jpg"
for doc_path in doclist:
doc.open(doc_path)
chunk = doc.chunk
T = chunk.transform.matrix


path = doc_path[:-3] + 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():
horizontal = -vect(vertical, normal)
#horizontal, vertical = -vertical, -horizontal

else:
PhotoScan.app.messageBox("Can't export orthophoto! " + path)
print("Script interrupted.")
continue

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])])

#print(proj) #debug

chunk.exportOrthophoto(path, type, self.blending, projection = proj, dx = d_x, dy = d_y)

self.btnP1.setDisabled(False)
self.btnQuit.setDisabled(False)
PhotoScan.app.update()
print("Orthophoto exported to:\n" + path)

print("Script finished.")
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 orthopohto in planar projection from multiple projects", main)

Running the script will add new menu item to the Main Menu.

In the dialog opened by running this new menu option you can specify the name of the markers to be used for the projection plane definition (markers with such labels should be present in all the projects that you are going to process), Then you'll be asked for the folder that contain PSZ files to be processed (from every project in the given folder PhotoScan will try to export orthophoto).
Best regards,
Alexey Pasumansky,
Agisoft LLC

_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Re: Script for exporting orthophotos using markers
« Reply #11 on: September 26, 2015, 11:05:02 AM »
Hello Alexey,

thank you so much! Basically ist works perfect! There is only one thing left, that is very important for me.
The point of origin of the exported Tif looks randomly. (e.g.  -19819.792 , 6365717.397).
When i use the export function over the UI, the point of origin of the Tif is (0 , 0)
But it would be perfect, if the exported orthophoto have his point of origin at (0 , Z-Value of Marker "m1" or "A").
Is this possible?  ;D
Thank you for your efforts!

This is my "extended" script:
+ color correction checkbox
+ type = tif
+ write_world=True
+ average blending

Code: [Select]
# Compatibility - PhotoScan Professional 1.1.6
# exports orthophoto in planar projection defined by vector (from two markers) and Z axes.
# script version 1.2
# added Color_Correction Checkbox
import os
import PhotoScan
from PySide import QtCore, QtGui

def getMarker(chunk, label):

for marker in chunk.markers:
if marker.label.upper() == label.upper():
return marker
return 0

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 = PhotoScan.AverageBlending #prefer average blending


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.Btn_cc = QtGui.QCheckBox("Color Correction")
self.Btn_cc.setChecked(True)

self.vectTxt = QtGui.QLabel()
self.vectTxt.setText("Horizontal vector:")
self.vectTxt.setFixedSize(150, 25)

self.vect2Txt = QtGui.QLabel()
self.vect2Txt.setText("Vertical vector:")
self.vect2Txt.setFixedSize(150, 25)

self.resEdt = QtGui.QLineEdit()
self.resEdt.setPlaceholderText("type in export resolution, e.g 0.01")
self.resEdt.setFixedSize(150, 25)

self.radioBtn_v = QtGui.QRadioButton("Vertical")
self.radioBtn_h = QtGui.QRadioButton("Horizontal")
self.radioBtn_v.setChecked(True)
self.radioBtn_h.setChecked(False)

self.llistV = [None, None]

self.llistV[0] = QtGui.QComboBox()
self.llistV[0].resize(150, 30)
self.llistV[1] = QtGui.QComboBox()
self.llistV[1].resize(150, 30)

self.llistH = [None, None]

self.llistH[0] = QtGui.QComboBox()
self.llistH[0].resize(150, 30)
self.llistH[1] = QtGui.QComboBox()
self.llistH[1].resize(150, 30)


self.radio = QtGui.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 = QtGui.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.addWidget(self.Btn_cc, 0,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 = PhotoScan.app.getExistingDirectory("Specify the folder with the projects:")
filelist = os.listdir(path)
doclist = list()
for file in filelist:
if file[-3:].upper() == "PSZ":
doclist.append(path + "\\" + file)


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

if self.llistV[0].currentIndex() == self.llistV[1].currentIndex():
PhotoScan.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():
PhotoScan.app.messageBox("Can't use the same marker for vector start and end.\n")
print("Script aborted.")
return 0

if len(chunk.markers) < 2:
PhotoScan.app.messageBox("No markers.\n")
print("Script aborted.")
return 0

print("Script started.")
type = "tif"
for doc_path in doclist:
doc.open(doc_path)
chunk = doc.chunk
T = chunk.transform.matrix


path = doc_path[:-3] + 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():
horizontal = -vect(vertical, normal)
#horizontal, vertical = -vertical, -horizontal

else:
PhotoScan.app.messageBox("Can't export orthophoto! " + path)
print("Script interrupted.")
continue

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])])

#print(proj) #debug
if self.Btn_cc.isChecked():
color_correction = color_correction=(True)

elif not self.Btn_cc.isChecked():
color_correction = color_correction=(False)

chunk.exportOrthophoto(path, type, self.blending, color_correction, projection = proj,write_world=True, dx = d_x, dy = d_y)
self.btnP1.setDisabled(False)
self.btnQuit.setDisabled(False)
PhotoScan.app.update()
print("Orthophoto exported to:\n" + path)

print("Script finished.")
return 1



def main():

global doc
doc = PhotoScan.app.document

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

dlg = ExportDlg(parent)

PhotoScan.app.addMenuItem("ArchaeoTools/Orthophoto", main)

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 14813
    • View Profile
Re: Script for exporting orthophotos using markers
« Reply #12 on: September 29, 2015, 01:12:05 PM »
Hello Marcel,

Ok, I'll check what could be done. But you wish to keep the original scale or it's not important?
Best regards,
Alexey Pasumansky,
Agisoft LLC

_mARCel_

  • Newbie
  • *
  • Posts: 22
  • I'm an archaeologist from Germany
    • View Profile
    • ArchaeoBW GmbH Home
Re: Script for exporting orthophotos using markers
« Reply #13 on: September 29, 2015, 03:42:25 PM »
Hello Alexey,
yes, the scale is very important for me.

Thanks a lot!!!

Dukytony

  • Jr. Member
  • **
  • Posts: 51
    • View Profile
Re: Script for exporting orthophotos using markers
« Reply #14 on: October 13, 2015, 12:11:26 PM »
This would be very useful to me (archeologist too) but i can't seem to make it work.

Every time I try to export the orthophoto I get this :

Script started.
Loading project...
loaded project in 2.606 sec
Finished processing in 2.606 sec (exit code 1)
initializing renderer... tessellating mesh... done (631405 -> 631405 faces)
done in 0.172 sec
Raster size: 0x0
Finished processing in 0.175 sec (exit code 0)
Orthophoto exported to:
D:\Users\me\mur sud n∞12.tif
Script finished.
>>>

And then nothing happens, no file in the folder it's supposed to be exported to...

Does someone have any idea what's wrong?

Thanks a lot!