Agisoft Metashape
Agisoft Metashape => Other Languages => Topic started by: Leonid on August 19, 2014, 07:35:15 PM
-
У меня есть идея, как обойти ограничение памяти, при создании mesh,
так, у меня около 120 фото, при самом лучшем качестве создается 120млн частиц, считается это около 8 часов, ок, при создании же mesh всей моей памяти(32gb) не хватает даже на 1/10 сцены, и после 6 часов обработки таймер уходит в 60 часов
При этом если ограничить box просчета при создании mesh, чтобы памяти хватало, все считается очень даже неплохо
Так вот, идея такова, почему бы при создании mesh не сделать такую функцию просчета, при которой задается основной box модели, а потом этот box делится на некоторое количество частей(в зависимости от количества оперативной памяти)и каждый участок считается отдельно, при этом нет никакого ограничения на количество памяти, в конце же все куски mesh объединяются в один, при этом все считается из одного облака и не происходит никаких косяков, по моему очень удобно
все это можно сделать и ручками, экспортируя части в zbrush и объединить их там, но почему бы не сделать это в программе автоматически, при этом не нужно ждать создание частей, а можно просто пойти спать, как вам такая идея?
-
Здравствуйте, Леонид,
Автоматизировать подобное разделение рабочей области и экспорт результата можно с помощью Python скриптов.
Проблемой могут стать области стыков, т.к. при подобном подходе допустимы тончайшие разрывы.
Однако, если Вам интересно, могу выслать пример подобного скрипта.
-
да, я тоже подумал насчет стыков, поэтому делаю легкий оверлап, возможно это будет полезной встроенной функцией для многих, да, если можно вышлите пример
-
ps ведь можно сделать тоже самое и для создания облака(с некоторой доработкой в области стыков), а эти две функции(создание облака и создание mesh) потребляют больше всего памяти, и это дает возможность считать большие проекты на машинах с небольшим количеством памяти без потери производительности
-
Добрый день, Леонид,
Вот пример скрипта, который разбивает исходную рабочую область на сетку N на M (задаётся в виде аргументов в соответствующей строке диалогового окна запуска скрипта). В принципе, такой подход можно расширить и на трёхмерный случай.
Обратите внимание, что исходный блок для данного скрипта должен содержать плотное облако.
## Splits active chunk into user defined grid of sub-chunks (images are kept but bounding box is split)
## after chunk being split, for every smaller chunk mesh is generated based on the dense cloud, then dense cloud is removed from smaller chunks
#arguments - X and Y grid sizes
#compatibility PhotoScan Professional 1.0.4
import PhotoScan
import sys
doc = PhotoScan.app.document
chunk = doc.activeChunk
def dist(v0, v1):
"""
Calculate distance between two points defined as vectors
"""
distance = (v1 - v0)
return distance.norm() #**2
partsX = 3 #parts of the model, 3 by default
partsY = 3
if len(sys.argv) == 2:
parts = int(sys.argv[1])
partsX = partsY = parts
elif len(sys.argv) == 3:
partsX = int(sys.argv[1])
partsY = int(sys.argv[2])
print("Script started...")
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()
new_chunk.label = "Chunk "+ str(i)+ "\\" + str(j)
new_chunk.model = None
doc.chunks.add(new_chunk)
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])
new_region.size = new_size
new_region.center = new_center
new_region.rot = new_rot
new_chunk.region = new_region
PhotoScan.app.update()
if new_chunk.dense_cloud:
new_chunk.buildModel("height field", "dense", interpolation = "enabled", faces = "high")
new_chunk.resetDepth()
new_chunk.dense_cloud = None #removing dense cloud
print("Script finished...")
PhotoScan.app.update()
-
Добрый день, Леонид,
Вот пример скрипта, который разбивает исходную рабочую область на сетку N на M (задаётся в виде аргументов в соответствующей строке диалогового окна запуска скрипта). В принципе, такой подход можно расширить и на трёхмерный случай.
Обратите внимание, что исходный блок для данного скрипта должен содержать плотное облако.
## Splits active chunk into user defined grid of sub-chunks (images are kept but bounding box is split)
## after chunk being split, for every smaller chunk mesh is generated based on the dense cloud, then dense cloud is removed from smaller chunks
#arguments - X and Y grid sizes
#compatibility PhotoScan Professional 1.0.4
import PhotoScan
import sys
doc = PhotoScan.app.document
chunk = doc.activeChunk
def dist(v0, v1):
"""
Calculate distance between two points defined as vectors
"""
distance = (v1 - v0)
return distance.norm() #**2
partsX = 3 #parts of the model, 3 by default
partsY = 3
if len(sys.argv) == 2:
parts = int(sys.argv[1])
partsX = partsY = parts
elif len(sys.argv) == 3:
partsX = int(sys.argv[1])
partsY = int(sys.argv[2])
print("Script started...")
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()
new_chunk.label = "Chunk "+ str(i)+ "\\" + str(j)
new_chunk.model = None
doc.chunks.add(new_chunk)
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])
new_region.size = new_size
new_region.center = new_center
new_region.rot = new_rot
new_chunk.region = new_region
PhotoScan.app.update()
if new_chunk.dense_cloud:
new_chunk.buildModel("height field", "dense", interpolation = "enabled", faces = "high")
new_chunk.resetDepth()
new_chunk.dense_cloud = None #removing dense cloud
print("Script finished...")
PhotoScan.app.update()
Очень полезный скрипт, но что дописать в скрипте, чтобы было небольшое перекрытие блоков а не разрывы на стыках?
-
Добрый день,
Вы можете домножить new_size на какой-нибудь коэффициент, например: new_region.size = new_size * 1.01
-
Добрый день!
Спасибо за скрипт, очень пригодился, однако возникла проблема.
В версии 1.1.0 скрипт перестал срабатывать, выдает сообщение AttributeError: 'PhotoScan.Document' object has no attribute 'activeChunk'
Видимо что то поменялось в API?
-
Здравствуйте,
Да, были некоторые изменения в API. Постараюсь завтра выложить скрипт для версии 1.1.0.
-
Новая версия скрипта для PhotoScan Pro 1.1.0:
## Splits active chunk into user defined grid of sub-chunks (images are kept but bounding box is split)
## after chunk being split, for every smaller chunk mesh is generated based on the dense cloud, then dense cloud is removed from smaller chunks
#arguments - X and Y grid sizes
#compatibility PhotoScan Professional 1.1.0
import PhotoScan
import sys
doc = PhotoScan.app.document
chunk = doc.chunk
def dist(v0, v1):
"""
Calculate distance between two points defined as vectors
"""
distance = (v1 - v0)
return distance.norm() #**2
partsX = 3 #parts of the model, 3 by default
partsY = 3
if len(sys.argv) == 2:
parts = int(sys.argv[1])
partsX = partsY = parts
elif len(sys.argv) == 3:
partsX = int(sys.argv[1])
partsY = int(sys.argv[2])
print("Script started...")
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()
new_chunk.label = "Chunk "+ str(i)+ "\\" + str(j)
new_chunk.model = None
doc.addChunk(new_chunk)
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])
new_region.size = new_size
new_region.center = new_center
new_region.rot = new_rot
new_chunk.region = new_region
PhotoScan.app.update()
if new_chunk.dense_cloud:
new_chunk.buildModel(surface = PhotoScan.SurfaceType.HeightField, source = PhotoScan.PointsSource.DensePoints, interpolation = PhotoScan.Interpolation.EnabledInterpolation, face_count = PhotoScan.FaceCount.HighFaceCount)
#new_chunk.resetDepth()
new_chunk.dense_cloud = None #removing dense cloud
print("Script finished...")
PhotoScan.app.update()
-
Выдает ошибку, "D:/chunk_divide.py", line 47, in <module>
doc.addChunk(new_chunk)
TypeError: addChunk() takes no arguments (1 given)
>>>
-
Проверьте, пожалуйста, что у Вас установлен последний билд версии 1.1.0 - 1995.
-
На билде 1995 все работает, спасибо большое!
-
При разбивке на блоки, каждый из них при построении облака точек наращивает место в RAM. Логично было бы добавить в скрипте "Split in chunks.py" галочку "удалять облако точек" после построения модели в блоке. Как удалить облако точек с помощью Python?
-
Чтобы удалить облако точек через Python нужно присвоить ему значение None:
chunk.dense_cloud = None
-
Чтобы удалить облако точек через Python нужно присвоить ему значение None:
chunk.dense_cloud = None
Спасибо, помогло
-
насколько я понимаю этот метод доступен только в про версии?
для стандартной это решение недоступно?
-
Да, использование скриптов доступно только в Профессиональной версии. В Стандартной версии можно лишь вручную дублировать чанки и также вручную выставлять границы рабочей области, чтобы повторить схему действия скрипта.
-
спасибо, вручную все получилось.
-
да, я тоже подумал насчет стыков, поэтому делаю легкий оверлап, возможно это будет полезной встроенной функцией для многих, да, если можно вышлите пример
-
Два исправления, чтобы в 1.4.3 заработало:
1.
заменить
doc.addChunk(new_chunk)
на
doc.chunks.append(new_chunk)
2.
заменить
PhotoScan.PointsSource.DensePoints
на
PhotoScan.DenseCloudData
Кстати, как потом объединить полученные модели?
-
Кстати, как потом объединить полученные модели?
Объединить chank's через "Обработка" -> "Объединить блоки..." включив опцию "Объединить модели" не получится?