Commit 814eb2718806045f3ca7727674c6c9337d0e9e8f

Authored by David Mayerich
1 parent 0288346a

fixed problems with memory allocation in stim::image

@@ -884,7 +884,7 @@ public: @@ -884,7 +884,7 @@ public:
884 /// using the following indexing: i = p*B + b 884 /// using the following indexing: i = p*B + b
885 /// @param matrix is the destination for the pixel data 885 /// @param matrix is the destination for the pixel data
886 /// @param mask is the mask 886 /// @param mask is the mask
887 - bool sift(T* matrix, unsigned char* mask = NULL){ 887 + bool sift(T* matrix, unsigned char* mask = NULL, bool PROGRESS = false){
888 size_t Lbytes = sizeof(T) * X(); 888 size_t Lbytes = sizeof(T) * X();
889 T* line = (T*) malloc( Lbytes ); //allocate space for a line 889 T* line = (T*) malloc( Lbytes ); //allocate space for a line
890 890
@@ -903,6 +903,7 @@ public: @@ -903,6 +903,7 @@ public:
903 pl++; //increment the pixel pointer 903 pl++; //increment the pixel pointer
904 } 904 }
905 } 905 }
  906 + if(PROGRESS) progress = (double)( (y+1)*Z() + 1) / (double)(Y() * Z()) * 100;
906 } 907 }
907 p += pl; //add the line increment to the running pixel index 908 p += pl; //add the line increment to the running pixel index
908 } 909 }
@@ -817,7 +817,7 @@ public: @@ -817,7 +817,7 @@ public:
817 /// using the following indexing: i = p*B + b 817 /// using the following indexing: i = p*B + b
818 /// @param matrix is the destination for the pixel data 818 /// @param matrix is the destination for the pixel data
819 /// @param mask is the mask 819 /// @param mask is the mask
820 - bool sift(T* matrix, unsigned char* mask = NULL){ 820 + bool sift(T* matrix, unsigned char* mask = NULL, bool PROGRESS = false){
821 size_t Bbytes = sizeof(T) * Z(); 821 size_t Bbytes = sizeof(T) * Z();
822 size_t XY = X() * Y(); 822 size_t XY = X() * Y();
823 T* band = (T*) malloc( Bbytes ); //allocate space for a line 823 T* band = (T*) malloc( Bbytes ); //allocate space for a line
@@ -836,6 +836,7 @@ public: @@ -836,6 +836,7 @@ public:
836 } 836 }
837 else 837 else
838 file.seekg(Bbytes, std::ios::cur); //otherwise skip this band 838 file.seekg(Bbytes, std::ios::cur); //otherwise skip this band
  839 + if(PROGRESS) progress = (double)(xy+1) / (double)XY * 100;
