Difference between revisions of "Split in chunks.py"
From Agisoft
Line 1: | Line 1: | ||
<pre> | <pre> | ||
− | # | + | #compatibility PhotoScan Pro 1.3 |
− | + | ||
− | + | ||
import PhotoScan | import PhotoScan | ||
− | from | + | from PySide2 import QtGui, QtCore, QtWidgets |
− | class SplitDlg( | + | QUALITY = {"1":PhotoScan.UltraQuality, |
+ | "2":PhotoScan.HighQuality, | ||
+ | "4":PhotoScan.MediumQuality, | ||
+ | "8":PhotoScan.LowQuality, | ||
+ | "16":PhotoScan.LowestQuality} | ||
+ | |||
+ | FILTERING = {"3":PhotoScan.NoFiltering, | ||
+ | "0":PhotoScan.MildFiltering, | ||
+ | "1":PhotoScan.ModerateFiltering, | ||
+ | "2":PhotoScan.AggressiveFiltering} | ||
+ | |||
+ | class SplitDlg(QtWidgets.QDialog): | ||
def __init__(self, parent): | def __init__(self, parent): | ||
− | + | QtWidgets.QDialog.__init__(self, parent) | |
self.setWindowTitle("Split in chunks") | self.setWindowTitle("Split in chunks") | ||
Line 19: | Line 28: | ||
self.gridHeight = 198 | self.gridHeight = 198 | ||
− | self.spinX = | + | self.spinX = QtWidgets.QSpinBox() |
self.spinX.setMinimum(2) | self.spinX.setMinimum(2) | ||
self.spinX.setMaximum(20) | self.spinX.setMaximum(20) | ||
self.spinX.setFixedSize(75, 25) | self.spinX.setFixedSize(75, 25) | ||
− | self.spinY = | + | self.spinY = QtWidgets.QSpinBox() |
self.spinY.setMinimum(2) | self.spinY.setMinimum(2) | ||
self.spinY.setMaximum(20) | self.spinY.setMaximum(20) | ||
self.spinY.setFixedSize(75, 25) | self.spinY.setFixedSize(75, 25) | ||
− | self.chkMesh = | + | self.chkMesh = QtWidgets.QCheckBox("Build Mesh") |
− | self.chkMesh.setFixedSize( | + | self.chkMesh.setFixedSize(100,50) |
self.chkMesh.setToolTip("Generates mesh for each cell in grid") | self.chkMesh.setToolTip("Generates mesh for each cell in grid") | ||
− | self.chkDense = | + | self.chkDense = QtWidgets.QCheckBox("Build Dense Cloud") |
− | self.chkDense.setFixedSize( | + | self.chkDense.setFixedSize(120,50) |
self.chkDense.setWhatsThis("Builds dense cloud for each cell in grid") | self.chkDense.setWhatsThis("Builds dense cloud for each cell in grid") | ||
− | self.chkMerge = | + | self.chkMerge = QtWidgets.QCheckBox("Merge Back") |
self.chkMerge.setFixedSize(90,50) | self.chkMerge.setFixedSize(90,50) | ||
self.chkMerge.setToolTip("Merges back the processing products formed in the individual cells") | 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.btnQuit = | + | self.txtOvp = QtWidgets.QLabel() |
+ | self.txtOvp.setText("Overlap (%):") | ||
+ | self.txtOvp.setFixedSize(90, 25) | ||
+ | |||
+ | self.edtOvp = QtWidgets.QLineEdit() | ||
+ | self.edtOvp.setPlaceholderText("0") | ||
+ | self.edtOvp.setFixedSize(100, 25) | ||
+ | |||
+ | self.btnQuit = QtWidgets.QPushButton("Close") | ||
self.btnQuit.setFixedSize(90,50) | self.btnQuit.setFixedSize(90,50) | ||
− | self.btnP1 = | + | self.btnP1 = QtWidgets.QPushButton("Split") |
self.btnP1.setFixedSize(90,50) | self.btnP1.setFixedSize(90,50) | ||
− | self.grid = | + | self.grid = QtWidgets.QLabel(" ") |
self.grid.resize(self.gridWidth, self.gridHeight) | self.grid.resize(self.gridWidth, self.gridHeight) | ||
tempPixmap = QtGui.QPixmap(self.gridWidth, self.gridHeight) | tempPixmap = QtGui.QPixmap(self.gridWidth, self.gridHeight) | ||
Line 66: | Line 87: | ||
self.grid.show() | self.grid.show() | ||
− | layout = | + | layout = QtWidgets.QGridLayout() #creating layout |
layout.addWidget(self.spinX, 0, 0) | layout.addWidget(self.spinX, 0, 0) | ||
layout.addWidget(self.spinY, 0, 1) | layout.addWidget(self.spinY, 0, 1) | ||
Line 74: | Line 95: | ||
layout.addWidget(self.chkMerge, 0, 4) | layout.addWidget(self.chkMerge, 0, 4) | ||
− | layout.addWidget(self.btnP1, | + | layout.addWidget(self.btnP1, 3, 2) |
− | layout.addWidget(self.btnQuit, | + | layout.addWidget(self.btnQuit, 3, 3) |
+ | |||
+ | layout.addWidget(self.txtOvp, 1, 3) | ||
+ | layout.addWidget(self.edtOvp, 1, 4) | ||
+ | |||
+ | layout.addWidget(self.chkSave, 2, 4) | ||
+ | |||
layout.addWidget(self.grid, 1, 0, 2, 2) | layout.addWidget(self.grid, 1, 0, 2, 2) | ||
self.setLayout(layout) | self.setLayout(layout) | ||
Line 138: | Line 165: | ||
buildDense = self.chkDense.isChecked() | buildDense = self.chkDense.isChecked() | ||
mergeBack = self.chkMerge.isChecked() | mergeBack = self.chkMerge.isChecked() | ||
+ | autosave = self.chkSave.isChecked() | ||
doc = PhotoScan.app.document | doc = PhotoScan.app.document | ||
chunk = doc.chunk | chunk = doc.chunk | ||
+ | |||
+ | if not chunk.transform.translation: | ||
+ | chunk.transform.matrix = chunk.transform.matrix | ||
region = chunk.region | region = chunk.region | ||
Line 154: | Line 185: | ||
for j in range(1, partsY + 1): #creating new chunks and adjusting bounding box | for j in range(1, partsY + 1): #creating new chunks and adjusting bounding box | ||
− | |||
− | |||
for i in range(1, partsX + 1): | for i in range(1, partsX + 1): | ||
− | new_chunk = chunk.copy() | + | new_chunk = chunk.copy(items = [PhotoScan.DataSource.DenseCloudData]) |
new_chunk.label = "Chunk "+ str(i)+ "\\" + str(j) | new_chunk.label = "Chunk "+ str(i)+ "\\" + str(j) | ||
− | |||
new_chunk.model = None | new_chunk.model = None | ||
− | + | ||
new_region = PhotoScan.Region() | new_region = PhotoScan.Region() | ||
new_rot = r_rotate | new_rot = r_rotate | ||
Line 167: | Line 195: | ||
new_center = offset + new_rot * new_center | new_center = offset + new_rot * new_center | ||
new_size = PhotoScan.Vector([x_scale, y_scale, z_scale]) | new_size = PhotoScan.Vector([x_scale, y_scale, z_scale]) | ||
− | new_region.size = new_size | + | |
+ | 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.center = new_center | ||
new_region.rot = new_rot | new_region.rot = new_rot | ||
Line 174: | Line 207: | ||
PhotoScan.app.update() | PhotoScan.app.update() | ||
+ | |||
+ | if autosave: | ||
+ | doc.save() | ||
if buildDense: | if buildDense: | ||
− | new_chunk.buildDenseCloud(quality = PhotoScan.Quality. | + | if new_chunk.depth_maps: |
+ | reuse_depth = True | ||
+ | quality = QUALITY[new_chunk.depth_maps.meta['depth/depth_downscale']] | ||
+ | filtering = FILTERING[new_chunk.depth_maps.meta['depth/depth_filter_mode']] | ||
+ | try: | ||
+ | new_chunk.buildDenseCloud(quality = quality, filter = filtering, keep_depth = False, reuse_depth = reuse_depth) | ||
+ | except RuntimeError: | ||
+ | print("Can't build dense cloud for " + chunk.label) | ||
+ | |||
+ | else: | ||
+ | reuse_depth = False | ||
+ | try: | ||
+ | new_chunk.buildDenseCloud(quality = PhotoScan.Quality.HighQuality, filter = PhotoScan.FilterMode.AggressiveFiltering, keep_depth = False, reuse_depth = reuse_depth) | ||
+ | except RuntimeError: | ||
+ | print("Can't build dense cloud for " + chunk.label) | ||
+ | |||
+ | |||
+ | if autosave: | ||
+ | doc.save() | ||
if buildMesh: | if buildMesh: | ||
if new_chunk.dense_cloud: | if new_chunk.dense_cloud: | ||
− | new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.DenseCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) | + | try: |
+ | new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.DenseCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) | ||
+ | except RuntimeError: | ||
+ | print("Can't build mesh for " + chunk.label) | ||
else: | else: | ||
− | new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.PointCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) | + | try: |
+ | new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.PointCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) | ||
+ | except RuntimeError: | ||
+ | new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.PointCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) | ||
+ | if autosave: | ||
+ | doc.save() | ||
+ | if not buildDense: | ||
+ | new_chunk.dense_cloud = None | ||
+ | |||
new_chunk.depth_maps = None | new_chunk.depth_maps = None | ||
+ | #new_chunk = None | ||
if mergeBack: | if mergeBack: | ||
Line 190: | Line 256: | ||
chunk = doc.chunks[i] | chunk = doc.chunks[i] | ||
chunk.remove(chunk.cameras) | chunk.remove(chunk.cameras) | ||
− | doc.chunks[0].model = None #removing model from original chunk, just for case | + | doc.chunks[0].model = None #removing model from 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.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. | doc.remove(doc.chunks[1:-1]) #removing smaller chunks. | ||
+ | if autosave: | ||
+ | doc.save() | ||
+ | |||
+ | if autosave: | ||
+ | doc.save() | ||
print("Script finished") | print("Script finished") | ||
Line 203: | Line 275: | ||
doc = PhotoScan.app.document | doc = PhotoScan.app.document | ||
− | app = | + | app = QtWidgets.QApplication.instance() |
parent = app.activeWindow() | parent = app.activeWindow() | ||
Line 209: | Line 281: | ||
− | PhotoScan.app.addMenuItem("Custom/Split in chunks", main) | + | PhotoScan.app.addMenuItem("Custom Menu/Split in chunks", main) |
</pre> | </pre> |
Revision as of 15:30, 17 February 2017
#compatibility PhotoScan Pro 1.3 import PhotoScan from PySide2 import QtGui, QtCore, QtWidgets QUALITY = {"1":PhotoScan.UltraQuality, "2":PhotoScan.HighQuality, "4":PhotoScan.MediumQuality, "8":PhotoScan.LowQuality, "16":PhotoScan.LowestQuality} FILTERING = {"3":PhotoScan.NoFiltering, "0":PhotoScan.MildFiltering, "1":PhotoScan.ModerateFiltering, "2":PhotoScan.AggressiveFiltering} 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(2) self.spinX.setMaximum(20) self.spinX.setFixedSize(75, 25) self.spinY = QtWidgets.QSpinBox() self.spinY.setMinimum(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.chkDense = QtWidgets.QCheckBox("Build Dense Cloud") self.chkDense.setFixedSize(120,50) self.chkDense.setWhatsThis("Builds dense cloud for each cell in grid") 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(100, 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, 0, 0) layout.addWidget(self.spinY, 0, 1) layout.addWidget(self.chkDense, 0, 2) layout.addWidget(self.chkMesh, 0, 3) layout.addWidget(self.chkMerge, 0, 4) layout.addWidget(self.btnP1, 3, 2) layout.addWidget(self.btnQuit, 3, 3) layout.addWidget(self.txtOvp, 1, 3) layout.addWidget(self.edtOvp, 1, 4) layout.addWidget(self.chkSave, 2, 4) layout.addWidget(self.grid, 1, 0, 2, 2) 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() doc = PhotoScan.app.document chunk = doc.chunk if not chunk.transform.translation: 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. for j in range(1, partsY + 1): #creating new chunks and adjusting bounding box for i in range(1, partsX + 1): new_chunk = chunk.copy(items = [PhotoScan.DataSource.DenseCloudData]) new_chunk.label = "Chunk "+ str(i)+ "\\" + str(j) new_chunk.model = None new_region = PhotoScan.Region() new_rot = r_rotate new_center = PhotoScan.Vector([(i - 0.5) * x_scale, (j - 0.5) * y_scale, 0.5 * z_scale]) new_center = offset + new_rot * new_center new_size = PhotoScan.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 PhotoScan.app.update() if autosave: doc.save() if buildDense: if new_chunk.depth_maps: reuse_depth = True quality = QUALITY[new_chunk.depth_maps.meta['depth/depth_downscale']] filtering = FILTERING[new_chunk.depth_maps.meta['depth/depth_filter_mode']] try: new_chunk.buildDenseCloud(quality = quality, filter = filtering, keep_depth = False, reuse_depth = reuse_depth) except RuntimeError: print("Can't build dense cloud for " + chunk.label) else: reuse_depth = False try: new_chunk.buildDenseCloud(quality = PhotoScan.Quality.HighQuality, filter = PhotoScan.FilterMode.AggressiveFiltering, keep_depth = False, reuse_depth = reuse_depth) 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 = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.DenseCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) except RuntimeError: print("Can't build mesh for " + chunk.label) else: try: new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.PointCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) except RuntimeError: new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.DataSource.PointCloudData, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount) if autosave: doc.save() if not buildDense: new_chunk.dense_cloud = None new_chunk.depth_maps = None #new_chunk = None if mergeBack: for i in range(1, len(doc.chunks)): chunk = doc.chunks[i] chunk.remove(chunk.cameras) doc.chunks[0].model = None #removing model from 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 main(): global doc doc = PhotoScan.app.document app = QtWidgets.QApplication.instance() parent = app.activeWindow() dlg = SplitDlg(parent) PhotoScan.app.addMenuItem("Custom Menu/Split in chunks", main)