Artec 3D Scanning SDK  2.0
Beyond Basics

The Basics page highlights only fundamental API functions and usage scenarios.

You can use more classes and functions to implement advanced usage scenarios.

Data Types and Structure

The table below lists interfaces for the most essential data types, whereas the figure shows their structure (by the example of IModel).

imodel_contents.svg
IModel structure
Interface Meaning
IBlob Memory chunk of undisclosed content
IArrayPoint3F Array of point positions
IArrayIndexTriplet Array of coordinate indices for triangles
IArrayMatrix4x4D Array of matrices
IImage Raster image
IArrayUVCoordinates Array of texture coordinates
ITexture IImage + UV coordinates + IArrayIndexTriplet
IFrame Captured frame
IMesh 3D surface without texture
IFrameMesh 3D surface obtained from the scanner (IMesh + IImage)
ICompositeMesh 3D surface obtained from algorithms (IMesh + ITexture)
IScan Set of IFrameMeshes
ICompositeContainer Set of ICompositeMeshes
IModel Set of IScans and ICompositeContainer
IProject Set of methods designed to work with data on a disk

Geometry Information

IModel is an array that includes both IScan and ICompositeContainer, although the latter might be empty.

Note
Don't confuse IModel with the concept of model in Artec Studio. Indeed, IModel is roughly equivalent to marking state for scans and models in the Workspace panel.

IСompositeСontainer mirrors the IScan's structure except for ScannerType. Another distinction is that the source of the surfaces (CompositeMeshes) is the fusion algorithm output or various mesh upload.

FrameMeshes make sense when they are stored in a sequence container and feature information on their relative positions. IScan is a minimum unit for storing reconstructed frame-meshes with supplemental information. The structure is as follows: each FrameMesh is assigned a transformation matrix and undisclosed attributes. Scan as a single whole has its own attributes, transformation matrix and data on the source of the surfaces (ScannerType).

See the figure above for more details.

Projects

IProject is an interface designed to work with Artec Studio projects. It can save and load 3D data from the project (createNewProject() and openProject() functions). Each project consists of entries (scans and models) and has its unique identifier (UUID). Each of the entries also has its UUID and type (EntryType).

Working with projects is similar to the way we launch algorithms using the API using the launchJob() function.

Saving to Project

First you may want to create function to run a job asynchronously with progress tracking:

base::ErrorCode runJobAsynchronously(
base::IModel* srcModel, base::IModel* trgModel, base::IJob* job, const char* jobName)
{
// And use it to align the scans
base::AlgorithmWorkset workset;
workset.in = srcModel;
workset.out = trgModel;
SimpleConsoleProgress* const progress = new SimpleConsoleProgress(jobName);
base::TRef<SimpleConsoleProgress> progressRef;
progressRef.attach(progress);
workset.progress = progressRef;
workset.cancellation = NULL;
base::TRef<SleepingObserver> observer;
createSleepingObserver(&observer);
SAFE_SDK_CALL(base::launchJob(job, &workset, observer));
// Here, a real-world application should perform some useful operations instead of waiting
observer->waitForCompletion();
return observer->getResult();
}
Then use the following function to save IModel object to Artec Studio file:
base::ErrorCode saveModelAsProject(base::IModel* model, project::IProject* project, const wchar_t* projectDstPath)
{
project::ProjectSaverSettings saveSettings;
saveSettings.path = projectDstPath;
SAFE_SDK_CALL(base::generateUuid(&saveSettings.projectId));
base::TRef<base::IJob> saver;
SAFE_SDK_CALL(project->createSaver(&saver, &saveSettings));
SAFE_SDK_CALL(runJobAsynchronously(model, nullptr, saver, "Saving project"));
}

Consult project-sample.cpp for details.

Loading from Project

To load two scans, first, we need to determine their identifier (UUIDs):