839 } 840 }
840 return true; 841 return true;
841 } 842 }
@@ -809,7 +809,7 @@ public: @@ -809,7 +809,7 @@ public:
809 /// using the following indexing: i = p*B + b 809 /// using the following indexing: i = p*B + b
810 /// @param matrix is the destination for the pixel data 810 /// @param matrix is the destination for the pixel data
811 /// @param mask is the mask 811 /// @param mask is the mask
812 - bool sift(T* matrix, unsigned char* mask = NULL){ 812 + bool sift(T* matrix, unsigned char* mask = NULL, bool PROGRESS = false){
813 unsigned long long XY = X() * Y(); //Number of XY pixels 813 unsigned long long XY = X() * Y(); //Number of XY pixels
814 unsigned long long L = XY * sizeof(T); //size of XY plane (in bytes) 814 unsigned long long L = XY * sizeof(T); //size of XY plane (in bytes)
815 815
@@ -827,9 +827,8 @@ public: @@ -827,9 +827,8 @@ public:
827 if(mask == NULL || mask[xy] != 0){ //if the pixel is valid 827 if(mask == NULL || mask[xy] != 0){ //if the pixel is valid
828 matrix[i*Z() + b] = band_image[xy]; //copy it to the appropriate point in the values[] array 828 matrix[i*Z() + b] = band_image[xy]; //copy it to the appropriate point in the values[] array
829 i++; 829 i++;
830 - //std::cout<<i<<std::endl;  
831 } 830 }
832 - 831 + if(PROGRESS) progress = (double)(xy+1) / (double)XY * 100;
833 } 832 }
834 } 833 }
835 834
@@ -670,13 +670,13 @@ public: @@ -670,13 +670,13 @@ public:
670 /// using the following indexing: i = b*P + p 670 /// using the following indexing: i = b*P + p
671 /// @param matrix is the destination for the pixel data 671 /// @param matrix is the destination for the pixel data
672 /// @param p is the mask 672 /// @param p is the mask
673 - bool sift(void* matrix, unsigned char* p = NULL){ 673 + bool sift(void* matrix, unsigned char* p = NULL, bool PROGRESS = false){
674 674
675 if (header.interleave == envi_header::BSQ){ //if the infile is bsq file 675 if (header.interleave == envi_header::BSQ){ //if the infile is bsq file
676 if (header.data_type == envi_header::float32) 676 if (header.data_type == envi_header::float32)
677 - return ((bsq<float>*)file)->sift((float*)matrix, p); 677 + return ((bsq<float>*)file)->sift((float*)matrix, p, PROGRESS);
678 else if (header.data_type == envi_header::float64) 678 else if (header.data_type == envi_header::float64)
679 - return ((bsq<double>*)file)->sift((double*)matrix, p); 679 + return ((bsq<double>*)file)->sift((double*)matrix, p, PROGRESS);
680 else{ 680 else{
681 std::cout << "ERROR: unidentified data type" << std::endl; 681 std::cout << "ERROR: unidentified data type" << std::endl;
682 exit(1); 682 exit(1);
@@ -685,9 +685,9 @@ public: @@ -685,9 +685,9 @@ public:
685 685
686 if (header.interleave == envi_header::BIP){ 686 if (header.interleave == envi_header::BIP){
687 if (header.data_type == envi_header::float32) 687 if (header.data_type == envi_header::float32)
688 - return ((bip<float>*)file)->sift((float*)matrix, p); 688 + return ((bip<float>*)file)->sift((float*)matrix, p, PROGRESS);
689 else if (header.data_type == envi_header::float64) 689 else if (header.data_type == envi_header::float64)
690 - return ((bip<double>*)file)->sift((double*)matrix, p); 690 + return ((bip<double>*)file)->sift((double*)matrix, p, PROGRESS);
691 else{ 691 else{
692 std::cout << "ERROR: unidentified data type" << std::endl; 692 std::cout << "ERROR: unidentified data type" << std::endl;
693 exit(1); 693 exit(1);
@@ -695,9 +695,9 @@ public: @@ -695,9 +695,9 @@ public:
695 } 695 }
696 if (header.interleave == envi_header::BIL){ 696 if (header.interleave == envi_header::BIL){
697 if (header.data_type == envi_header::float32) 697 if (header.data_type == envi_header::float32)
698 - return ((bil<float>*)file)->sift((float*)matrix, p); 698 + return ((bil<float>*)file)->sift((float*)matrix, p, PROGRESS);
699 else if (header.data_type == envi_header::float64) 699 else if (header.data_type == envi_header::float64)
700 - return ((bil<double>*)file)->sift((double*)matrix, p); 700 + return ((bil<double>*)file)->sift((double*)matrix, p, PROGRESS);
701 else{ 701 else{
702 std::cout << "ERROR: unidentified data type" << std::endl; 702 std::cout << "ERROR: unidentified data type" << std::endl;
703 exit(1); 703 exit(1);
stim/image/image.h
@@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
6 #include <vector> 6 #include <vector>
7 #include <iostream> 7 #include <iostream>
8 #include <limits> 8 #include <limits>
9 -#include <typeinfo>  
10 9
11 namespace stim{ 10 namespace stim{
12 /// This static class provides the STIM interface for loading, saving, and storing 2D images. 11 /// This static class provides the STIM interface for loading, saving, and storing 2D images.
@@ -25,8 +24,6 @@ class image{ @@ -25,8 +24,6 @@ class image{
25 size_t Y() const { return R[2]; } 24 size_t Y() const { return R[2]; }
26 size_t C() const { return R[0]; } 25 size_t C() const { return R[0]; }
27 26
28 - size_t bytes(){ return size() * sizeof(T); }  
29 -  
30 void init(){ //initializes all variables, assumes no memory is allocated 27 void init(){ //initializes all variables, assumes no memory is allocated
31 memset(R, 0, sizeof(size_t) * 3); //set the resolution and number of channels to zero 28 memset(R, 0, sizeof(size_t) * 3); //set the resolution and number of channels to zero
32 img = NULL; 29 img = NULL;
@@ -34,7 +31,6 @@ class image{ @@ -34,7 +31,6 @@ class image{
34 31
35 void unalloc(){ //frees any resources associated with the image 32 void unalloc(){ //frees any resources associated with the image
36 if(img) free(img); //if memory has been allocated, free it 33 if(img) free(img); //if memory has been allocated, free it
37 - img=NULL;  
38 } 34 }
39 35
40 36
@@ -45,16 +41,15 @@ class image{ @@ -45,16 +41,15 @@ class image{
45 41
46 void allocate(){ 42 void allocate(){
47 unalloc(); 43 unalloc();
48 - img = (T*) malloc( bytes() ); //allocate memory  
49 - memset(img, 0, bytes()); 44 + img = (T*) malloc( sizeof(T) * R[0] * R[1] * R[2] ); //allocate memory
50 } 45 }
51 46
52 void allocate(size_t x, size_t y, size_t c){ //allocate memory based on the resolution 47 void allocate(size_t x, size_t y, size_t c){ //allocate memory based on the resolution
53 - unalloc();  
54 R[0] = c; R[1] = x; R[2] = y; //set the resolution 48 R[0] = c; R[1] = x; R[2] = y; //set the resolution
55 allocate(); //allocate memory 49 allocate(); //allocate memory
56 } 50 }
57 51
  52 + size_t bytes(){ return size() * sizeof(T); }
58 53
59 size_t idx(size_t x, size_t y, size_t c = 0){ 54 size_t idx(size_t x, size_t y, size_t c = 0){
60 return y * C() * X() + x * C() + c; 55 return y * C() * X() + x * C() + c;
@@ -62,23 +57,13 @@ class image{ @@ -62,23 +57,13 @@ class image{
62 57
63 58
64 int cv_type(){ 59 int cv_type(){
65 - // The following is C++ 11 code, but causes problems on some compilers (ex. nvcc). Below is my best approximation to a solution  
66 -  
67 - //if(std::is_same<T, unsigned char>::value) return CV_MAKETYPE(CV_8U, (int)C());  
68 - //if(std::is_same<T, char>::value) return CV_MAKETYPE(CV_8S, (int)C());  
69 - //if(std::is_same<T, unsigned short>::value) return CV_MAKETYPE(CV_16U, (int)C());  
70 - //if(std::is_same<T, short>::value) return CV_MAKETYPE(CV_16S, (int)C());  
71 - //if(std::is_same<T, int>::value) return CV_MAKETYPE(CV_32S, (int)C());  
72 - //if(std::is_same<T, float>::value) return CV_MAKETYPE(CV_32F, (int)C());  
73 - //if(std::is_same<T, double>::value) return CV_MAKETYPE(CV_64F, (int)C());  
74 -  
75 - if(typeid(T) == typeid(unsigned char)) return CV_MAKETYPE(CV_8U, (int)C());  
76 - if(typeid(T) == typeid(char)) return CV_MAKETYPE(CV_8S, (int)C());  
77 - if(typeid(T) == typeid(unsigned short)) return CV_MAKETYPE(CV_16U, (int)C());  
78 - if(typeid(T) == typeid(short)) return CV_MAKETYPE(CV_16S, (int)C());  
79 - if(typeid(T) == typeid(int)) return CV_MAKETYPE(CV_32S, (int)C());  
80 - if(typeid(T) == typeid(float)) return CV_MAKETYPE(CV_32F, (int)C());  
81 - if(typeid(T) == typeid(double)) return CV_MAKETYPE(CV_64F, (int)C()); 60 + if(std::is_same<T, unsigned char>::value) return CV_MAKETYPE(CV_8U, (int)C());
  61 + if(std::is_same<T, char>::value) return CV_MAKETYPE(CV_8S, (int)C());
  62 + if(std::is_same<T, unsigned short>::value) return CV_MAKETYPE(CV_16U, (int)C());
  63 + if(std::is_same<T, short>::value) return CV_MAKETYPE(CV_16S, (int)C());
  64 + if(std::is_same<T, int>::value) return CV_MAKETYPE(CV_32S, (int)C());
  65 + if(std::is_same<T, float>::value) return CV_MAKETYPE(CV_32F, (int)C());
  66 + if(std::is_same<T, double>::value) return CV_MAKETYPE(CV_64F, (int)C());
82 67
83 std::cout<<"ERROR in stim::image::cv_type - no valid data type found"<<std::endl; 68 std::cout<<"ERROR in stim::image::cv_type - no valid data type found"<<std::endl;
84 exit(1); 69 exit(1);
@@ -86,35 +71,23 @@ class image{ @@ -86,35 +71,23 @@ class image{
86 71
87 /// Returns the value for "white" based on the dynamic range (assumes white is 1.0 for floating point images) 72 /// Returns the value for "white" based on the dynamic range (assumes white is 1.0 for floating point images)
88 T white(){ 73 T white(){
89 - // The following is C++ 11 code, but causes problems on some compilers (ex. nvcc). Below is my best approximation to a solution  
90 -  
91 - //if(std::is_same<T, unsigned char>::value) return UCHAR_MAX;  
92 - //if(std::is_same<T, unsigned short>::value) return SHRT_MAX;  
93 - //if(std::is_same<T, unsigned>::value) return UINT_MAX;  
94 - //if(std::is_same<T, unsigned long>::value) return ULONG_MAX;  
95 - //if(std::is_same<T, unsigned long long>::value) return ULLONG_MAX;  
96 - //if(std::is_same<T, float>::value) return 1.0f;  
97 - //if(std::is_same<T, double>::value) return 1.0;  
98 -  
99 - if(typeid(T) == typeid(unsigned char)) return UCHAR_MAX;  
100 - if(typeid(T) == typeid(unsigned short)) return SHRT_MAX;  
101 - if(typeid(T) == typeid(unsigned)) return UINT_MAX;  
102 - if(typeid(T) == typeid(unsigned long)) return ULONG_MAX;  
103 - if(typeid(T) == typeid(unsigned long long)) return ULLONG_MAX;  
104 - if(typeid(T) == typeid(float)) return 1.0f;  
105 - if(typeid(T) == typeid(double)) return 1.0; 74 + if(std::is_same<T, unsigned char>::value) return UCHAR_MAX;
  75 + if(std::is_same<T, unsigned short>::value) return SHRT_MAX;
  76 + if(std::is_same<T, unsigned>::value) return UINT_MAX;
  77 + if(std::is_same<T, unsigned long>::value) return ULONG_MAX;
  78 + if(std::is_same<T, unsigned long long>::value) return ULLONG_MAX;
  79 + if(std::is_same<T, float>::value) return 1.0f;
  80 + if(std::is_same<T, double>::value) return 1.0;
106 81
107 std::cout<<"ERROR in stim::image::white - no white value known for this data type"<<std::endl; 82 std::cout<<"ERROR in stim::image::white - no white value known for this data type"<<std::endl;
108 - exit(1); 83 +
109 } 84 }
110 85
111 86
112 public: 87 public:
113 88
114 /// Default constructor - creates an empty image object 89 /// Default constructor - creates an empty image object
115 - image(){  
116 - init(); //initialize all variables to zero, don't allocate any memory  
117 - } 90 + image(){ init(); } //initialize all variables to zero, don't allocate any memory
118 91
119 /// Constructor with a filename - loads the specified file 92 /// Constructor with a filename - loads the specified file
120 image(std::string filename){ //constructor initialize the image with an image file 93 image(std::string filename){ //constructor initialize the image with an image file
@@ -136,7 +109,7 @@ public: @@ -136,7 +109,7 @@ public:
136 } 109 }
137 110
138 /// Copy constructor - duplicates an image object 111 /// Copy constructor - duplicates an image object
139 - image(const stim::image<T> &I){ 112 + image(const stim::image<T>& I){
140 init(); 113 init();
141 allocate(I.X(), I.Y(), I.C()); 114 allocate(I.X(), I.Y(), I.C());
142 memcpy(img, I.img, bytes()); 115 memcpy(img, I.img, bytes());
@@ -147,7 +120,16 @@ public: @@ -147,7 +120,16 @@ public:
147 free(img); 120 free(img);
148 } 121 }
149 122
  123 + /*stim::image<T> operator=(const stim::image<T>& I){
  124 + if(&I == this) //handle self-assignment
  125 + return *this;
  126 + allocate(I.X(), I.Y(), I.C());
  127 + memcpy(img, I.img, bytes());
  128 + return *this;
  129 + }*/
  130 +
150 stim::image<T>& operator=(const stim::image<T>& I){ 131 stim::image<T>& operator=(const stim::image<T>& I){
  132 + init();
151 if(&I == this) //handle self-assignment 133 if(&I == this) //handle self-assignment
152 return *this; 134 return *this;
153 allocate(I.X(), I.Y(), I.C()); 135 allocate(I.X(), I.Y(), I.C());
@@ -160,22 +142,15 @@ public: @@ -160,22 +142,15 @@ public:
160 142
161 cv::Mat cvImage = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED); //use OpenCV to open the image file 143 cv::Mat cvImage = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED); //use OpenCV to open the image file
162 if(!cvImage.data){ 144 if(!cvImage.data){
163 - std::cout<<"ERROR stim::image::load() - unable to find image "<<filename<<" ["<<__FILE__<<" (line "<<__LINE__<<")]"<<std::endl; 145 + std::cout<<"ERROR stim::image::load() - unable to find image "<<filename<<std::endl;
164 exit(1); 146 exit(1);
165 } 147 }
166 allocate(cvImage.cols, cvImage.rows, cvImage.channels()); //allocate space for the image 148 allocate(cvImage.cols, cvImage.rows, cvImage.channels()); //allocate space for the image
167 - T* cv_ptr = (T*) cvImage.data;  
168 - if(C() == 1)  
169 - {  
170 - //if this is a single-color image, just copy the data  
171 - memcpy(img, cv_ptr, bytes());  
172 - }  
173 - if(C() == 3)  
174 - { //if this is a 3-color image, OpenCV uses BGR interleaving 149 + T* cv_ptr = (T*)cvImage.data;
  150 + if(C() == 1) //if this is a single-color image, just copy the data
  151 + memcpy(img, cv_ptr, bytes());
  152 + if(C() == 3) //if this is a 3-color image, OpenCV uses BGR interleaving
175 set_interleaved_bgr(cv_ptr, X(), Y()); 153 set_interleaved_bgr(cv_ptr, X(), Y());
176 - }  
177 -  
178 - cvImage.release();  
179 } 154 }
180 155
181 //save a file 156 //save a file
@@ -189,18 +164,16 @@ public: @@ -189,18 +164,16 @@ public:
189 get_interleaved_bgr(buffer); 164 get_interleaved_bgr(buffer);
190 cv::Mat cvImage((int)Y(), (int)X(), cv_type(), buffer); 165 cv::Mat cvImage((int)Y(), (int)X(), cv_type(), buffer);
191 cv::imwrite(filename, cvImage); 166 cv::imwrite(filename, cvImage);
192 - cvImage.release();  
193 - free(buffer);  
194 } 167 }
195 168
196 //create an image from an interleaved buffer 169 //create an image from an interleaved buffer
197 - void set_interleaved_rgb(T* buffer, size_t width, size_t height, size_t channels = 3){  
198 - allocate(width, height, channels); 170 + void set_interleaved_rgb(T* buffer, size_t width, size_t height){
  171 + allocate(width, height, 3);
199 memcpy(img, buffer, bytes()); 172 memcpy(img, buffer, bytes());
200 } 173 }
201 174
202 - void set_interleaved_bgr(T* buffer, size_t width, size_t height, size_t channels = 3){  
203 - allocate(width, height, channels); 175 + void set_interleaved_bgr(T* buffer, size_t width, size_t height){
  176 + allocate(width, height, 3);
204 for(size_t c = 0; c < C(); c++){ //copy directly 177 for(size_t c = 0; c < C(); c++){ //copy directly
205 for(size_t y = 0; y < Y(); y++){ 178 for(size_t y = 0; y < Y(); y++){
206 for(size_t x = 0; x < X(); x++){ 179 for(size_t x = 0; x < X(); x++){
@@ -380,34 +353,6 @@ public: @@ -380,34 +353,6 @@ public:
380 353
381 return r; //return the inverted image 354 return r; //return the inverted image
382 } 355 }
383 -  
384 - /// Invert an image by calculating I1 = alpha - I0, where alpha is the maximum image value  
385 - image<T> invert(){  
386 - size_t N = size(); //calculate the total number of values in the image  
387 - image<T> r(X(), Y(), C()); //allocate space for the resulting image  
388 - T white_val = maxv();  
389 - for(size_t n = 0; n < N; n++)  
390 - r.img[n] = white_val - img[n]; //perform the inversion  
391 -  
392 - return r; //return the inverted image  
393 - }  
394 -  
395 - ///crops the image from x1 to x0 and y1 to y0 and returns a new (smaller) image.  
396 - image<T> crop(int x0, int x1, int y0, int y1)  
397 - {  
398 -  
399 - image<T> ret(x1-x0, y1-y0, C());  
400 - int newWidth = x1-x0;  
401 - int destidx, srcidx;  
402 - ///for each row, cut what amount of data from the original and put it into the new copy.  
403 - for(int i = 0; i < (y1-y0); i++)  
404 - {  
405 - destidx = i*newWidth*C(); ///destination index one per each row  
406 - srcidx = ((i+(y0))*X()+x0)*C(); ///source index, one per each row.  
407 - memcpy(&ret.img[destidx], &img[srcidx], sizeof(T)*newWidth*C());  
408 - }  
409 - return ret;  
410 - }  
411 356
412 image<T> srgb2lab(){ 357 image<T> srgb2lab(){
413 std::cout<<"ERROR stim::image::srgb2lab - function has been broken, re-implement."<<std::endl; 358 std::cout<<"ERROR stim::image::srgb2lab - function has been broken, re-implement."<<std::endl;
@@ -426,7 +371,6 @@ public: @@ -426,7 +371,6 @@ public:
426 exit(1); 371 exit(1);
427 } 372 }
428 373
429 -  
430 // leila's code for non_interleaving data in 3D 374 // leila's code for non_interleaving data in 3D
431 //create an data set from an interleaved buffer 375 //create an data set from an interleaved buffer
432 void set_interleaved3(T* buffer, size_t width, size_t height, size_t depth, size_t channels = 3){ 376 void set_interleaved3(T* buffer, size_t width, size_t height, size_t depth, size_t channels = 3){