Skip to content

Commit

Permalink
Fixes executable paths and interfaces Colmap and OpenMVS. closes #22, c…
Browse files Browse the repository at this point in the history
…loses #56, closes #64, closes #57.
  • Loading branch information
norgeotloic committed Nov 24, 2018
1 parent 26ab6d1 commit 6bd90f7
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 30 deletions.
8 changes: 4 additions & 4 deletions scripts/bakemyscan.py
Expand Up @@ -96,16 +96,16 @@ def check_valid_file(_file, _exts=None, _image=False, _can_create=False):
parser.print_help()
print('ERROR: invalid method name')
sys.exit(5)
if args.method == "MMGS" and bpy.context.user_preferences.addons["BakeMyScan"].preferences.mmgs == "":
if args.method == "MMGS" and bpy.types.Scene.executables["mmgs"] == "":
print("MMGS is not configured in the user preferences")
sys.exit(6)
if args.method == "INSTANT" and bpy.context.user_preferences.addons["BakeMyScan"].preferences.instant == "":
if args.method == "INSTANT" and bpy.types.Scene.executables["instant"] == "":
print("Instant Meshes is not configured in the user preferences")
sys.exit(7)
if args.method == "QUADRIFLOW" and bpy.context.user_preferences.addons["BakeMyScan"].preferences.quadriflow == "":
if args.method == "QUADRIFLOW" and bpy.types.Scene.executables["quadriflow"] == "":
print("Quadriflow is not configured in the user preferences")
sys.exit(8)
if args.method == "MESHLAB" and bpy.context.user_preferences.addons["BakeMyScan"].preferences.meshlabserver == "":
if args.method == "MESHLAB" and bpy.types.Scene.executables["meshlabserver"] == "":
print("Meshlabserver is not configured in the user preferences")
sys.exit(9)

Expand Down
82 changes: 77 additions & 5 deletions src/PREFS.py
@@ -1,21 +1,93 @@
import bpy
import os
import json

def absolute_paths(self, context):
#Make the paths absolute
bpy.types.Scene.executables["mmgs"] = os.path.abspath(bpy.path.abspath(self.mmgs)) if self.mmgs!="" else ""
bpy.types.Scene.executables["instant"] = os.path.abspath(bpy.path.abspath(self.instant)) if self.instant!="" else ""
bpy.types.Scene.executables["quadriflow"] = os.path.abspath(bpy.path.abspath(self.quadriflow)) if self.quadriflow!="" else ""
bpy.types.Scene.executables["meshlabserver"] = os.path.abspath(bpy.path.abspath(self.meshlabserver)) if self.meshlabserver!="" else ""
bpy.types.Scene.executables["colmap"] = os.path.abspath(bpy.path.abspath(self.colmap)) if self.colmap!="" else ""
bpy.types.Scene.executables["interfacevisualsfm"] = os.path.abspath(bpy.path.abspath(self.interfacevisualsfm)) if self.interfacevisualsfm!="" else ""
bpy.types.Scene.executables["densifypointcloud"] = os.path.abspath(bpy.path.abspath(self.densifypointcloud)) if self.densifypointcloud!="" else ""
bpy.types.Scene.executables["reconstructmesh"] = os.path.abspath(bpy.path.abspath(self.reconstructmesh)) if self.reconstructmesh!="" else ""
bpy.types.Scene.executables["texturemesh"] = os.path.abspath(bpy.path.abspath(self.texturemesh)) if self.texturemesh!="" else ""
bpy.types.Scene.executables["openmvsdir"] = os.path.abspath(bpy.path.abspath(self.openmvsdir)) if self.openmvsdir!="" else ""
#Write to a .json file to keep even after updating the addon
path = os.path.join(bpy.utils.resource_path('USER'), "bakemyscan.config")
with open(path, 'w') as fp:
json.dump(bpy.types.Scene.executables, fp, sort_keys=True, indent=4)
return None
def find_openmvs_executables(self, context):
bpy.types.Scene.executables["openmvsdir"] = os.path.abspath(bpy.path.abspath(self.openmvsdir)) if self.openmvsdir!="" else ""
for f in os.listdir(bpy.types.Scene.executables["openmvsdir"]):
if "InterfaceVisualSFM" in f:
self.interfacevisualsfm = os.path.join(bpy.types.Scene.executables["openmvsdir"], f)
if "DensifyPointCloud" in f:
self.densifypointcloud = os.path.join(bpy.types.Scene.executables["openmvsdir"], f)
if "ReconstructMesh" in f:
self.reconstructmesh = os.path.join(bpy.types.Scene.executables["openmvsdir"], f)
if "TextureMesh" in f:
self.texturemesh = os.path.join(bpy.types.Scene.executables["openmvsdir"], f)
return None