base::ErrorCode loadInputScans(project::IProject* project, base::IModel** pModel)
{
// Load two scans
const int numScansToLoad = 2;
base::TRef<base::IArrayUuid> uuids;
SAFE_SDK_CALL(createArrayUuid(&uuids, numScansToLoad));
int numScans = 0;
const int numEntries = project->getEntryCount();
for (int i = 0; i < numEntries && numScans < numScansToLoad; ++i)
{
project::EntryInfo entry;
SAFE_SDK_CALL(project->getEntry(i, &entry));
if (entry.type == project::EntryType_Scan)
{
uuids->setElement(numScans, entry.uuid);
++numScans;
}
Then load them:
project::ProjectLoaderSettings settings;
settings.entryList = uuids;
base::TRef<base::IJob> loader;
SAFE_SDK_CALL(project->createLoader(&loader, &settings));
SAFE_SDK_CALL(base::createModel(pModel));
SAFE_SDK_CALL(runJobAsynchronously(nullptr, *pModel, loader, "Loading scans"));
}

Textures

IFrameMesh is designed to work with frames that have only a (single) texture obtained from the scanner. The IСompositeMesh interface, on the other hand, offers various methods for multiple textures that are outputs of an algorithm.

If your focus is only on geometry (e.g., you didn't capture or don't intend to map texture), you can use the parent class IMesh.

Coordinates and Transformation Matrices

Scanner captures frames in the coordinate system that has its origin in the center of 3D camera (primary 3D camera for Spider). After being registered, frames are assigned transformation matrices. Each scan has its own coordinate system with the origin.

scanners.png
Scanner primary camera and tripod mounting point

Mesh Coordinates

To obtain coordinates for each point of a mesh, call the IMesh::getPoints() method. This method returns IArrayPoint3F, which can return the point array using the IArrayPoint3F::getPointer() method.

Texture Coordinates (UV)

The IFrameMesh::getUVCoordinates() method returns UV coordinates for each point of a mesh. Since not each frame has texture, first check it using the isTextured() method.

Calculating Coordinate-System Offset

To move frames from the scanner camera coordinate system to the tripod mounting point, do the following:

  1. Obtain frame transformation matrix using getTransformation
  2. Find invertible matrix of the offset calculation matrix (see below)
  3. Multiply transformation and invertible matrices.
// Matrix for Eva scanner
1 0 0 0
0 0.983 -0.186 44.633
0 0.186 0.983 -27.776
0 0 0 1
// Matrix for Spider scanner
-1 0 0 0
0 0.954709 0.297542 120.97
0 0.297542 -0.954709 16.053
0 0 0 1
Note
Don't forger to recalculate texture matrix into the new coordinate system.
  1. Use getTextureMappingMatrix()
  2. Save matrix
  3. Call IFrameMesh::mapTexture.

Algorithms' Ins and Outs

Processing 3D Data outlines basic concepts of using algorithms. The IAlgorithm interface inherits from IJob, which represents a basic multithreaded work item. To run an IJob-based algorithm task, use either of the following calls:

Notification About Completion

To receive notification regarding completion of an IJob, implement your own completed() method for a JobObserverBase descendent. See project-sample.cpp for details.

IRef, TRef and RefBase: Reference Counting

For convenience, API includes the following classes related to reference counting.

We recommend using TRef when working with classes that have names starting with I (e.g., IScanner ):

using namespace artec::sdk::base;
ErrorCode ec = createBlob(&blob, size);

The example below illustrates how to use a custom class with reference counting and efficient memory management:

using namespace artec::sdk::base;
ErrorCode ec = createFrameMesh( &surface, points_count, triangles_count );
if( ErrorCode_OK != ec)
return ec;
TArrayPoint3F points = surface->getPoints();
TArrayIndexTriplet triangles = surface->getTriangles();
...
points[last_point].x = sett.minBound.x + j * step_.u;
points[last_point].y = sett.maxBound.y - i * step_.v;
points[last_point].z = img_data[pos];
...
triangles[last_tri].data[0] = pts_buffer[pos];
triangles[last_tri].data[1] = pts_buffer[pos+img_width];
triangles[last_tri].data[2] = pts_buffer[pos+1];