#include "iclGLTextureMapImage.h" #include #include #include using std::memset; namespace icl{ using namespace std; template GLTextureMapImage::GLTextureMapImage(const Size &imageSize, bool useSingleBuffer, int channels,int cellSize){ // {{{ open ICLASSERT( channels == 3 || channels == 1 || channels == 4); ICLASSERT( cellSize >= 16); ICLASSERT( getDepth() != depth64f ); m_iChannels = channels; m_iCellSize = cellSize; m_iImageW = imageSize.width; m_iImageH = imageSize.height; m_iXCells = m_iImageW/m_iCellSize; m_iYCells = m_iImageH/m_iCellSize; m_bUseSingleBuffer = useSingleBuffer; m_iRestX = m_iImageW % m_iCellSize; m_iRestY = m_iImageH % m_iCellSize; if(m_iRestX) m_iXCells++; if(m_iRestY) m_iYCells++; m_iCellDataSize = m_iCellSize*m_iCellSize*m_iChannels; m_matTextureNames = SimpleMatrix(m_iXCells,m_iYCells); if(m_bUseSingleBuffer){ m_ptCellData = new T[m_iCellDataSize]; // This is an asyncronous gl call an may cause problems .. // -> set useSingleBuffer to false to avoid this glGenTextures(m_iXCells*m_iYCells,m_matTextureNames.data()); }else{ m_ptCellData = 0; m_matCellData = SimpleMatrix(m_iXCells,m_iYCells); } m_matROISizes = SimpleMatrix(m_iXCells,m_iYCells); for(int y=0;y GLTextureMapImage::~GLTextureMapImage(){ // {{{ open if(m_bUseSingleBuffer){ glDeleteTextures(m_iXCells*m_iYCells,m_matTextureNames.data()); delete [] m_ptCellData; }else{ if(m_matCellData.dim()){ for(int y=0;y void GLTextureMapImage::setPackAlignment(depth d, int linewidth){ // {{{ open switch (d){ case depth8u:{ if(linewidth%2) glPixelStorei(GL_UNPACK_ALIGNMENT,1); else if(linewidth%4) glPixelStorei(GL_UNPACK_ALIGNMENT,2); else if(linewidth%8) glPixelStorei(GL_UNPACK_ALIGNMENT,4); else glPixelStorei(GL_UNPACK_ALIGNMENT,8); break; } case depth16s:{ if(linewidth%2) glPixelStorei(GL_UNPACK_ALIGNMENT,2); else if(linewidth%4) glPixelStorei(GL_UNPACK_ALIGNMENT,4); else glPixelStorei(GL_UNPACK_ALIGNMENT,8); break; } case depth32s: case depth32f:{ if(linewidth%2) glPixelStorei(GL_UNPACK_ALIGNMENT,4); else glPixelStorei(GL_UNPACK_ALIGNMENT,8); break; } default: ICL_INVALID_FORMAT; break; } } // }}} template void GLTextureMapImage::bci(int b, int c, int i) { m_aiBCI[0] = b; m_aiBCI[1] = c; m_aiBCI[2] = i; } namespace{ template void calculate_minmax_interleaved(T *data, Size dataROISize, int dataLineLength, int channels, std::vector > &ranges){ for(int x=0;x std::vector > GLTextureMapImage::getMinMax() const{ if(m_bUseSingleBuffer){ ERROR_LOG("image range cannot be extracted in singleBufferMode"); return std::vector >(); } std::vector > mm(m_iChannels,Range(std::numeric_limits::max(),std::numeric_limits::min())); for(int y=0;y vector GLTextureMapImage::getColor(int x, int y) const{ if(m_bUseSingleBuffer){ ERROR_LOG("getting image colors is not supported in single buffer mode"); return vector(); } if(x>=0 && y>=0 && x color; for(int c=0;c(); } template void GLTextureMapImage::updateTextures(const Img *image){ // {{{ open ICLASSERT_RETURN( image); ICLASSERT( m_iChannels == image->getChannels() ); ICLASSERT( m_iImageW == image->getWidth()); ICLASSERT( m_iImageH == image->getHeight()); if(m_bUseSingleBuffer){ // this is not allowed, because openGL cannot be accessed thread-safe setPackAlignment(getDepth(),image->getWidth()); setUpPixelTransfer(getDepth(),m_aiBCI[0],m_aiBCI[1],m_aiBCI[2], image); static GLenum aeGLTypes[] = { GL_UNSIGNED_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_FLOAT }; GLenum glType = aeGLTypes[getDepth()]; for(int y=0;y *src = image->shallowCopy(Rect(Point(x*m_iCellSize,y*m_iCellSize),m_matROISizes[x][y])); if(x==m_iXCells -1 || y == m_iYCells-1){ fill(m_ptCellData,m_ptCellData+m_iCellDataSize,0); } planarToInterleaved(src,m_ptCellData,m_iCellSize*m_iChannels*sizeof(T)); delete src; if(m_iChannels == 1){ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_iCellSize, m_iCellSize,0, GL_LUMINANCE, glType, m_ptCellData); }else if (m_iChannels == 3){ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_iCellSize, m_iCellSize,0, GL_RGB, glType, m_ptCellData); }else if (m_iChannels == 4){ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_iCellSize, m_iCellSize,0, GL_RGBA, glType, m_ptCellData); }else{ ERROR_LOG("invalid channel count: \"" << m_iChannels << "\""); } } } resetPixelTransfer(); }else{ // multiTextureBuffer for(int y=0;y *src = image->shallowCopy(Rect(Point(x*m_iCellSize,y*m_iCellSize),m_matROISizes[x][y])); planarToInterleaved(src,m_matCellData[x][y],m_iCellSize*m_iChannels*sizeof(T)); delete src; } } } } // }}} template void GLTextureMapImage::resetPixelTransfer(){ glPixelTransferf(GL_ALPHA_SCALE,1); glPixelTransferf(GL_RED_SCALE,1); glPixelTransferf(GL_GREEN_SCALE,1); glPixelTransferf(GL_BLUE_SCALE,1); glPixelTransferf(GL_ALPHA_BIAS,0); glPixelTransferf(GL_RED_BIAS,0); glPixelTransferf(GL_GREEN_BIAS,0); glPixelTransferf(GL_BLUE_BIAS,0); } template void GLTextureMapImage::setUpPixelTransfer(depth d, float brightness, float contrast, float intensity, const ImgBase *image){ // {{{ open (void)intensity; icl32f fScaleRGB(0),fBiasRGB(0); if( (brightness < 0) && (contrast < 0) && (intensity < 0)){ // image is null, because SingleBufferMode does not work! icl64f dScaleRGB,dBiasRGB; // auto adaption std::vector > channelRanges = getMinMax(); Range r; if(channelRanges.size()){ r = Range(channelRanges[0].minVal,channelRanges[0].maxVal); for(int i=1;i r.maxVal) r.maxVal = channelRanges[i].maxVal; } }else{ r = Range(0,255); } icl64f l = iclMax(double(1),r.getLength()); switch (getDepth()){ case depth8u:{ dScaleRGB = l ? 255.0/l : 255; dBiasRGB = (- dScaleRGB * r.minVal)/255.0; break; } case depth16s:{ static const icl64f _max = (65536/2-1); dScaleRGB = l ? _max/l : _max; dBiasRGB = (- dScaleRGB * r.minVal)/255.0; break; } /* orig: not working but... why drawn as float case depth32s:{ // drawn as float dScaleRGB = l ? 255.0/l : 255; dBiasRGB = (- dScaleRGB * r.minVal)/255.0; // if not working properly: dBiasRGB /= 255.0 break; } */ case depth32s:{ // drawn as float dScaleRGB = l ? 255.0/l : 255; dBiasRGB = (- dScaleRGB * r.minVal)/255.0; // if not working properly: dBiasRGB /= 255.0 break; } case depth32f:{ dScaleRGB = l ? 255.0/l : 255; dBiasRGB = (- dScaleRGB * r.minVal)/255.0; dScaleRGB /= 255.0; break; } case depth64f:{ // drawn as float dScaleRGB = l ? 255.0/l : 255; dBiasRGB = (- dScaleRGB * r.minVal)/255.0; dScaleRGB /= 255.0; break; } default: ICL_INVALID_FORMAT; break; } fScaleRGB = dScaleRGB; fBiasRGB = dBiasRGB; }else{ fBiasRGB = (float)brightness/255.0; fScaleRGB = 1; switch(d){ case depth8u: fScaleRGB = 1; break; case depth16s: fScaleRGB = 127; break; // or 255 ? case depth32s: case depth32f: case depth64f: fScaleRGB = 1.0/255; break; } float c = (float)contrast/255; if(c>0) c*=10; fScaleRGB*=(1.0+c); fBiasRGB-=c/2; } glPixelTransferf(GL_ALPHA_SCALE,fScaleRGB); glPixelTransferf(GL_RED_SCALE,fScaleRGB); glPixelTransferf(GL_GREEN_SCALE,fScaleRGB); glPixelTransferf(GL_BLUE_SCALE,fScaleRGB); glPixelTransferf(GL_ALPHA_BIAS,fBiasRGB); glPixelTransferf(GL_RED_BIAS,fBiasRGB); glPixelTransferf(GL_GREEN_BIAS,fBiasRGB); glPixelTransferf(GL_BLUE_BIAS,fBiasRGB); } // }}} template bool GLTextureMapImage::compatible(const Img *image) const{ // {{{ open return image->getWidth() == m_iImageW && image->getHeight() == m_iImageH && image->getChannels() == m_iChannels; } // }}} template Img *GLTextureMapImage::deepCopy() const{ if(m_bUseSingleBuffer){ return 0; } Img *image = new Img(Size(m_iImageW,m_iImageH), m_iChannels); for(int y=0;ysetROI(Rect(Point(x*m_iCellSize,y*m_iCellSize),m_matROISizes[x][y])); interleavedToPlanar(m_matCellData[x][y],image,m_iCellSize*m_iChannels*sizeof(T)); } } image->setFullROI(); return image; } namespace{ inline float winToDraw(float x, float w) { return (2/w) * x -1; } inline float drawToWin(float x, float w) { return (w/2) * x + (w/2); } } template void GLTextureMapImage::drawTo(const Rect &rect, const Size &windowSize, scalemode mode){ // {{{ open if(!m_bUseSingleBuffer){ glGenTextures(m_iXCells*m_iYCells,m_matTextureNames.data()); //depth d = getDepth(); //int depthIdx = (int)d; setPackAlignment(getDepth(),m_iImageW); setUpPixelTransfer(getDepth(),m_aiBCI[0],m_aiBCI[1],m_aiBCI[2], 0); static GLenum aeGLTypes[] = { GL_UNSIGNED_BYTE, GL_SHORT, GL_FLOAT, GL_FLOAT, GL_FLOAT }; GLenum glType = aeGLTypes[getDepth()]; for(int y=0;y void GLTextureMapImage::drawTo3D(float *pCenter, float *pFirstAxis, float *pSecondAxis){ if(!m_bUseSingleBuffer){ glGenTextures(m_iXCells*m_iYCells,m_matTextureNames.data()); setPackAlignment(getDepth(),m_iImageW); setUpPixelTransfer(getDepth(),m_aiBCI[0],m_aiBCI[1],m_aiBCI[2], 0); static GLenum aeGLTypes[] = { GL_UNSIGNED_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_FLOAT }; GLenum glType = aeGLTypes[getDepth()]; for(int y=0;y inline void histo_entry(T v, double m, vector &h, unsigned int n, double r){ // todo check 1000 times +5 times (3Times done!) h[ ceil( n*(v-m)/(r+1)) ]++; } template void calculate_histo_interleaved(T *data, Size dataROISize, int dataLineLength, int channels, const std::vector &ranges, std::vector< std::vector > &histos){ for(int x=0;x const ImageStatistics &GLTextureMapImage::updateStatistics(ImageStatistics &s){ s.isNull = false; s.d = getDepth(); std::vector > rangesT = getMinMax(); s.ranges.resize(rangesT.size()); for(unsigned int i=0;i useRanges = s.ranges; if(s.params.getFormat() != formatMatrix){ std::fill(useRanges.begin(),useRanges.end(),Range64f(0,255)); } for(int y=0;y; template class GLTextureMapImage; template class GLTextureMapImage; template class GLTextureMapImage; }