class BakeMyScanPrefs(bpy.types.AddonPreferences):
bl_idname = 'BakeMyScan'
mmgs = bpy.props.StringProperty(name="MMGS Executable", subtype='FILE_PATH')
instant = bpy.props.StringProperty(name="Instant Meshes Executable", subtype='FILE_PATH')
quadriflow = bpy.props.StringProperty(name="Quadriflow Executable", subtype='FILE_PATH')
meshlabserver = bpy.props.StringProperty(name="Meshlabserver Executable", subtype='FILE_PATH')

executables = {}
#Remeshers
mmgs = bpy.props.StringProperty(name="MMGS Executable", subtype='FILE_PATH', update=absolute_paths)
instant = bpy.props.StringProperty(name="Instant Meshes Executable", subtype='FILE_PATH', update=absolute_paths)
quadriflow = bpy.props.StringProperty(name="Quadriflow Executable", subtype='FILE_PATH', update=absolute_paths)
meshlabserver = bpy.props.StringProperty(name="Meshlabserver Executable", subtype='FILE_PATH', update=absolute_paths)
#Scanning executables
colmap = bpy.props.StringProperty(name="Colmap Executable", subtype='FILE_PATH', update=absolute_paths)
openmvsdir = bpy.props.StringProperty(name="OpenMVS directory", subtype='DIR_PATH', update=find_openmvs_executables)
#OpenMVS executables
interfacevisualsfm = bpy.props.StringProperty(name="InterfaceVisualSFM", subtype='FILE_PATH', update=absolute_paths)
densifypointcloud = bpy.props.StringProperty(name="DensifyPointCloud", subtype='FILE_PATH', update=absolute_paths)
reconstructmesh = bpy.props.StringProperty(name="ReconstructMesh", subtype='FILE_PATH', update=absolute_paths)
texturemesh = bpy.props.StringProperty(name="TextureMesh", subtype='FILE_PATH', update=absolute_paths)

def check(self, context):
return True
def draw(self, context):
layout = self.layout
layout.label(text="Executable paths")
layout.label(text="Remeshing tools")
layout.prop(self, "instant")
layout.prop(self, "mmgs")
layout.prop(self, "quadriflow")
layout.prop(self, "meshlabserver")
layout.label(text="Photogrammetry")
layout.prop(self, "colmap")
layout.prop(self, "openmvsdir")
#Display the OpenMVS executables
if self.openmvsdir != "":
layout.prop(self, "interfacevisualsfm")
layout.prop(self, "densifypointcloud")
layout.prop(self, "reconstructmesh")
layout.prop(self, "texturemesh")

def register():
bpy.types.Scene.executables = {}
bpy.utils.register_class(BakeMyScanPrefs)
PREFS = bpy.context.user_preferences.addons["BakeMyScan"].preferences

#Print the preferences
for x in PREFS.keys():
print(x, PREFS[x])

