[ismrmrd] 26/177: Added Cpp Dataset type. Can now read/write XML header and Acquisitions.

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Wed Jan 14 20:01:58 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to annotated tag v1.1.0.beta.1
in repository ismrmrd.

commit 90cdaf0653c5318d8e43194d8f0930fbd261c41c
Author: Souheil Inati <souheil.inati at nih.gov>
Date:   Wed Aug 27 13:34:15 2014 -0400

    Added Cpp Dataset type.  Can now read/write XML header and Acquisitions.
---
 CMakeLists.txt              |  3 +-
 doc/doxygen/Doxyfile.in     |  6 ++--
 examples/c++/basic_test.cpp | 63 ++++++++++++++++++++++++++++++++++++-
 examples/c/main.c           | 16 ++++++++++
 ismrmrd.c                   | 22 ++++++++++---
 ismrmrd.cpp                 | 41 ++++++++++++++++++++++--
 ismrmrd.h                   | 23 ++++++++++++--
 ismrmrd_dataset.cpp         | 76 +++++++++++++++++++++++++++++++++++++++++++++
 ismrmrd_dataset.h           | 29 +++++++++++++++++
 9 files changed, 266 insertions(+), 13 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19d40b0..d848309 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,7 @@ add_library(ismrmrd SHARED
 		    ismrmrd.c 
 		    ismrmrd.cpp 
 		    ismrmrd_dataset.c
+		    ismrmrd_dataset.cpp
   		    xml/ismrmrd_xml.cpp
   		    xml/ismrmrd_meta.cpp
   		    xml/pugixml.cpp)
