diff options
Diffstat (limited to 'NT/src/cvimage.h')
| -rw-r--r-- | NT/src/cvimage.h | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/NT/src/cvimage.h b/NT/src/cvimage.h new file mode 100644 index 0000000..d3f824c --- /dev/null +++ b/NT/src/cvimage.h @@ -0,0 +1,302 @@ +#ifndef ROTOR_CVIMAGE +#define ROTOR_CVIMAGE + +#include <math.h> +#include <cv.h> +#include <highgui.h> +#include <unordered_map> + +//converting to use a cv image... +//cv::Mat supports most of what we want here +//need to think +//http://answers.opencv.org/question/8202/using-external-image-data-in-a-cvmat/ + +//all access to the image is presently through a pointer to the data +//cv::Mat supports this + +//how will copying work? +//Rotor::Image will contain a cv::Mat object which may own its data or inherit it +//cv::Mat should take care of reference counting + +//can cv::Mat + +namespace Rotor { + class pixeltables{ + //handy pixel arithmetic lookup tables as nested arrays + //so - pixels.add[0x78][0x66]; will give the precalculated result of adding with saturation + // pixels.mono_weights[0][0x100]; will give the red component to convert to mono + public: + pixeltables(){ + add=new uint8_t*[256]; + multiply=new uint8_t*[256]; + overlay=new uint8_t*[256]; + min=new uint8_t*[256]; + max=new uint8_t*[256]; + for (int i=0;i<256;i++){ + add[i]=new uint8_t[256]; + multiply[i]=new uint8_t[256]; + overlay[i]=new uint8_t[256]; + min[i]=new uint8_t[256]; + max[i]=new uint8_t[256]; + for (int j=0;j<256;j++){ + add[i][j]=(uint8_t)std::min(i+j,0xFF); + multiply[i][j]=(uint8_t)(((double)i)*(((double)j)/255.0)); + overlay[i][j]=j<128?(uint8_t)((i*j)>>7):255-(((0xFF-i)*(0xFF-j))>>7); + min[i][j]=j<i?j:i; + max[i][j]=j>i?j:i; + } + } + mono_weights=new uint8_t*[3]; + double weights[3]={0.2989, 0.5870, 0.1140}; + for (int i=0;i<3;i++) { + mono_weights[i]=new uint8_t[256]; + for (int j=0;j<256;j++){ + mono_weights[i][j]=(uint8_t)(((double)j)*weights[i]); + } + } + } + virtual ~pixeltables(){ + for (int i=0;i<256;i++){ + delete[] add[i]; + delete[] multiply[i]; + delete[] overlay[i]; + delete[] min[i]; + delete[] max[i]; + } + delete[] add; + delete[] multiply; + delete[] overlay; + delete[] min; + delete[] max; + for (int i=0;i<3;i++) { + delete[] mono_weights[i]; + } + delete[] mono_weights; + } + uint8_t **add; + uint8_t **multiply; + uint8_t **overlay; + uint8_t **mono_weights; + uint8_t **max; + uint8_t **min; + }; + static pixeltables pixels; + class Image{ + //transform should be a method of image + public: + Image(){ + zero(); + }; + Image(int _w,int _h){ + zero(); + setup(_w,_h); + }; + Image(const Image &mom) { + // copy constructor + zero(); + rgb=mom.rgb.clone(); + w=mom.w; + h=mom.h; + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //always just deallocate cv::Mat from stack + } + ~Image() { + free(); + }; + void free(){ + if (RGBdata&&ownsRGBdata) delete[] RGBdata; + if (Adata&&ownsAdata) delete[] Adata; + if (Zdata&&ownsZdata) delete[] Zdata; + rgb.release(); + alpha.release(); + zero(); + } + void zero(){ + RGBdata=nullptr; + Adata=nullptr; + Zdata=nullptr; + w=0; + h=0; + ownsRGBdata=ownsAdata=ownsZdata=false; + } + //space out to 32 bit RGB padding for cairo + void convert24(); + void convert32(); + int getStride(){ + return w*3; + } + bool clear(){ + rgb.setTo(0); + return true; + }; + bool setup(int _w,int _h){ //set up with internal data + if (_w==0||_h==0||(_w*_h*3)>10000000) { + //some kind of elusive thing that shows up only in non debug builds + std::cerr<<"Error! cvimage: request to set up image at "<<_w<<"x"<<_h<<std::endl; + return false; + } + if ((w!=_w)|(h!=_h)){ + free(); + rgb.create(_h,_w,CV_8UC3); + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //will not be necessary + w=_w; + h=_h; + } + return true; + /* + if (w!=_w||h!=_h||!ownsRGBdata||!ownsAdata||!ownsZdata){ + free(); + w=_w; + h=_h; + RGBdata=new uint8_t[w*h*3]; + Adata=new uint8_t[w*h]; + Zdata=new uint16_t[w*h]; + ownsRGBdata=ownsAdata=ownsZdata=true; + return true; + } + else return false; + */ + } + bool read_file(std::string &filename){ + rgb=cv::imread(filename,CV_LOAD_IMAGE_COLOR); + if (rgb.empty()) return false; + RGBdata=rgb.data; + ownsRGBdata=false; + w=rgb.rows; + h=rgb.cols; + return true; + } + bool setup_fromRGB(int _w,int _h,uint8_t *pRGBdata,int linepadding=0){ + //here the data belongs to libavcodec or other + //could move to using cv::Mat there also and just passing cv:Mat over + + //linepadding causes crash, but it doesn't seem to be necessary + // Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP) + rgb=cv::Mat(_h,_w,CV_8UC3,pRGBdata,(_w*3)+linepadding); + //std::cerr<<"created cv::Mat with step= "<<rgb.step<<",should be "<<((_w*3)+linepadding)<<std::endl; + + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //will not be necessary + w=_w; + h=_h; + return true; + /* + if (w!=_w||h!=_h||ownsRGBdata||!ownsAdata||!ownsZdata){ + free(); + w=_w; + h=_h; + RGBdata=pRGBdata; + Adata=new uint8_t[w*h]; + Zdata=new uint16_t[w*h]; + ownsRGBdata=false; + ownsAdata=ownsZdata=true; + return true; + } + return false; + */ + } + bool setup_fromMat(cv::Mat& othermat){ + //here the mat belongs to another object + if (othermat.channels()==1) { + cv::cvtColor(othermat, rgb, CV_GRAY2RGB); + } + else rgb=othermat; + RGBdata=rgb.data; //can move to use the bare pointer eventually + ownsRGBdata=false; //will not be necessary + w=rgb.rows; + h=rgb.cols; + return true; + } + //leaks + Image* clone(){ + Image *t=new Image(); + t->rgb=rgb.clone(); + t->w=w; + t->h=h; + t->RGBdata=t->rgb.data; //can move to use the bare pointer eventually + t->ownsRGBdata=false; //always just deallocate cv::Mat from stack + /* + for (int i=0;i<w*h*3;i++) { + t->RGBdata[i]=RGBdata[i]; + } + */ + return t; + } + void crop(int _w,int _h){ //change borders, crop/ extend, centred + cv::Mat source; + int X,Y,W,H; + //do crop part + if ( _w<w||_h<h){ + //create crop rectangle xywh + X=Y=0; + W=w; + H=h; + if (_w<w){ + W=_w; + X=(w-_w)/2; + w=_w; + } + if (_h<h){ + H=_h; + Y=(h-_h)/2; + h=_h; + } + cv::Mat cropped; + CvRect r=cvRect(X,Y,W,H) ; + rgb(r).copyTo(source); + } + else source=rgb; + copyMakeBorder(source,rgb,(_h-h)/2,(_h-h)/2,(_w-w)/2,(_w-w)/2,cv::BORDER_REPLICATE); + w=rgb.rows; + h=rgb.cols; + } + void resize(int _w,int _h){ + cv::resize(rgb,rgb,cv::Size(_w,_h),0,0,cv::INTER_LINEAR ); + w=rgb.rows; + h=rgb.cols; + } + Image & operator=(const Image &other); + //believe these still work, don't know if these optimisations are better than opencvs.. + Image & operator+=(const Image &other); + Image & operator*=(const Image &other); + Image & operator^=(const Image &other); + Image & alpha_blend(const Image &other); + Image & alpha_blend_cv(const Image &other); + Image & alpha_merge(const Image &other); + Image & alpha_from_cv(cv::Mat &other); + Image & add_wrap(const Image &other); + Image & divide_wrap(const Image &other); + Image & overlay(const Image &other); + Image & min(const Image &other); + Image & max(const Image &other); + Image & operator*=(const double &amount); + Image & operator+=(const double &amount); + Image & operator-=(const double &amount); + Image & operator/=(const double &amount); + Image * operator*(const double &amount); + Image * operator+(const double &amount); + Image * operator-(const double &amount); + Image * operator/(const double &amount); + uint8_t *RGBdata; + uint8_t *Adata; + uint16_t *Zdata; + int h,w; + bool ownsRGBdata,ownsAdata,ownsZdata; //better done through auto_ptr? + + //making the interface for mip mapping + //should reduce in powers of 2 + // + + cv::Mat rgb; + cv::Mat alpha; + + //store a library of mipmaps + std::unordered_map<int,cv::Mat> mipmaps; + + cv::Mat& get_mipmap(int level); + + }; +} + +#endif |