#Try to read in the preferences
path = os.path.join(bpy.utils.resource_path('USER'), "bakemyscan.config")
if os.path.exists(path):
with open(path, 'r') as fp:
bpy.types.Scene.executables = json.load(fp)
#Assign them to the variables
for x in bpy.types.Scene.executables.keys():
if PREFS[x] == "":
PREFS[x] = bpy.types.Scene.executables[x]
print(bpy.types.Scene.executables)
def unregister():
bpy.utils.unregister_class(BakeMyScanPrefs)
del bpy.types.Scene.executables
31 changes: 17 additions & 14 deletions src/fn_soft.py
Expand Up @@ -142,10 +142,10 @@ def colmap_auto(
sparse=1,
dense=1,
mesher="delaunay",
executable="colmap",
colmap="colmap",
gpu=False
):
cmd = '"' + executable + '" automatic_reconstructor '
cmd = '"' + colmap + '" automatic_reconstructor '
cmd += "--workspace_path %s " % workspace
cmd += "--image_path %s " % images
cmd += "--quality %s " % quality
Expand All @@ -165,7 +165,12 @@ def colmap_openmvs(
sparse=1,
dense=1,
mesher="delaunay",
executable="colmap"
colmap="colmap",
interfacevisualsfm = "InterfaceVisualSFM",
densifypointcloud = "DensifyPointCloud",
reconstructmesh = "ReconstructMesh",
texturemesh = "TextureMesh",
meshlabserver = "meshlabserver"
):
DB = os.path.join(workspace, "database.db")
SP = os.path.join(workspace, "sparse")
Expand All @@ -175,23 +180,21 @@ def colmap_openmvs(
os.chdir(workspace)

#Colmap
cmd1 = executable + " feature_extractor --database_path %s --image_path %s " % (DB, images)
cmd2 = executable + " exhaustive_matcher --database_path %s" % DB
cmd3 = executable + " mapper --database_path %s --image_path %s --output_path %s" % ( DB, images, SP )
cmd4 = executable + " model_converter --input_path %s --output_path %s --output_type NVM" % (os.path.join(SP, "0"), os.path.join(workspace, "model.nvm"))
cmd1 = colmap + " feature_extractor --database_path %s --image_path %s " % (DB, images)
cmd2 = colmap + " exhaustive_matcher --database_path %s" % DB
cmd3 = colmap + " mapper --database_path %s --image_path %s --output_path %s" % ( DB, images, SP )
cmd4 = colmap + " model_converter --input_path %s --output_path %s --output_type NVM" % (os.path.join(SP, "0"), os.path.join(workspace, "model.nvm"))

#OpenMVS
cmd5 = "InterfaceVisualSFM -w %s -i %s" % (workspace, os.path.join(workspace, "model.nvm"))
cmd6 = "DensifyPointCloud -w %s -i %s --resolution-level %d" % (workspace, os.path.join(workspace, "model.mvs"), 2)
cmd7 = "ReconstructMesh -w %s -i %s" % (workspace, os.path.join(workspace, "model_dense.mvs"))
cmd8 = "TextureMesh -w %s -i %s" % (workspace, os.path.join(workspace, "model_dense_mesh.mvs"))
cmd5 = interfacevisualsfm + " -w %s -i %s" % (workspace, os.path.join(workspace, "model.nvm"))
cmd6 = densifypointcloud + " -w %s -i %s --resolution-level %d" % (workspace, os.path.join(workspace, "model.mvs"), 2)
cmd7 = reconstructmesh + " -w %s -i %s" % (workspace, os.path.join(workspace, "model_dense.mvs"))
cmd8 = texturemesh + " -w %s -i %s" % (workspace, os.path.join(workspace, "model_dense_mesh.mvs"))

#Conversion
cmd9 = "meshlabserver -om wt -i %s -o %s" % (os.path.join(workspace, "model_dense_mesh_texture.ply"), os.path.join(workspace, "model_dense_mesh_texture.obj"))
cmd9 = meshlabserver + " -om wt -i %s -o %s" % (os.path.join(workspace, "model_dense_mesh_texture.ply"), os.path.join(workspace, "model_dense_mesh_texture.obj"))

os.chdir(old)


for cmd in [cmd1, cmd2, cmd3, cmd4, cmd5, cmd6, cmd7, cmd8]:
out, err, code = run(cmd)
if code!=0:
Expand Down
30 changes: 26 additions & 4 deletions src/op_REMESHERS.py
Expand Up @@ -145,7 +145,7 @@ def draw(self, context):

#Overriden methods
def setexe(self, context):
self.executable = context.user_preferences.addons["BakeMyScan"].preferences.quadriflow
self.executable = bpy.types.Scene.executables["quadriflow"]
def export(self, context):
bpy.ops.export_scene.obj(
filepath = os.path.join(self.tmp.name, "tmp.obj"),
Expand Down Expand Up @@ -217,7 +217,7 @@ def draw(self, context):

#Overriden methods
def setexe(self, context):
self.executable = context.user_preferences.addons["BakeMyScan"].preferences.instant
self.executable = bpy.types.Scene.executables["instant"]
def export(self, context):
bpy.ops.export_scene.obj(
filepath = os.path.join(self.tmp.name, "tmp.obj"),
Expand Down Expand Up @@ -312,7 +312,7 @@ def draw(self, context):

#Overriden methods
def setexe(self, context):
self.executable = context.user_preferences.addons["BakeMyScan"].preferences.mmgs
self.executable = bpy.types.Scene.executables["mmgs"]
def export(self, context):
obj = context.active_object
self.maxDim = max( max( obj.dimensions[0], obj.dimensions[1]) , obj.dimensions[2] )
Expand Down Expand Up @@ -353,7 +353,7 @@ def draw(self, context):

#Overriden methods
def setexe(self, context):
self.executable = context.user_preferences.addons["BakeMyScan"].preferences.meshlabserver
self.executable = bpy.types.Scene.executables["meshlabserver"]
def export(self, context):
bpy.ops.export_scene.obj(
filepath = os.path.join(self.tmp.name, "tmp.obj"),
Expand Down Expand Up @@ -759,6 +759,28 @@ def remesh(self, context):



"""
class Ultimate(bpy.types.Operator):
bl_idname = "bakemyscan.retopo"
bl_label = "Ultimate retopo"
bl_options = {"REGISTER"}
#For executable remeshers
tmp = tempfile.TemporaryDirectory()
executable = None
results = []
keepMaterials = False
#For remeshers which need to duplicate the object
workonduplis = False
method = bpy.props.EnumProperty(
items= (
('iterative', 'iterative', 'iterative'),
("2", "2", "2"),
("4", "4", "4"), ("6", "6", "6")) , name="r", description="Orientation symmetry type", default="r0")
"""

def register() :
bpy.utils.register_class(BaseRemesher)
bpy.utils.register_class(Quadriflow)
Expand Down
23 changes: 21 additions & 2 deletions src/op_SCAN.py
Expand Up @@ -41,13 +41,15 @@ def poll(self, context):
return 0
if len([imghdr.what(os.path.join(D,x)) for x in os.listdir(D) if not os.path.isdir(os.path.join(D,x))]) == 0:
return 0
if bpy.types.Scene.executables["colmap"] == "":
return 0
return 1

def execute(self, context):
if True:
D = bpy.types.Scene.imgpaths
self.results = fn_soft.colmap_auto(
executable = "colmap",
colmap = bpy.types.Scene.executables["colmap"],
workspace = D,
images = D,
mesher = self.mesher,
Expand Down Expand Up @@ -98,20 +100,37 @@ def poll(self, context):
return 0
if len([imghdr.what(os.path.join(D,x)) for x in os.listdir(D) if not os.path.isdir(os.path.join(D,x))]) == 0:
return 0
if bpy.types.Scene.executables["colmap"] == "":
return 0
if bpy.types.Scene.executables["densifypointcloud"] == "":
return 0
if bpy.types.Scene.executables["interfacevisualsfm"] == "":
return 0
if bpy.types.Scene.executables["reconstructmesh"] == "":
return 0
if bpy.types.Scene.executables["texturemesh"] == "":
return 0
if bpy.types.Scene.executables["meshlabserver"] == "":
return 0
return 1

def execute(self, context):
if True:
D = bpy.types.Scene.imgpaths
self.results = fn_soft.colmap_openmvs(
executable = "colmap",
workspace = D,
images = D,
mesher = self.mesher,
quality = self.quality,
sparse = 1 if self.sparse else 0,
dense = 1 if self.sparse else 0,
single_camera = 1 if self.single else 0,
colmap=bpy.types.Scene.executables["colmap"],
interfacevisualsfm = bpy.types.Scene.executables["interfacevisualsfm"],
densifypointcloud = bpy.types.Scene.executables["densifypointcloud"],
reconstructmesh = bpy.types.Scene.executables["reconstructmesh"],
texturemesh = bpy.types.Scene.executables["texturemesh"],
meshlabserver = bpy.types.Scene.executables["meshlabserver"],
)
return{'FINISHED'}
else:
Expand Down
2 changes: 1 addition & 1 deletion tests/tests.py
Expand Up @@ -14,7 +14,7 @@
import json

#Do we stop the execution on error?
_BREAK = True
_BREAK = False
#Path to the local_directory
_DIR = os.path.dirname(__file__)
def _PATH(f):
Expand Down

0 comments on commit 6bd90f7

Please sign in to comment.