@@ -73,7 +74,7 @@ install(FILES
 # copy the examples directory
 install(DIRECTORY examples DESTINATION .)
 
-#add_subdirectory(doc)
+add_subdirectory(doc)
 #add_subdirectory(utilities)
 #add_subdirectory(tests)
 #add_subdirectory(matlab)
diff --git a/doc/doxygen/Doxyfile.in b/doc/doxygen/Doxyfile.in
index b11e86e..39e238c 100644
--- a/doc/doxygen/Doxyfile.in
+++ b/doc/doxygen/Doxyfile.in
@@ -629,7 +629,7 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = @CMAKE_CURRENT_SOURCE_DIR@/../../ @CMAKE_CURRENT_BINARY_DIR@/../../src/xsd/
+INPUT                  = @CMAKE_SOURCE_DIR@ @CMAKE_SOURCE_DIR@/xml
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -653,7 +653,7 @@ FILE_PATTERNS          =
 # should be searched for input files as well. Possible values are YES and NO.
 # If left blank NO is used.
 
-RECURSIVE              = YES
+RECURSIVE              = NO
 
 # The EXCLUDE tag can be used to specify files and/or directories that should
 # excluded from the INPUT source files. This way you can easily exclude a
@@ -682,7 +682,7 @@ EXCLUDE_PATTERNS       =
 # wildcard * is used, a substring. Examples: ANamespace, AClass,
 # AClass::ANamespace, ANamespace::*Test
 
-EXCLUDE_SYMBOLS        = ISMRMRD::complex_t ISMRMRD::double_complex_t ISMRMRD::AcquisitionHeader_with_data ISMRMRD::ImageHeader_with_data 
+EXCLUDE_SYMBOLS        = 
 
 # The EXAMPLE_PATH tag can be used to specify one or more files or
 # directories that contain example code fragments that are included (see
diff --git a/examples/c++/basic_test.cpp b/examples/c++/basic_test.cpp
index 099efbf..2943974 100644
--- a/examples/c++/basic_test.cpp
+++ b/examples/c++/basic_test.cpp
@@ -1,6 +1,7 @@
 #include <iostream>
 #include "ismrmrd.h"
 #include "ismrmrd_xml.h"
+#include "ismrmrd_dataset.h"
 
 int main (int args, char** argv) {
 
@@ -17,6 +18,14 @@ int main (int args, char** argv) {
   std::cout << "Flags 2: " << acqhdr.flags() << std::endl;
   std::cout << "ACQ_FIRST_IN_SLICE: " << acqhdr.isFlagSet(ISMRMRD_ACQ_FIRST_IN_SLICE) << std::endl;
 
+  // How to use the AcquisitionHeader as a wrapper to the C struct.
+  ISMRMRD_AcquisitionHeader c_acqhdr;
+  ismrmrd_init_acquisition_header(&c_acqhdr);
+  c_acqhdr.flags = 64;
+  
+  AcquisitionHeader acqhdr2(&c_acqhdr);
+  std::cout << "AcquisitionHeader copy: flags: " << acqhdr2.flags() << std::endl;
+  
   Acquisition acq;
   std::cout << "Version: " << acq.version() << std::endl;
   std::cout << "Flags 0: " << acq.flags() << std::endl;
@@ -31,8 +40,60 @@ int main (int args, char** argv) {
   acq.number_of_samples(64);
   std::cout << "Number of samples: " << acq.number_of_samples() << std::endl;
   
+  Acquisition acq2(acq);
+  std::cout << "Acquisition flags: " << acq.flags() << "    Acquisition copy flags: " << acq2.flags() << std::endl;
+  std::cout << "Acquisition ACQ_FIRST_IN_SLICE: " << acq.isFlagSet(ISMRMRD_ACQ_FIRST_IN_SLICE) << std::endl;
+  std::cout << "Acquisition copy ACQ_FIRST_IN_SLICE: " << acq2.isFlagSet(ISMRMRD_ACQ_FIRST_IN_SLICE) << std::endl;
+  std::cout << "Acquisition nsamp: " << acq.number_of_samples() << "    Acquisition copy nsamp: " << acq2.number_of_samples() << std::endl;
+ 
+  // How to use the Acquisition as a wrapper to the C struct.
+  ISMRMRD_Acquisition c_acq;
+  ismrmrd_init_acquisition(&c_acq);
+  c_acq.head.number_of_samples = 128;
+  c_acq.head.active_channels = 4;
+  ismrmrd_make_consistent_acquisition(&c_acq);
+  for (int k=0; k<c_acq.head.number_of_samples; k++) {
+      for (int c=0; c<c_acq.head.active_channels; c++) {
+          c_acq.data[k*c_acq.head.active_channels + c] = std::complex<float>(1.0, 1.0);
+      }
+  }
+  ismrmrd_set_flag(&(c_acq.head.flags), ISMRMRD_ACQ_FIRST_IN_SLICE);
+  Acquisition acq3(&c_acq);
+  std::cout << "Acquisition nsamp: " << c_acq.head.number_of_samples << "    Acquisition wrapper nsamp: " << acq3.number_of_samples() << std::endl;
+  std::cout << "Acquisition data[4]: " << c_acq.data[4].real() << "      Acquisition wrapper data[4]: " << acq3.data()[4].real() << std::endl;
+
+  // Open an existing file
+  Dataset dataset1 = Dataset("myfile.h5", "/dataset", false);
+
+  // Open a second dataset
+  Dataset dataset2 = Dataset("myfile2.h5", "/dataset", true);
+  
+  // Read the header from file 1
+  std::string xmlstring;
+  dataset1.readHeader(xmlstring);
+  std::cout << "XML Header: " << xmlstring << std::endl;
 
-  ISMRMRD::IsmrmrdHeader h;
+  // Write the header to file 2
+  dataset2.writeHeader(xmlstring);
+  
+  // Read the number of acquisitions
+  unsigned long numacq = dataset1.getNumberOfAcquisitions();
+  std::cout << "Number of acquisitions: " << numacq << std::endl;
+  
+  // Read the first few acquisitions
+  if (numacq > 3) { numacq=3; }
+
+  for (unsigned long n = 0; n<numacq; n++) {
+      Acquisition * acqref = dataset1.readAcquisition(n);
+      std::cout << "Acquisition " << n << " nsamp: " << acqref->number_of_samples() << std::endl;
+      std::cout << "Acquisition " << n << " flags: " << acqref->flags() << std::endl;
+      std::cout << "Acquisition " << n << " data[4]: " << acqref->data()[4].real() << std::endl;
+      dataset2.appendAcquisition(* acqref);
+      delete acqref;
+  }
+  std::cout << "Dataset2: number of acquisitions: " << dataset2.getNumberOfAcquisitions() << std::endl;
+  
+  //ISMRMRD::IsmrmrdHeader h;
   //serialize(h,std::cout);
 
   return 0;
diff --git a/examples/c/main.c b/examples/c/main.c
index ab16e0d..c3e7699 100644
--- a/examples/c/main.c
+++ b/examples/c/main.c
@@ -34,8 +34,12 @@ int main(void)
 
     /* Append some acquisitions */
     ISMRMRD_Acquisition acq;
+    // must initialize an acquisition before you can use it
+    ismrmrd_init_acquisition(&acq);
     int nacq_write = 5;
     for (int n=0; n < nacq_write; n++) {
+        // must free an acquisition before you can reinitialize it
+        ismrmrd_init_acquisition(&acq);
         ismrmrd_init_acquisition(&acq);
         acq.head.number_of_samples = 128;
         acq.head.active_channels = 4;
@@ -75,6 +79,7 @@ int main(void)
 
     /* read the next to last one */
     ISMRMRD_Acquisition acq2;
+    ismrmrd_init_acquisition(&acq2);
     unsigned long index = 0;
     if (nacq_read>1) {
         index = nacq_read - 1;
@@ -88,7 +93,18 @@ int main(void)
     printf("Flags: %llu\n", acq2.head.flags);
     printf("Data[4]: %f, %f\n", creal(acq2.data[4]), cimag(acq2.data[4]));
     
+    ISMRMRD_Acquisition acq3;
+    ismrmrd_init_acquisition(&acq3);
+    ismrmrd_copy_acquisition(&acq3, &acq2);
+    
+    printf("Pointers 3: %p\t 2: %p\n", (void *) acq3.data, (void *) acq2.data);
+    printf("Data 3: %f\t 2: %f\n", creal(acq3.data[4]), creal(acq2.data[4]));
+        
     /* Clean up */
+    /* This frees the internal memory of the acquisitions */
+    ismrmrd_cleanup_acquisition(&acq);
+    ismrmrd_cleanup_acquisition(&acq2);
+    ismrmrd_cleanup_acquisition(&acq3);
     free(xmlstring);
 
     /* Close the dataset */
diff --git a/ismrmrd.c b/ismrmrd.c
index 8124128..5c2d930 100644
--- a/ismrmrd.c
+++ b/ismrmrd.c
@@ -41,8 +41,19 @@ void ismrmrd_init_acquisition_header(ISMRMRD_AcquisitionHeader *hdr) {
 
 void ismrmrd_init_acquisition(ISMRMRD_Acquisition *acq) {
     ismrmrd_init_acquisition_header(&acq->head);
-    acq->traj = NULL;
-    acq->data = NULL;
+    acq->traj = (float *)malloc(ismrmrd_size_of_acquisition_traj(acq));
+    acq->data = (complex_float_t *)malloc(ismrmrd_size_of_acquisition_data(acq));
+}
+
+void ismrmrd_cleanup_acquisition(ISMRMRD_Acquisition *acq) {
+    free(acq->data);
+    free(acq->traj);
+}
+    
+ISMRMRD_Acquisition * ismrmrd_create_acquisition() {
+    ISMRMRD_Acquisition *acq = (ISMRMRD_Acquisition *) malloc(sizeof(ISMRMRD_Acquisition));
+    ismrmrd_init_acquisition(acq);
+    return acq;
 }
 
 void ismrmrd_free_acquisition(ISMRMRD_Acquisition *acq) {
@@ -52,10 +63,13 @@ void ismrmrd_free_acquisition(ISMRMRD_Acquisition *acq) {
 }
 
 void ismrmrd_copy_acquisition(ISMRMRD_Acquisition *acqdest, const ISMRMRD_Acquisition *acqsource) {
+    /* Copy the header */
     memcpy(&acqdest->head, &acqsource->head, sizeof(ISMRMRD_AcquisitionHeader));
+    /* Reallocate memory for the trajectory and the data*/
     ismrmrd_make_consistent_acquisition(acqdest);
-    memcpy(&acqdest->traj, &acqsource->traj, ismrmrd_size_of_acquisition_traj(acqdest));
-    memcpy(&acqdest->data, &acqsource->data, ismrmrd_size_of_acquisition_data(acqdest));
+    /* Copy the trajectory and the data */
+    memcpy(acqdest->traj, acqsource->traj, ismrmrd_size_of_acquisition_traj(acqsource));
+    memcpy(acqdest->data, acqsource->data, ismrmrd_size_of_acquisition_data(acqsource));
 }
 
 int ismrmrd_make_consistent_acquisition(ISMRMRD_Acquisition *acq) {
diff --git a/ismrmrd.cpp b/ismrmrd.cpp
index 0a9b4c7..7828ae6 100644
--- a/ismrmrd.cpp
+++ b/ismrmrd.cpp
@@ -5,8 +5,13 @@ namespace ISMRMRD {
 //
 // AcquisitionHeader class implementation
 //
+// Constructors
 AcquisitionHeader::AcquisitionHeader() {
-    ismrmrd_init_acquisition_header(&(head_));
+    ismrmrd_init_acquisition_header(&head_);
+};
+
+AcquisitionHeader::AcquisitionHeader(const ISMRMRD_AcquisitionHeader *head) {
+    memcpy(&head_, head, sizeof(ISMRMRD_AcquisitionHeader));
 };
 
 // Accessors and mutators
@@ -128,9 +133,36 @@ void AcquisitionHeader::clearAllFlags() {
 //
 // Acquisition class Implementation
 //
+// Constructors, assignment operator, destructor
 Acquisition::Acquisition() {
     ismrmrd_init_acquisition(&acq_);
-};
+}
+
+Acquisition::Acquisition(const Acquisition &other) {
+    // This is a deep copy
+    ismrmrd_init_acquisition(&acq_);
+    ismrmrd_copy_acquisition(&acq_, &other.acq_);
+}
+
+Acquisition::Acquisition(const ISMRMRD_Acquisition *acq) {
+    // This is a deep copy
+    ismrmrd_init_acquisition(&acq_);
+    ismrmrd_copy_acquisition(&acq_, acq);
+}
+
+Acquisition & Acquisition::operator= (const Acquisition &other) {
+    // Assignment makes a copy
+    if (this != &other )
+    {
+        ismrmrd_init_acquisition(&acq_);
+        ismrmrd_copy_acquisition(&acq_, &other.acq_);
+    }
+    return *this;
+}
+
+Acquisition::~Acquisition() {
+    ismrmrd_cleanup_acquisition(&acq_);
+}
 
 // Accessors and mutators
 const uint16_t &Acquisition::version() {
@@ -235,6 +267,11 @@ int32_t (&Acquisition::user_int()) [ISMRMRD_USER_INTS] { return acq_.head.user_i
 
 float (&Acquisition::user_float()) [ISMRMRD_USER_FLOATS] { return acq_.head.user_float; };
 
+// Data and Trajectory accessors
+complex_float_t * Acquisition::data() { return acq_.data; };
+
+float * Acquisition::traj() { return acq_.traj; };
+
 // Flag methods
 bool Acquisition::isFlagSet(const uint64_t val) {
     return ismrmrd_is_flag_set(acq_.head.flags, val);
diff --git a/ismrmrd.h b/ismrmrd.h
index 0fcb6e3..e5c92ac 100644
--- a/ismrmrd.h
+++ b/ismrmrd.h
@@ -210,13 +210,15 @@ typedef struct ISMRMRD_Acquisition {
     complex_float_t *data;
 } ISMRMRD_Acquisition;
 
-void ismrmrd_init_acquisition(ISMRMRD_Acquisition *acq);
+ISMRMRD_Acquisition * ismrmrd_create_acquisition();
 void ismrmrd_free_acquisition(ISMRMRD_Acquisition *acq);
+void ismrmrd_init_acquisition(ISMRMRD_Acquisition *acq);
+void ismrmrd_cleanup_acquisition(ISMRMRD_Acquisition *acq);
 void ismrmrd_copy_acquisition(ISMRMRD_Acquisition *acqdest, const ISMRMRD_Acquisition *acqsource);
 int ismrmrd_make_consistent_acquisition(ISMRMRD_Acquisition *acq);
 size_t ismrmrd_size_of_acquisition_traj(const ISMRMRD_Acquisition *acq);
 size_t ismrmrd_size_of_acquisition_data(const ISMRMRD_Acquisition *acq);
-
+    
 /**********/
 /* Images */
 /**********/
@@ -338,8 +340,13 @@ void ismrmrd_quaternion_to_directions(float quat[4], float read_dir[3], float ph
 
 class AcquisitionHeader {
 public:
+    // Constructors
     AcquisitionHeader();
+    AcquisitionHeader(const ISMRMRD_AcquisitionHeader *head);
 
+    // TODO
+    // Do we need to define an assignment operator?
+    
     // Accessors and mutators
     const uint16_t &version();
     const uint64_t &flags();
@@ -384,8 +391,14 @@ protected:
 };
 
 class Acquisition {
+    friend class Dataset;
 public:
+    // Constructors, assignment, destructor
     Acquisition();
+    Acquisition(const Acquisition &other);
+    Acquisition(const ISMRMRD_Acquisition *acq);
+    Acquisition & operator= (const Acquisition &other);
+    ~Acquisition();
 
     // Accessors and mutators
     const uint16_t &version();
@@ -415,6 +428,12 @@ public:
     int32_t (&user_int())[ISMRMRD_USER_INTS];
     float (&user_float())[ISMRMRD_USER_FLOATS];
 
+    // Data and Trajectory accessors
+    complex_float_t * data();
+    uint64_t numDataElements();
+    float * traj();
+    uint64_t numTrajElements();
+
     // Flag methods
     bool isFlagSet(const uint64_t val);
     void setFlag(const uint64_t val);
diff --git a/ismrmrd_dataset.cpp b/ismrmrd_dataset.cpp
new file mode 100644
index 0000000..88d7a39
--- /dev/null
+++ b/ismrmrd_dataset.cpp
@@ -0,0 +1,76 @@
+#include "ismrmrd_dataset.h"
+
+namespace ISMRMRD {
+//
+// Dataset class implementation
+//
+// Constructor
+Dataset::Dataset(const char* filename, const char* groupname, bool create_file_if_needed)
+{
+    // TODO error checking and exception throwing
+    // Initialize the dataset
+    int status;
+    status = ismrmrd_init_dataset(&dset_, filename, groupname);
+    // Open the file
+    status = ismrmrd_open_dataset(&dset_, create_file_if_needed);
+}
+
+// Destructor
+Dataset::~Dataset()
+{
+    int status = ismrmrd_close_dataset(&dset_);
+}
+
+// XML Header
+int Dataset::writeHeader(const std::string& xmlstring)
+{
+    int status = ismrmrd_write_header(&dset_, xmlstring.c_str());
+    return status;
+}
+
+int Dataset::writeHeader(const char* xml)
+{
+    int status = ismrmrd_write_header(&dset_, xml);
+    return status;
+}
+
+int Dataset::readHeader(std::string& xmlstring){
+    char * temp = ismrmrd_read_header(&dset_);
+    xmlstring = std::string(temp);
+    free(temp);
+    return ISMRMRD_NOERROR;
+}
+
+char * Dataset::readHeader()
+{
+    // The C-API uses malloc.  In Cpp we expect pointers to have been created with new,
+    // so we make a copy.
+    char * temp = ismrmrd_read_header(&dset_);
+    size_t xmllength = strlen(temp);
+    char * xml = new char[xmllength];
+    memcpy(xml, temp, xmllength);
+    free(temp);
+    return xml;
+}
+
+// Acquisitions
+int Dataset::appendAcquisition(const Acquisition &acq)
+{
+    int status = ismrmrd_append_acquisition(&dset_, &acq.acq_);
+    return status;
+}
+
+Acquisition * Dataset::readAcquisition(unsigned long index)
+{
+    Acquisition * acq = new Acquisition();
+    int status = ismrmrd_read_acquisition(&dset_, index, &acq->acq_);
+    return acq;
+}
+
+unsigned long Dataset::getNumberOfAcquisitions()
+{
+    unsigned long num =  ismrmrd_get_number_of_acquisitions(&dset_);
+    return num;
+}
+
+} // namespace ISMRMRD
diff --git a/ismrmrd_dataset.h b/ismrmrd_dataset.h
index ca74cd9..1f589de 100644
--- a/ismrmrd_dataset.h
+++ b/ismrmrd_dataset.h
@@ -146,6 +146,35 @@ int ismrmrd_get_number_of_arrays(const ISMRMRD_Dataset *dset, const char *varnam
     
 #ifdef __cplusplus
 } /* extern "C" */
+
+//
+//  ISMRMRD Datset C++ Interface
+//
+
+// TODO:
+// - exports as needed
+class Dataset {
+public:
+    // Constructor and destructor
+    Dataset(const char* filename, const char* groupname, bool create_file_if_needed = true);
+    ~Dataset();
+    
+    // Methods
+    // XML Header
+    int writeHeader(const std::string& xmlstring);
+    int writeHeader(const char* xml);
+    int readHeader(std::string& xmlstring);
+    char * readHeader();
+    // Acquisitions
+    int appendAcquisition(const Acquisition &acq);
+    Acquisition * readAcquisition(unsigned long index);
+    unsigned long getNumberOfAcquisitions();
+
+protected:
+    ISMRMRD_Dataset dset_;
+};
+
+
 } /* ISMRMRD namespace */
 #endif
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/ismrmrd.git



More information about the debian-science-commits mailing list