Commit 26da82c8bdc9c3289d5dfae45b2629acd99edda6

Authored by David Mayerich
1 parent 983b730b

finalized stim::gl_texture edits for Windows

stim/gl/gl_texture.h
... ... @@ -5,8 +5,11 @@
5 5 #include <iostream>
6 6 #include <vector>
7 7 #include "../grids/image_stack.h"
8   -#include <GL/glut.h>
9   -#include <GL/glext.h>
  8 +//Visual Studio requires GLEW
  9 +#ifdef _WIN32
  10 + #include <GL/glew.h>
  11 +#endif
  12 +//#include <GL/glut.h>
10 13 #include <stim/gl/error.h>
11 14 namespace stim{
12 15  
... ... @@ -15,21 +18,21 @@ class gl_texture
15 18 Uses image_stack class in order to create a texture object.
16 19 */
17 20  
18   -template<typename T>
19   -class gl_texture : public virtual image_stack<T>
  21 +template<typename T, typename F = float>
  22 +class gl_texture : public virtual image_stack<T, F>
20 23 {
21 24 protected:
22 25 //std::string path;
23 26 GLuint texID; //OpenGL object
24 27 GLenum texture_type; //1D, 2D, 3D
25   - GLint interpType;
26   - GLint texWrap;
27   - GLenum type;
28   - GLenum format;
  28 + GLint interpolation;
  29 + GLint wrap;
  30 + GLenum cpu_type;
  31 + GLenum gpu_type;
  32 + GLenum format; //format for the texture (GL_RGBA, GL_LUMINANCE, etc.)
29 33 using image_stack<T>::R;
30   - using image_stack<T>::S;
  34 + //using image_stack<T>::S;
31 35 using image_stack<T>::ptr;
32   - using image_stack<T>::samples;
33 36  
34 37 /// Sets the internal texture_type, based on the data dimensions
35 38 void setTextureType(){
... ... @@ -44,22 +47,186 @@ class gl_texture : public virtual image_stack&lt;T&gt;
44 47 //initializes important variables
45 48 void init() {
46 49 texID = 0; //initialize texture ID to zero, default if OpenGL returns an error
47   - memset(R, 0, sizeof)
  50 + memset(R, 0, sizeof(size_t));
  51 + memset(S, 0, sizeof(F));
  52 + }
  53 +
  54 + //guesses the color format of the texture
  55 + GLenum guess_format(){
  56 + size_t channels = R[0];
  57 + switch(channels){
  58 + case 1:
  59 + return GL_LUMINANCE;
  60 + case 2:
  61 + return GL_RG;
  62 + case 3:
  63 + return GL_RGB;
  64 + case 4:
  65 + return GL_RGBA;
  66 + default:
  67 + std::cout<<"Error in stim::gl_texture - unable to guess texture format based on number of channels ("<<R[4]<<")"<<std::endl;
  68 + exit(1);
  69 + }
  70 + }
  71 +
  72 + //guesses the OpenGL CPU data type based on T
  73 + GLenum guess_cpu_type(){
  74 + // The following is C++ 11 code, but causes problems on some compilers (ex. nvcc). Below is my best approximation to a solution
  75 +
  76 + //if(std::is_same<T, unsigned char>::value) return CV_MAKETYPE(CV_8U, (int)C());
  77 + //if(std::is_same<T, char>::value) return CV_MAKETYPE(CV_8S, (int)C());
  78 + //if(std::is_same<T, unsigned short>::value) return CV_MAKETYPE(CV_16U, (int)C());
  79 + //if(std::is_same<T, short>::value) return CV_MAKETYPE(CV_16S, (int)C());
  80 + //if(std::is_same<T, int>::value) return CV_MAKETYPE(CV_32S, (int)C());
  81 + //if(std::is_same<T, float>::value) return CV_MAKETYPE(CV_32F, (int)C());
  82 + //if(std::is_same<T, double>::value) return CV_MAKETYPE(CV_64F, (int)C());
  83 +
  84 + if(typeid(T) == typeid(unsigned char)) return GL_UNSIGNED_BYTE;
  85 + if(typeid(T) == typeid(char)) return GL_BYTE;
  86 + if(typeid(T) == typeid(unsigned short)) return GL_UNSIGNED_SHORT;
  87 + if(typeid(T) == typeid(short)) return GL_SHORT;
  88 + if(typeid(T) == typeid(unsigned int)) return GL_UNSIGNED_INT;
  89 + if(typeid(T) == typeid(int)) return GL_INT;
  90 + if(typeid(T) == typeid(float)) return GL_FLOAT;
  91 +
  92 + std::cout<<"ERROR in stim::gl_texture - no valid data type found"<<std::endl;
  93 + exit(1);
  94 + }
  95 +
  96 + //Guesses the "internal format" of the texture to closely approximate the original format
  97 + GLint guess_gpu_type(){
  98 + switch(format){
  99 + case GL_LUMINANCE:
  100 + switch(cpu_type){
  101 + case GL_BYTE:
  102 + case GL_UNSIGNED_BYTE:
  103 + return GL_LUMINANCE8;
  104 + case GL_SHORT:
  105 + case GL_UNSIGNED_SHORT:
  106 + return GL_LUMINANCE16;
  107 + case GL_INT:
  108 + case GL_UNSIGNED_INT:
  109 + return GL_LUMINANCE32I_EXT;
  110 + case GL_FLOAT:
  111 + return GL_LUMINANCE32F_ARB;
  112 + default:
  113 + std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
  114 + exit(1);
  115 + }
  116 + case GL_RGB:
  117 + switch(cpu_type){
  118 + case GL_BYTE:
  119 + case GL_UNSIGNED_BYTE:
  120 + return GL_RGB8;
  121 + case GL_SHORT:
  122 + case GL_UNSIGNED_SHORT:
  123 + return GL_RGB16;
  124 + case GL_INT:
  125 + case GL_UNSIGNED_INT:
  126 + return GL_RGB32I;
  127 + case GL_FLOAT:
  128 + return GL_RGB32F;
  129 + default:
  130 + std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
  131 + exit(1);
  132 + }
  133 + case GL_RGBA:
  134 + switch(cpu_type){
  135 + case GL_BYTE:
  136 + case GL_UNSIGNED_BYTE:
  137 + return GL_RGBA8;
  138 + case GL_SHORT:
  139 + case GL_UNSIGNED_SHORT:
  140 + return GL_RGBA16;
  141 + case GL_INT:
  142 + case GL_UNSIGNED_INT:
  143 + return GL_RGBA32I;
  144 + case GL_FLOAT:
  145 + return GL_RGBA32F;
  146 + default:
  147 + std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
  148 + exit(1);
  149 + }
  150 + default:
  151 + std::cout<<"error in stim::gl_texture - unable to guess GPU internal format"<<std::endl;
  152 + exit(1);
  153 + }
  154 + }
  155 + /// creates this texture in the current OpenGL context
  156 + void generate_texture(){
  157 + glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  158 + CHECK_OPENGL_ERROR
  159 + glGenTextures(1, &texID);
  160 + CHECK_OPENGL_ERROR
  161 + glBindTexture(texture_type, texID);
  162 + CHECK_OPENGL_ERROR
  163 + glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, interpolation);
  164 + CHECK_OPENGL_ERROR
  165 + glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, interpolation);
  166 + CHECK_OPENGL_ERROR
  167 + switch(texture_type){
  168 + case GL_TEXTURE_3D:
  169 + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap);
  170 + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap);
  171 + glTexParameteri(texture_type, GL_TEXTURE_WRAP_R, wrap);
  172 + glTexImage3D(texture_type, 0, gpu_type, (GLsizei)R[1], (GLsizei)R[2], (GLsizei)R[3], 0, format, cpu_type, ptr);
  173 + break;
  174 + case GL_TEXTURE_2D:
  175 + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap);
  176 + CHECK_OPENGL_ERROR
  177 + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, wrap);
  178 + CHECK_OPENGL_ERROR
  179 + glTexImage2D(texture_type, 0, gpu_type, (GLsizei)R[1], (GLsizei)R[2], 0, format, cpu_type, ptr);
  180 + CHECK_OPENGL_ERROR
  181 + break;
  182 + case GL_TEXTURE_1D:
  183 + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, wrap);
  184 + CHECK_OPENGL_ERROR
  185 + glTexImage1D(texture_type, 0, gpu_type, (GLsizei)R[1], 0, format, cpu_type, ptr);
  186 + CHECK_OPENGL_ERROR
  187 + break;
  188 + default:
  189 + std::cout<<"Error in stim::gl_texture - unrecognized texture target when generating texture"<<std::endl;
  190 + exit(1);
  191 + break;
  192 + }
  193 + CHECK_OPENGL_ERROR
