#ifndef STIM_IMAGE_H #define STIM_IMAGE_H #include #include #include #include #include namespace stim{ /// This static class provides the STIM interface for loading, saving, and storing 2D images. /// Data is stored in an interleaved (BIP) format (default for saving and loading is RGB). //currently this interface uses CImg // T = data type (usually unsigned char) template class image{ //cimg_library::CImg img; T* img; //pointer to the image data (assumes RGB for loading/saving) size_t R[3]; size_t X() const { return R[1]; } size_t Y() const { return R[2]; } size_t C() const { return R[0]; } void init(){ //initializes all variables, assumes no memory is allocated memset(R, 0, sizeof(size_t) * 3); //set the resolution and number of channels to zero img = NULL; } void unalloc(){ //frees any resources associated with the image if(img) free(img); //if memory has been allocated, free it } void clear(){ //clears all image data unalloc(); //unallocate previous memory init(); //re-initialize the variables } void allocate(){ img = (T*) malloc( sizeof(T) * R[0] * R[1] * R[2] ); //allocate memory } void allocate(size_t x, size_t y, size_t c){ //allocate memory based on the resolution R[0] = c; R[1] = x; R[2] = y; //set the resolution allocate(); //allocate memory } size_t bytes(){ return size() * sizeof(T); } size_t idx(size_t x, size_t y, size_t c = 0){ return y * C() * X() + x * C() + c; } int cv_type(){ if(std::is_same::value) return CV_MAKETYPE(CV_8U, (int)C()); if(std::is_same::value) return CV_MAKETYPE(CV_8S, (int)C()); if(std::is_same::value) return CV_MAKETYPE(CV_16U, (int)C()); if(std::is_same::value) return CV_MAKETYPE(CV_16S, (int)C()); if(std::is_same::value) return CV_MAKETYPE(CV_32S, (int)C()); if(std::is_same::value) return CV_MAKETYPE(CV_32F, (int)C()); if(std::is_same::value) return CV_MAKETYPE(CV_64F, (int)C()); std::cout<<"ERROR in stim::image::cv_type - no valid data type found"<::value) return UCHAR_MAX; if(std::is_same::value) return SHRT_MAX; if(std::is_same::value) return UINT_MAX; if(std::is_same::value) return ULONG_MAX; if(std::is_same::value) return ULLONG_MAX; if(std::is_same::value) return 1.0f; if(std::is_same::value) return 1.0; std::cout<<"ERROR in stim::image::white - no white value known for this data type"<& I){ allocate(I.X(), I.Y(), I.C()); //allocate(I.R[1], I.R[2], I.R[0]); memcpy(img, I.img, bytes()); } /// Destructor - clear memory // ~image(){ // free(img); // } void clear_exp(){ //clears all image data unalloc(); } stim::image operator=(const stim::image& I){ if(&I == this) //handle self-assignment return *this; allocate(I.X(), I.Y(), I.C()); memcpy(img, I.img, bytes()); return *this; } /// Load an image from a file void load(std::string filename){ cv::Mat cvImage = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED); //use OpenCV to open the image file if(!cvImage.data){ std::cout<<"ERROR stim::image::load() - unable to find image "< I; for(int i = 0; i < file_list.size(); i++) I.load(file_list[i].srt()) You will run out of memory. */ memcpy(img, cv_ptr, bytes()); // img = cvImage.data; } if(C() == 3) //if this is a 3-color image, OpenCV uses BGR interleaving set_interleaved_bgr(cv_ptr, X(), Y()); // cvImage.deallocate(); } //save a file void save(std::string filename){ //OpenCV uses an interleaved format, so convert first and then output T* buffer = (T*) malloc(bytes()); if(C() == 1) memcpy(buffer, img, bytes()); else if(C() == 3) get_interleaved_bgr(buffer); cv::Mat cvImage((int)Y(), (int)X(), cv_type(), buffer); cv::imwrite(filename, cvImage); cvImage.release(); free(buffer); } //create an image from an interleaved buffer void set_interleaved_rgb(T* buffer, size_t width, size_t height, size_t channels = 3){ allocate(width, height, channels); memcpy(img, buffer, bytes()); } void set_interleaved_bgr(T* buffer, size_t width, size_t height, size_t channels = 3){ allocate(width, height, channels); for(size_t c = 0; c < C(); c++){ //copy directly for(size_t y = 0; y < Y(); y++){ for(size_t x = 0; x < X(); x++){ img[idx(x, y, c)] = buffer[y * X() * C() + x * C() + (2-c)]; } } } } void get_interleaved_bgr(T* data){ //for each channel for(size_t y = 0; y < Y(); y++){ for(size_t x = 0; x < X(); x++){ for(size_t c = 0; c < C(); c++){ data[y * X() * C() + x * C() + (2-c)] = img[idx(x, y, c)]; } } } } void get_interleaved_rgb(T* data){ memcpy(data, img, bytes()); } image channel(size_t c){ //create a new image image r(X(), Y(), 1); for(size_t x = 0; x < X(); x++){ for(size_t y = 0; y < Y(); y++){ r.img[r.idx(x, y, c)] = img[idx(x, y, c)]; } } return r; } T& operator()(size_t x, size_t y, size_t c = 0){ return img[idx(x, y, c)]; } /// Set all elements in the image to a given scalar value /// @param v is the value used to set all values in the image image operator=(T v){ size_t N = size(); for(size_t n = 0; n < N; n++) img[n] = v; return *this; } /// Copy the given data to the specified channel /// @param c is the channel number that the data will be copied to /// @param buffer is a pointer to the image to be copied to channel c void set_channel(T* buffer, size_t c){ size_t x, y; for(y = 0; y < Y(); y++){ for(x = 0; x < X(); x++){ img[idx(x, y, c)] = buffer[c]; } } } size_t channels(){ return C(); } size_t width(){ return X(); } size_t height(){ return Y(); } T* data(){ return img; } //returns the size (number of values) of the image size_t size(){ return C() * X() * Y(); } /// Returns the number of nonzero values size_t nnz(){ size_t N = X() * Y() * C(); size_t nz = 0; for(size_t n = 0; n < N; n++) if(img[n] != 0) nz++; return nz; //return the number of nonzero pixels } //this function returns indices of pixels that have nonzero values std::vector sparse_idx(){ std::vector s; //allocate an array s.resize(nnz()); //allocate space in the array size_t N = size(); //size_t C = channels(); //T* ptr = img.data(); //get a pointer to the image data size_t i = 0; for(size_t n = 0; n < N; n++){ if(img[n] != 0){ s[i] = n; i++; } } return s; //return the index list } /// Returns the maximum pixel value in the image T maxv(){ T max_val = img[0]; //initialize the maximum value to the first one size_t N = size(); //get the number of pixels for (size_t n=0; n max_val){ //if the value is higher than the current max max_val = img[n]; } } return max_val; } /// Returns the maximum pixel value in the image T minv(){ T min_val = img[0]; //initialize the maximum value to the first one size_t N = size(); //get the number of pixels for (size_t n=0; n invert(T white_val){ size_t N = size(); //calculate the total number of values in the image image r(X(), Y(), C()); //allocate space for the resulting image for(size_t n = 0; n < N; n++) r.img[n] = white_val - img[n]; //perform the inversion return r; //return the inverted image } ///crops the image from x1 to x0 and y1 to y0 and returns a new (smaller) image. ///Untested image crop(int x0, int x1, int y0, int y1) { image ret(x1-x0, y1-y0, C()); int newWidth = x1-x0; int destidx, srcidx; // for(int i = 0; i < (y1-y0); i++) { destidx = i*newWidth*C(); ///destination index one per each row srcidx = ((i+(y0))*X()+x0)*C(); ///source index, one per each row. ret.set_interleaved_rgb(img[srcidx], newWidth, y1-y0, C()); memcpy(&ret.img[destidx], &buffer[srcidx], sizeof(T)*newWidth*C()); } // for(int i = 0; i < (x1 -x0); i++) // { // for(int j = 0; j < (y1 - y0); j++) // { // destidx = j*newWidth*C() + i; // srcidx = ((i+(y0))*X() +x0)*C() + i; // ret.img[destidx] = img[srcidx]; // } // } return ret; } image srgb2lab(){ std::cout<<"ERROR stim::image::srgb2lab - function has been broken, re-implement."< convolve2(image mask){ std::cout<<"ERROR stim::image::convolve2 - function has been broken, and shouldn't really be in here."< rotate(float angle, float cx, float cy){ std::cout<<"ERROR stim::image::rotate - function has been broken, and shouldn't really be in here."<