diff --git a/README.md b/README.md index 41a7217..8cc50ed 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,10 @@ Consult the application in *example* to see many of the API features exercised. ## TODO -* Add test regressions +* Add test regressions and more documentation * Improve performance of streaming large amounts of data by eliminating unnecessary copying. -* Expand support to more datatype instances in DVID (like sparse volumes) +* Expand support to more datatype instances in DVID (like sparse volumes) and handling DVID meta-data +* Simpler package linking ## Notes diff --git a/example/libdvid_example.cpp b/example/libdvid_example.cpp index 7273de1..cbac1cf 100644 --- a/example/libdvid_example.cpp +++ b/example/libdvid_example.cpp @@ -6,6 +6,37 @@ using std::string; using namespace libdvid; +// image 1 mask +unsigned char img1_mask[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0, + 0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0, + 0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1, + 0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1, + 0,0,1,1,1,1,0,1,1,1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1, + 0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1, + 0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1, + 0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0, + 0,0,1,0,0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +// image 2 mask +unsigned char img2_mask[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}; + +int WIDTH = 28; +int HEIGHT = 11; + int main(int argc, char** argv) { if (argc != 3) { cout << "Usage: " << endl; @@ -20,7 +51,7 @@ int main(int argc, char** argv) { string label_datatype_name = "labels1"; string keyvalue_datatype_name = "keys"; - // test creation of DVID datatypes + // ** Test creation of DVID datatypes ** if(!dvid_node.create_grayscale8(gray_datatype_name)) { cout << gray_datatype_name << " already exists" << endl; } @@ -30,8 +61,61 @@ int main(int argc, char** argv) { if(!dvid_node.create_keyvalue(keyvalue_datatype_name)) { cout << keyvalue_datatype_name << " already exists" << endl; } + + // ** Write and read grayscale data ** + // create grayscale image volume + unsigned char * img_gray = new unsigned char [sizeof(img1_mask)*2]; + for (int i = 0; i < sizeof(img1_mask); ++i) { + img_gray[i] = img1_mask[i] * 255; + img_gray[i+sizeof(img1_mask)] = img2_mask[i] * 255; + } + + // create binary data string wrapper (no meta-data for now -- must explicitly create) + BinaryDataPtr graybin = BinaryData::create_binary_data((char*)(img_gray), sizeof(img1_mask)*2); + tuple start; start.push_back(0); start.push_back(0); start.push_back(0); + tuple sizes; sizes.push_back(WIDTH); sizes.push_back(HEIGHT); sizes.push_back(2); + tuple channels; channels.push_back(0); channels.push_back(1); channels.push_back(2); + + // post grayscale volume + // one could also write 2D image slices but the starting location must + // be at least an ND point where N is greater than 2 + dvid_node.write_volume_roi(gray_datatype_name, start, sizes, channels, graybin); + + // retrieve the image volume and make sure it makes the posted volume + DVIDGrayPtr graycomp; + dvid_node.get_volume_roi(gray_datatype_name, start, sizes, channels, graycomp); + unsigned char* datacomp = graycomp->get_raw(); + for (int i = 0; i < sizeof(img1_mask)*2; ++i) { + assert(datacomp[i] == img_gray[i]); + } + + // ** Write and read labels64 data ** + // create label 64 image volume + unsigned long long * img_labels = new unsigned long long [sizeof(img1_mask)*2]; + for (int i = 0; i < sizeof(img1_mask); ++i) { + img_labels[i] = img1_mask[i] * 255; + img_labels[i+sizeof(img1_mask)] = img2_mask[i] * 255; + } + + // create binary data string wrapper (64 bits per pixel) + BinaryDataPtr labelbin = BinaryData::create_binary_data((char*)(img_labels), sizeof(img1_mask)*2*8); + + // post labels volume + // one could also write 2D image slices but the starting location must + // be at least an ND point where N is greater than 2 - // test key value interface + // !! not currently working + //dvid_node.write_volume_roi(label_datatype_name, start, sizes, channels, labelbin); + + // retrieve the image volume and make sure it makes the posted volume + DVIDLabelPtr labelcomp; + dvid_node.get_volume_roi(label_datatype_name, start, sizes, channels, labelcomp); + unsigned long long* labeldatacomp = labelcomp->get_raw(); + for (int i = 0; i < sizeof(img1_mask)*2; ++i) { + //assert(labeldatacomp[i] == img_labels[i]); + } + + // ** Test key value interface ** Json::Value data_init; data_init["hello"] = "world"; dvid_node.put(keyvalue_datatype_name, "spot0", data_init); diff --git a/libdvid/BinaryData.h b/libdvid/BinaryData.h index 15a94eb..bcc9ef4 100644 --- a/libdvid/BinaryData.h +++ b/libdvid/BinaryData.h @@ -14,9 +14,9 @@ typedef boost::shared_ptr BinaryDataPtr; class BinaryData { public: - static BinaryDataPtr create_binary_data(const char* data_) + static BinaryDataPtr create_binary_data(const char* data_, unsigned int length) { - return BinaryDataPtr(new BinaryData(data_)); + return BinaryDataPtr(new BinaryData(data_, length)); } static BinaryDataPtr create_binary_data(std::ifstream& fin) { @@ -33,7 +33,7 @@ class BinaryData { } ~BinaryData() {} private: - BinaryData(const char* data_) : data(data_) {} + BinaryData(const char* data_, unsigned int length) : data(data_, length) {} BinaryData(std::ifstream& fin) { data.assign( (std::istreambuf_iterator(fin) ), diff --git a/libdvid/DVIDNode.h b/libdvid/DVIDNode.h index bfbdf66..0f04550 100644 --- a/libdvid/DVIDNode.h +++ b/libdvid/DVIDNode.h @@ -23,12 +23,12 @@ class DVIDNode { bool create_grayscale8(std::string datatype_name); bool create_labels64(std::string datatype_name); - void get_gray_slice(std::string datatype_instance, tuple start, + void get_volume_roi(std::string datatype_instance, tuple start, tuple sizes, tuple channels, DVIDGrayPtr& gray); - void get_label_slice(std::string datatype_instance, tuple start, + void get_volume_roi(std::string datatype_instance, tuple start, tuple sizes, tuple channels, DVIDLabelPtr& labels); - void write_label_slice(std::string datatype_instance, tuple start, + void write_volume_roi(std::string datatype_instance, tuple start, tuple sizes, tuple channels, BinaryDataPtr data); // Key-Value Interface diff --git a/libdvid/DVIDVoxels.h b/libdvid/DVIDVoxels.h index 5a0d563..2d0d156 100644 --- a/libdvid/DVIDVoxels.h +++ b/libdvid/DVIDVoxels.h @@ -11,11 +11,11 @@ class DVIDVoxels { public: static boost::shared_ptr > get_dvid_voxels(T* array_) { - return boost::shared_ptr >(new DVIDVoxels(array_)); + return boost::shared_ptr >(new DVIDVoxels(array_)); } static boost::shared_ptr > get_dvid_voxels(std::string& data_str) { - return boost::shared_ptr >(new DVIDVoxels(data_str)); + return boost::shared_ptr >(new DVIDVoxels(data_str)); } ~DVIDVoxels() diff --git a/src/DVIDNode.cpp b/src/DVIDNode.cpp index b4806b2..05f112a 100644 --- a/src/DVIDNode.cpp +++ b/src/DVIDNode.cpp @@ -10,7 +10,6 @@ using namespace boost::network; using std::ifstream; using std::set; using std::stringstream; Json::Reader json_reader; - namespace libdvid { DVIDNode::DVIDNode(DVIDServer web_addr_, UUID uuid_) : @@ -65,7 +64,7 @@ void DVIDNode::put(std::string keyvalue, std::string key, Json::Value& data) { stringstream datastr; datastr << data; - BinaryDataPtr bdata = BinaryData::create_binary_data(datastr.str().c_str()); + BinaryDataPtr bdata = BinaryData::create_binary_data(datastr.str().c_str(), datastr.str().length()); put(keyvalue, key, bdata); } @@ -82,7 +81,7 @@ void DVIDNode::get(std::string keyvalue, std::string key, BinaryDataPtr& value) } std::string data = body(respdata); // ?! allow intialization to happen in constructor - value = BinaryData::create_binary_data(data.c_str()); + value = BinaryData::create_binary_data(data.c_str(), data.length()); } void DVIDNode::get(std::string keyvalue, std::string key, Json::Value& data) @@ -96,7 +95,7 @@ void DVIDNode::get(std::string keyvalue, std::string key, Json::Value& data) } } -void DVIDNode::get_gray_slice(std::string datatype_instance, tuple start, +void DVIDNode::get_volume_roi(std::string datatype_instance, tuple start, tuple sizes, tuple channels, DVIDGrayPtr& gray) { std::string volume; @@ -104,7 +103,7 @@ void DVIDNode::get_gray_slice(std::string datatype_instance, tuple start, gray = DVIDVoxels::get_dvid_voxels(volume); } -void DVIDNode::get_label_slice(std::string datatype_instance, tuple start, +void DVIDNode::get_volume_roi(std::string datatype_instance, tuple start, tuple sizes, tuple channels, DVIDLabelPtr& labels) { std::string volume; @@ -112,7 +111,7 @@ void DVIDNode::get_label_slice(std::string datatype_instance, tuple start, labels = DVIDVoxels::get_dvid_voxels(volume); } -void DVIDNode::write_label_slice(std::string datatype_instance, tuple start, +void DVIDNode::write_volume_roi(std::string datatype_instance, tuple start, tuple sizes, tuple channels, BinaryDataPtr data) { client::request requestobj(construct_volume_uri( diff --git a/todo b/todo index 0c863ce..39aa286 100644 --- a/todo +++ b/todo @@ -1,8 +1,6 @@ --make some fake image data -- perhaps write out hello world on two planes --debug - --documentation +-documentation/fix label pushing +-be careful about 0/nulls -find datatype_instance function -integration and unit tests -automatically include cppnet and boost libraries in build