48 194 }
49 195  
50 196 public:
51 197  
52 198 ///default constructor
53   - gl_texture() : image_stack<T>() {
54   -
  199 + gl_texture( GLint interp = GL_LINEAR, //default to linear interpolation
  200 + GLint twrap = GL_REPEAT) //default repeating the texture at the edges
  201 + : image_stack<T>() {
  202 + init(); //initialize the texture with NULL values
  203 + interpolation = interp; //store the interpolation type
  204 + wrap = twrap; //store the wrap type
55 205 }
56 206  
57 207 ///@param string path to the directory with the image files.
58 208 ///Creates an instance of the gl_texture object with a path to the data.
59 209  
60   - gl_texture(std::string file_mask){
61   - image_stack<T>::load_images(file_mask);
62   - setTextureType();
  210 + gl_texture(std::string file_mask, GLint interp = GL_LINEAR, GLint twrap = GL_REPEAT){
  211 + init();
  212 + interpolation = interp; //store interpolation type
  213 + wrap = twrap; //store wrap type
  214 + load(file_mask);
  215 + }
  216 +
  217 + ///Attaches the texture to the current OpenGL context and makes it ready to render
  218 + void attach(){
  219 + if(texID == 0) generate_texture(); //generate the texture if it doesn't already exist
  220 + else{
  221 + std::cout<<"Texture has already been attached to a context."<<std::endl;
  222 + exit(1);
  223 + }
  224 + }
  225 +
  226 + //binds a texture to be the current render source
  227 + void bind(){
  228 + glBindTexture(texture_type, texID); //bind the texture to the appropriate texture target
  229 + CHECK_OPENGL_ERROR
63 230 }
64 231  
65 232 ///returns the dimentions of the data in the x, y, z directions.
... ... @@ -72,21 +239,6 @@ class gl_texture : public virtual image_stack&lt;T&gt;
72 239 x = R[0]; y = R[1]; z = R[2];
73 240 }
74 241  
75   - ///@param GLint interp --GL_LINEAR, GL_NEAREST...
76   - ///@param GLint twrap --GL_REPEAR, GL_CLAMP_TO_EDGE...
77   - ///@param GLenum dataType --GL_UNSIGNED_BYTE, GL_FLOAT16...
78   - ///@param GLenum dataFormat--GL_LUMINANCE, GL_RGB...
79   - /// Texture paramenters.
80   - void setTexParam(GLint interp = GL_LINEAR,
81   - GLint twrap = GL_CLAMP_TO_EDGE,
82   - GLenum dataType = GL_UNSIGNED_BYTE,
83   - GLenum dataFormat = GL_LUMINANCE){
84   - interpType = interp;
85   - texWrap = twrap;
86   - type = dataType;
87   - format = dataFormat;
88   - }
89   -
90 242 ///@param x size of the voxel in x direction
91 243 ///@param y size of the voxel in y direction
92 244 ///@param z size of the voxel in z direction
... ... @@ -106,15 +258,12 @@ class gl_texture : public virtual image_stack&lt;T&gt;
106 258 ///@param file_mask specifies the file(s) to be loaded
107 259 /// Sets the path and calls the loader on that path.
108 260 void load(std::string file_mask){
109   - image_stack<T>::load_images(file_mask);
110   - setTextureType();
  261 + image_stack<T>::load_images(file_mask); //load images
  262 + setTextureType(); //set the texture type: 1D, 2D, 3D
  263 + format = guess_format(); //guess the texture format based on the number of image channels
  264 + cpu_type = guess_cpu_type(); //guess the CPU type based on the template
  265 + gpu_type = guess_gpu_type(); //guess the GPU type based on the format and template
111 266 }
112   -
113   - /// Returns an std::string path associated with an instance of the gl_texture class.
114   - //std::string getPath()
115   - //{
116   - // return path;
117   - //}
118 267  
119 268 /// Returns the GLuint id of the texture created by/associated with the
120 269 /// instance of the gl_texture class.
... ... @@ -122,39 +271,8 @@ class gl_texture : public virtual image_stack&lt;T&gt;
122 271 return texID;
123 272 }
124 273  
125   - /// Creates a texture and from the loaded data and
126   - /// assigns that texture to texID
127   - //TO DO :::: 1D textures
128   - //TO DO:::add methods for handling the cases of T
129   - // and convert them to GL equivalent.
130   - // i.e. an overloaded function that handles paramenter conversion.
131   - void createTexture(){
132   - glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
133   - glGenTextures(1, &texID);
134   - glBindTexture(texture_type, texID);
135   - glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, interpType);
136   - glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, interpType);
137   - switch(texture_type){
138   - case GL_TEXTURE_3D:
139   - glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, texWrap);
140   - glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, texWrap);
141   - glTexParameteri(texture_type, GL_TEXTURE_WRAP_R, texWrap);
142   - glTexImage3D(texture_type, 0, 1, R[1], R[2], R[3], 0, format, type, ptr);
143   - glPixelStorei(GL_PACK_ALIGNMENT,1);
144   - break;
145   - case GL_TEXTURE_2D:
146   - glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, texWrap);
147   - glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, texWrap);
148   - glTexImage2D(texture_type, 0, 1, R[1], R[2], 0, format, type, ptr);
149   - break;
150   - }
151   - }
152   - ///Temporary methods for debugging and testing are below.
153   - ///Self-explanatory.
154 274  
155   - T*
156   - getData()
157   - {
  275 + T* getData(){
158 276 return ptr;
159 277 }
160 278  
... ...
stim/grids/grid.h
... ... @@ -24,27 +24,26 @@ protected:
24 24 F S[D]; //spacing between element samples
25 25 T* ptr; //pointer to the data (on the GPU or CPU)
26 26  
27   - ///Return the total number of values in the binary file
28   - size_t samples(){
29   - size_t s = 1;
30   - for(size_t d = 0; d < D; d++)
31   - s *= R[d];
32   - return s;
33   - }
  27 +
34 28  
35 29 ///Initializes a grid by allocating the necessary memory and setting all values to zero
36 30 void init(){
37   - size_t N = samples(); //calculate the total number of values
38   - ptr = (T*)calloc(sizeof(T) * N); //allocate memory to store the grid
  31 + ptr = NULL; //initialize the data pointer to NULL
  32 + memset(R, 0, sizeof(size_t) * D); //set the resolution to zero
  33 + for(size_t d = 0; d < D; d++) S[d] = (F)1.0; //initialize the spacing to unity
  34 + }
  35 +
  36 + void alloc(){
  37 + if(ptr != NULL) free(ptr); //if memory has already been allocated, free it
  38 + size_t N = samples(); //calculate the total number of values
  39 + ptr = (T*)calloc(sizeof(T), N); //allocate memory to store the grid
39 40 }
40 41  
41 42 public:
42 43  
43 44 ///Default constructor doesn't do anything
44 45 grid(){
45   - memset(R, 0, sizeof(size_t) * D); //initialize the grid dimensions to zero
46   - memset(S, 0, sizeof(F) * D); //initialize the grid size to zero
47   - ptr = NULL; //set the data pointer to NULL
  46 + init();
48 47 }
49 48  
50 49 ///Constructor used to specify the grid size as a vector
... ... @@ -56,6 +55,19 @@ public:
56 55 init();
57 56 }
58 57  
  58 + ///Return the total number of values in the binary file
  59 + size_t samples(){
  60 + size_t s = 1;
  61 + for(size_t d = 0; d < D; d++)
  62 + s *= R[d];
  63 + return s;
  64 + }
  65 +
  66 + ///Return the number of bytes in the binary file
  67 + size_t bytes(){
  68 + return samples() * sizeof(T);
  69 + }
  70 +
