#ifndef STIM_IMAGE_H #define STIM_IMAGE_H #include #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(){ unalloc(); 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(){ // The following is C++ 11 code, but causes problems on some compilers (ex. nvcc). Below is my best approximation to a solution //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()); if(typeid(T) == typeid(unsigned char)) return CV_MAKETYPE(CV_8U, (int)C()); if(typeid(T) == typeid(char)) return CV_MAKETYPE(CV_8S, (int)C()); if(typeid(T) == typeid(unsigned short)) return CV_MAKETYPE(CV_16U, (int)C()); if(typeid(T) == typeid(short)) return CV_MAKETYPE(CV_16S, (int)C()); if(typeid(T) == typeid(int)) return CV_MAKETYPE(CV_32S, (int)C()); if(typeid(T) == typeid(float)) return CV_MAKETYPE(CV_32F, (int)C()); if(typeid(T) == typeid(double)) 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; if(typeid(T) == typeid(unsigned char)) return UCHAR_MAX; if(typeid(T) == typeid(unsigned short)) return SHRT_MAX; if(typeid(T) == typeid(unsigned)) return UINT_MAX; if(typeid(T) == typeid(unsigned long)) return ULONG_MAX; if(typeid(T) == typeid(unsigned long long)) return ULLONG_MAX; if(typeid(T) == typeid(float)) return 1.0f; if(typeid(T) == typeid(double)) return 1.0; std::cout<<"ERROR in stim::image::white - no white value known for this data type"<& I){ init(); allocate(I.X(), I.Y(), I.C()); memcpy(img, I.img, bytes()); } /// Destructor - clear memory ~image(){ free(img); } stim::image& operator=(const stim::image& I){ init(); 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 "< 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, 0)] = 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 } 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."<