Skip to content

Commit

Permalink
adds python interface to fetch sparse labels from DVID
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephen Plaza committed Nov 2, 2017
1 parent 10e7349 commit 8f3628e
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 5 deletions.
5 changes: 2 additions & 3 deletions libdvid/DVIDNodeService.h
Original file line number Diff line number Diff line change
Expand Up @@ -846,12 +846,11 @@ class DVIDNodeService {
* \param bodyid body label id
* \param labelname name of labelarray datatype
* \param maskblocks libdvid blocks encoding 0/255 byte mask for body
* \param maxsize the maximum size body size allowed to trigger downsampling (0 = no limit)
* \param erosion shrink body size erosion (0 = no erosion)
* \param scale resolution to use to fetch body (-1 = use default 0 or determined by maxsize)
* \param maxsize the maximum size body size allowed to trigger downsampling (0 = no limit)
* \return scale resolution of mask
*/
int get_sparselabelmask(std::uint64_t bodyid, std::string labelname, std::vector<DVIDCompressedBlock>& maskblocks, unsigned long long maxsize=0, int scale=-1);
int get_sparselabelmask(std::uint64_t bodyid, std::string labelname, std::vector<DVIDCompressedBlock>& maskblocks, int scale=-1, unsigned long long maxsize=0);

/*!
* Fetches sparse label volume as a series of block masks using labelarray interface.
Expand Down
3 changes: 3 additions & 0 deletions libdvid/DVIDVoxels.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ typedef DVIDVoxels<uint8, 3> Roi3D;
//! 2D label volume
typedef DVIDVoxels<uint64, 2> Labels2D;

//! 2D array of coordinates
typedef DVIDVoxels<int32, 2> Coords2D;

//! 2D 8-bit volume (corresponding to grayscale)
typedef DVIDVoxels<uint8, 2> Grayscale2D;

Expand Down
1 change: 1 addition & 0 deletions libdvid/Globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace libdvid {
typedef boost::uint8_t uint8;
typedef boost::uint16_t uint16;
typedef boost::uint32_t uint32;
typedef boost::int32_t int32;
typedef boost::uint64_t uint64;

//! By default everything in DVID has 32x32x32 blocks
Expand Down
2 changes: 1 addition & 1 deletion load_tests/extract_sparse_body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ int main(int argc, char** argv)
cout << "fetch labels" << endl;
{
ScopeTime overall_time;
scale = dvid_node.get_sparselabelmask(atoi(argv[7]), argv[3], maskblocks, 0, atoi(argv[8]));
scale = dvid_node.get_sparselabelmask(atoi(argv[7]), argv[3], maskblocks, atoi(argv[8]), 0);
}
cout << "num blocks: " << maskblocks.size() << endl;

Expand Down
3 changes: 3 additions & 0 deletions python/src/converters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,10 @@ namespace libdvid { namespace python {
template <> struct numpy_typenums<uint8> { static const int typenum = NPY_UINT8; };
template <> struct numpy_typenums<uint16> { static const int typenum = NPY_UINT16; };
template <> struct numpy_typenums<uint32> { static const int typenum = NPY_UINT32; };
template <> struct numpy_typenums<int32> { static const int typenum = NPY_INT32; };
template <> struct numpy_typenums<uint64> { static const int typenum = NPY_UINT64; };


//!*********************************************************************************************
//! Declares a mapping between numpy typenumbers and the corresponding dtype names
//!*********************************************************************************************
Expand All @@ -288,6 +290,7 @@ namespace libdvid { namespace python {
(NPY_UINT8, "uint8")
(NPY_UINT16, "uint16")
(NPY_UINT32, "uint32")
(NPY_INT32, "int32")
(NPY_UINT64, "uint64");

//!*********************************************************************************************
Expand Down
68 changes: 68 additions & 0 deletions python/src/libdvid_python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,62 @@ namespace libdvid { namespace python {
return result_list;
}

//! Python wrapper function for DVIDNodeService::get_sparselabelmask().
//! Instead of requiring the user to pass an "out-parameter" (not idiomatic in python),
//! This wrapper function returns the result as a python list of numpy objects.
boost::python::tuple get_sparselabelmask( DVIDNodeService & nodeService, uint64_t bodyid,
std::string labelname, int scale)
{
using namespace boost::python;

// Retrieve from DVID
std::vector<DVIDCompressedBlock> maskblocks;
nodeService.get_sparselabelmask(bodyid, labelname, maskblocks, scale);

// if there are no blocks, there should be an exception
assert(maskblocks.size() > 0);

// Convert to Python list
list result_list;

// create coordinate data
Dims_t cdims;
cdims.push_back(3); cdims.push_back(maskblocks.size());
unsigned int coordlength = 3*maskblocks.size();
int* coordsdata = new int[coordlength];
int coordindex = 0;

size_t blocksize = maskblocks[0].get_blocksize();
Dims_t bdims(3, blocksize);
size_t blength = blocksize*blocksize*blocksize;

BOOST_FOREACH(DVIDCompressedBlock const & cblock, maskblocks)
{
// Thanks to some logic in converters.hpp,
// this cast will convert the DVIDVoxels into an ndarray
// load coordinates
auto offset = cblock.get_offset();
coordsdata[coordindex++] = offset[2];
coordsdata[coordindex++] = offset[1];
coordsdata[coordindex++] = offset[0];


// create dvid voxels per cblock
auto rawdata = cblock.get_uncompressed_data()->get_raw();
Array8bit3D voxels(rawdata, blength, bdims);

result_list.append( static_cast<object>(voxels) );
}

// create coords voxel type which will be converted to an ndarray
Coords2D coords(coordsdata, coordlength, cdims);
delete []coordsdata;

// return tuple of result list and ndarray
return make_tuple(static_cast<object>(coords), result_list);
}


//! Python wrapper function for DVIDConnection::get_roi_partition().
//! (Since "return-by-reference" is not an option in Python, boost::python can't provide an automatic wrapper.)
//! Returns a tuple: (status, result_list, error_msg), where result_list is a list of SubstackZYX tuples
Expand Down Expand Up @@ -419,6 +475,7 @@ namespace libdvid { namespace python {
ndarray_to_volume<Labels3D>();
ndarray_to_volume<Grayscale2D>();
ndarray_to_volume<Labels2D>();
ndarray_to_volume<Coords2D>();

// BlockXYZ <--> BlockZYX (for python conventions)
namedtuple_converter<BlockXYZ, int, 3>::class_member_ptr_vec block_members =
Expand Down Expand Up @@ -907,6 +964,17 @@ namespace libdvid { namespace python {
":param roi: name of the roi instance \n"
":returns: list of ``BlockZYX`` coordinate tuples \n")

.def("get_sparselabelmask", &get_sparselabelmask,
( arg("service"), arg("bodyid"), arg("labelname"), arg("scale") ),
"Retrieve a list of block coordinates and masks fora given body. \n"
"The blocks returned will be ordered by Z then Y then X. \n"
"\n\n"
":param bodyid: sparse body mask to fetch \n"
":param labelname: name of segmentation type \n"
":param scale: resolution level for mask (0=no downsampling) \n"
":returns: (2d INT Nx3 array of z, y, x voxel coordinates for each block, list of 3D 8bit ndarray masks) \n")


.def("post_roi", &DVIDNodeService::post_roi,
( arg("roi_name"), arg("blocks_zyx") ),
"Load an ROI defined by a list of blocks. This command \n"
Expand Down
2 changes: 1 addition & 1 deletion src/DVIDNodeService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2049,7 +2049,7 @@ void write_subblock(T* block, T* subblock_flat, int gz, int gy, int gx, const un
});
}

int DVIDNodeService::get_sparselabelmask(uint64_t bodyid, std::string labelname, std::vector<DVIDCompressedBlock>& maskblocks, unsigned long long maxsize, int scale)
int DVIDNodeService::get_sparselabelmask(uint64_t bodyid, std::string labelname, std::vector<DVIDCompressedBlock>& maskblocks, int scale, unsigned long long maxsize)
{
if (scale == -1 && maxsize > 0) {
// TODO: get label size (need new DVID API)
Expand Down

0 comments on commit 8f3628e

Please sign in to comment.