59 71 void
60 72 setDim(stim::vec<float> s){
61 73 for(size_t d = 0; d < D; d++)
... ... @@ -64,7 +76,7 @@ public:
64 76  
65 77 ///Constructor used to specify the grid size as a set of parameters
66 78 /// @param X0... is a list of values describing the grid size along each dimension
67   - grid( size_t X0, ...){
  79 + /*grid( size_t X0, ...){
68 80 R[0] = X0; //set the grid size of the first dimension
69 81 va_list ap; //get a variable list
70 82 va_start(ap, X0); //start the variable list at the first element
... ... @@ -72,18 +84,35 @@ public:
72 84 R[d] = va_arg(ap, size_t); //read the value from the variable list as a size_t
73 85 va_end(ap);
74 86 init(); //initialize the grid
75   - }
  87 + }*/
76 88  
77 89 ///Set the spacing between grid sample points
78 90 /// @param X0... is a list of values describing the grid sample spacing
79   - void spacing(F X0, ...) {
  91 + /*void spacing(F X0, ...) {
80 92 S[0] = X0; //set the grid size of the first dimension
81 93 va_list ap; //get a variable list
82 94 va_start(ap, X0); //start the variable list at the first element
83 95 for (size_t d = 1; d<D; d++) //for each additional element
84   - S[d] = va_arg(ap, size_t); //read the value from the variable list as a size_t
  96 + S[d] = va_arg(ap, F); //read the value from the variable list as a size_t
85 97 va_end(ap);
86   - init(); //initialize the grid
  98 + }*/
  99 +
  100 + /// Set the spacing between grid sample points for the specified dimension
  101 + void spacing(size_t d, F sp){
  102 + if(d < D) S[d] = sp;
  103 + else{
  104 + std::cout<<"error in stim::grid::spacing() - insufficient dimensions"<<std::endl;
  105 + exit(1);
  106 + }
  107 + }
  108 +
  109 + /// Return the spacing for a given dimension
  110 + F spacing(size_t d){
  111 + if(d < D) return S[d];
  112 + else{
  113 + std::cout<<"error in stim::grid::spacing() - insufficient dimensions"<<std::endl;
  114 + exit(1);
  115 + }
87 116 }
88 117  
89 118 /// Get the sample spacing for the given dimension
... ... @@ -91,6 +120,16 @@ public:
91 120 return S[d];
92 121 }
93 122  
  123 + /// Get the size of the grid along the specified dimension
  124 + F size(size_t d){
  125 + return (F)R[d] * S[d];
  126 + }
  127 +
  128 + /// Return the number of samples
  129 + size_t samples(size_t d){
  130 + return R[d];
  131 + }
  132 +
94 133 ///Writes the binary data to disk
95 134  
96 135 /// @param filename is the name of the binary file to be written
... ... @@ -118,7 +157,7 @@ public:
118 157  
119 158 ///Gets a single value from the grid given a set of coordinates
120 159 /// @param x0... is a list of coordinates specifying the desired value
121   - T get(unsigned long x0, ...){
  160 + /*T get(unsigned long x0, ...){
122 161  
123 162 va_list ap; //create a variable list
124 163  
... ... @@ -133,13 +172,13 @@ public:
133 172 va_end(ap);
134 173  
135 174 return ptr[idx]; //access the appropriate element and return the value
136   - }
  175 + }*/
137 176  
138 177 ///Sets a value in the grid
139 178  
140 179 /// @param value is the grid point value
141 180 /// @x0... is the coordinate of the value to be set
142   - void set(T value, unsigned long x0, ...){
  181 + /*void set(T value, unsigned long x0, ...){
143 182 va_list ap; //create a variable list
144 183 unsigned long F = 1; //initialize the dimension counter to 1
145 184 unsigned long idx = x0; //initialize the index to the first variable
... ... @@ -151,7 +190,7 @@ public:
151 190 }
152 191 va_end(ap);
153 192 ptr[idx] = value; //set the value at the indexed location
154   - }
  193 + }*/
155 194  
156 195  
157 196 ///Outputs grid data as a string
... ...
stim/grids/image_stack.h
... ... @@ -10,16 +10,15 @@ namespace stim{
10 10  
11 11 ///This class is used to load 3D grid data from stacks of images
12 12 // The class uses a 4D grid object, where the first dimension is a color value.
13   -template<typename T>
14   -class image_stack : public virtual stim::grid<T, 4>{
  13 +template<typename T, typename F = float>
  14 +class image_stack : public virtual stim::grid<T, 4, F>{
15 15  
16 16 enum image_type {stimAuto, stimMono, stimRGB, stimRGBA};
17 17  
18 18 protected:
19   - using stim::grid<T, 4>::S;
  19 + //using stim::grid<T, 4>::S;
20 20 using stim::grid<T, 4>::R;
21 21 using stim::grid<T, 4>::ptr;
22   - using stim::grid<T, 4>::samples;
23 22 using stim::grid<T, 4>::read;
24 23  
25 24 public:
... ... @@ -28,6 +27,42 @@ public:
28 27  
29 28 }
30 29  
  30 + /// Overloads grid::samples() to return the number of samples associated with a given spatial dimension
  31 + /// this is necessary because R[0] stores the color
  32 + size_t samples(size_t d){
  33 + return grid<T, 4, F>::samples(d + 1);
  34 + }
  35 +
  36 + size_t samples(){
  37 + return R[1] * R[2] * R[3]; //return the number of spatial samples
  38 + }
  39 +
  40 + /// Returns the number of color channels
  41 + size_t channels(){
  42 + return R[0];
  43 + }
  44 +
  45 + /// Overloads grid::size() to return the size of the grid associated with a given spatial dimension
  46 + F size(size_t d){
  47 + return grid<T, 4, F>::size(d + 1);
  48 + }
  49 +
  50 + /// Sets the spacing between samples in the image stack
  51 + void spacing(F sx, F sy, F sz){
  52 + grid<T, 4, F>::S[1] = sx; //set the sample spacing for the appropriate spatial dimension
  53 + grid<T, 4, F>::S[2] = sy;
  54 + grid<T, 4, F>::S[3] = sz;
  55 + }
  56 +
  57 + F spacing(size_t d){
  58 + return grid<T, 4, F>::spacing(d + 1);
  59 + }
  60 +
  61 + /// Overloads the spacing parameter to set the size of the grid associated with a given spatial dimension
  62 + //void spacing(F sx, F sy = 1.0f, F sz = 1.0f){
  63 + // grid<T, 4, F>::spacing((F)1.0, sx, sy, sz);
  64 + //}
  65 +
31 66 ///Load an image stack based on a file mask. Images are loaded in alphanumeric order
32 67 /// @param file_mask is the mask describing images to be loaded
33 68 void load_images(std::string file_mask){
... ... @@ -42,17 +77,15 @@ public:
42 77 std::cout<<"STIM ERROR (image_stack): No matching files for loading a stack."<<std::endl;
43 78 exit(1);
44 79 }
45   - for(int i = 0; i < file_list.size(); i++)
46   - std::cout << file_list[i].str() << std::endl;
47 80  
48 81 //load the first image and set all of the image_stack properties
49 82 stim::image<T> I(file_list[0].str());
50 83  
51 84 //set the image resolution and number of channels
52   - R.push(I.channels());
53   - R.push(I.width());
54   - R.push(I.height());
55   - R.push(file_list.size());
  85 + R[0] = I.channels();
  86 + R[1] = I.width();
  87 + R[2] = I.height();
  88 + R[3] = file_list.size();
56 89  
57 90 //allocate storage space
58 91 ptr = (T*)malloc(sizeof(T) * samples());
... ...
stim/image/image.h
... ... @@ -159,7 +159,10 @@ public:
159 159 std::cout<<"ERROR stim::image::load() - unable to find image "<<filename<<std::endl;
160 160 exit(1);
161 161 }
162   - allocate(cvImage.cols, cvImage.rows, cvImage.channels()); //allocate space for the image
  162 + int cols = cvImage.cols;
  163 + int rows = cvImage.rows;
  164 + int channels = cvImage.channels();
  165 + allocate(cols, rows, channels); //allocate space for the image
163 166 unsigned char* cv_ptr = (unsigned char*)cvImage.data;
164 167 if(C() == 1) //if this is a single-color image, just copy the data
165 168 memcpy(img, cv_ptr, bytes());
... ...