From 30ded9e8ab0421b7671f7dd1ff7a5d07b167e43c Mon Sep 17 00:00:00 2001 From: BOUKHRIS Mohamed Omar Date: Wed, 17 Jul 2019 12:09:46 +0200 Subject: [PATCH 1/4] cgal depends on CImg --- .../MeshGenerationFromImage_test.cpp | 2 +- .../plugins/CGALPlugin/CMakeLists.txt | 28 +- .../CGALPlugin/MeshGenerationFromImage.h | 4 +- .../plugins/CImgPlugin/CMakeLists.txt | 5 +- .../CImgPlugin/src/CImgPlugin/CImgData.h | 644 ++++++++++++++++++ applications/plugins/image/ImageTypes.h | 633 +---------------- 6 files changed, 672 insertions(+), 644 deletions(-) create mode 100644 applications/plugins/CImgPlugin/src/CImgPlugin/CImgData.h diff --git a/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp b/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp index f331f860225..b228d5d6244 100644 --- a/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp +++ b/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp @@ -36,7 +36,7 @@ #define CGALPLUGIN_MESHGENERATIONFROMIMAGE_CPP #include -#include +//#include namespace cgal { diff --git a/applications/plugins/CGALPlugin/CMakeLists.txt b/applications/plugins/CGALPlugin/CMakeLists.txt index 814b2c3adc4..413516da5ff 100644 --- a/applications/plugins/CGALPlugin/CMakeLists.txt +++ b/applications/plugins/CGALPlugin/CMakeLists.txt @@ -31,16 +31,18 @@ set(README_FILES CGALPlugin.txt) find_package(SofaFramework REQUIRED) -find_package(image QUIET) -if(image_FOUND) - list(APPEND HEADER_FILES MeshGenerationFromImage.h) - list(APPEND HEADER_FILES MeshGenerationFromImage.inl) - list(APPEND SOURCE_FILES MeshGenerationFromImage.cpp) - find_package(CGAL REQUIRED COMPONENTS ImageIO) -else() - message(STATUS "CGALPlugin: could not find image, won't build MeshGenerationFromImage") - find_package(CGAL REQUIRED) +find_package(CImgPlugin QUIET) +if(CImgPlugin_FOUND) + list(APPEND HEADER_FILES MeshGenerationFromImage.h) + list(APPEND HEADER_FILES MeshGenerationFromImage.inl) + list(APPEND SOURCE_FILES MeshGenerationFromImage.cpp) + find_package(CGAL REQUIRED COMPONENTS ImageIO) +else () + message (STATUS "CImgPlugin not found, won't build MeshGenerationFromImage") + find_package(CGAL REQUIRED) endif() + + ## CGAL dependencies list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") find_package(MPFR REQUIRED) @@ -93,8 +95,12 @@ set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${CGALPLUGIN_VERSION}) set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-DSOFA_BUILD_CGALPLUGIN") set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${HEADER_FILES}") target_link_libraries(${PROJECT_NAME} SofaCore SofaSimulationCommon ${Boost_LIBRARIES} ${GMP_LIBRARIES} ${MPFR_LIBRARIES} ${CGAL_LIBRARY}) -if(image_FOUND) - target_link_libraries(${PROJECT_NAME} ${CGAL_ImageIO_LIBRARY} image) + + +if(CImgPlugin_FOUND) + target_link_libraries(${PROJECT_NAME} ${CGAL_ImageIO_LIBRARY} CImgPlugin) +else() + target_link_libraries(${PROJECT_NAME} ${CGAL_ImageIO_LIBRARY}) endif() if(SOFA_BUILD_TESTS) diff --git a/applications/plugins/CGALPlugin/MeshGenerationFromImage.h b/applications/plugins/CGALPlugin/MeshGenerationFromImage.h index d730d66c72d..d87b9910e5c 100644 --- a/applications/plugins/CGALPlugin/MeshGenerationFromImage.h +++ b/applications/plugins/CGALPlugin/MeshGenerationFromImage.h @@ -45,7 +45,9 @@ #include #include #include -#include + +//#include +#include //CGAL typedef CGAL::Exact_predicates_inexact_constructions_kernel K; diff --git a/applications/plugins/CImgPlugin/CMakeLists.txt b/applications/plugins/CImgPlugin/CMakeLists.txt index 257dacd712a..4ff857be427 100644 --- a/applications/plugins/CImgPlugin/CMakeLists.txt +++ b/applications/plugins/CImgPlugin/CMakeLists.txt @@ -4,7 +4,8 @@ project(CImgPlugin VERSION 0.1) set(HEADER_FILES src/CImgPlugin/ImageCImg.h src/CImgPlugin/CImgPlugin.h - src/CImgPlugin/SOFACImg.h + src/CImgPlugin/SOFACImg.h + src/CImgPlugin/CImgData.h ) set(SOURCE_FILES @@ -86,7 +87,7 @@ add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) target_compile_options(${PROJECT_NAME} PUBLIC ${CIMG_CFLAGS}) target_compile_options(${PROJECT_NAME} PRIVATE "-DSOFA_BUILD_CIMGPLUGIN") -target_link_libraries(${PROJECT_NAME} SofaCore ${EXTERNAL_LIBS}) +target_link_libraries(${PROJECT_NAME} SofaCore SofaSimulationCommon ${EXTERNAL_LIBS}) target_include_directories(${PROJECT_NAME} PUBLIC "$") target_include_directories(${PROJECT_NAME} PUBLIC "$") target_include_directories(${PROJECT_NAME} PUBLIC "$") diff --git a/applications/plugins/CImgPlugin/src/CImgPlugin/CImgData.h b/applications/plugins/CImgPlugin/src/CImgPlugin/CImgData.h new file mode 100644 index 00000000000..db574495a86 --- /dev/null +++ b/applications/plugins/CImgPlugin/src/CImgPlugin/CImgData.h @@ -0,0 +1,644 @@ +#pragma once + +#include + +// datatypes +#include +#include +#include + +// visual dependencies +#include +#include + +// helpers +#include +#include +#include +#include + + +namespace sofa +{ + +namespace defaulttype +{ + + + +/// a virtual, non templated Image class that can be allocated without knowing its exact type +struct BaseImage +{ + typedef Vec<5,unsigned int> imCoord; // [x,y,z,s,t] + virtual void setDimensions(const imCoord& dim) = 0; + virtual void fill(const SReal val)=0; + virtual ~BaseImage() {} +}; + + + + +//-----------------------------------------------------------------------------------------------// +/// 5d-image structure on top of a shared memory CImgList +//-----------------------------------------------------------------------------------------------// + + +template +struct Image : public BaseImage +{ + typedef _T T; + typedef cimg_library::CImg CImgT; + + /// the 5 dimension labels of an image ( x, y, z, spectrum=nb channels , time ) + typedef enum{ DIMENSION_X=0, DIMENSION_Y, DIMENSION_Z, DIMENSION_S /* spectrum = nb channels*/, DIMENSION_T /*4th dimension = time*/, NB_DimensionLabel } DimensionLabel; + +protected: + cimg_library::CImgList img; // list of images along temporal dimension. Each image is 4-dimensional (x,y,z,s) where s is the spectrum (e.g. channels for color images, vector or tensor values, etc.) + +public: + static const char* Name(); + + ///constructors/destructors + Image() {} + Image(const Image& _img, bool shared=false) : img(_img.getCImgList(), shared) {} + Image( const cimg_library::CImg& _img ) : img(_img) {} + + /// copy operators + Image& operator=(const Image& im) + { + if(im.getCImgList().size()) img.assign(im.getCImgList()); + return *this; + } + Image& assign(const Image& im, const bool shared=false) + { + if(im.getCImgList().size()) img.assign(im.getCImgList(),shared); + return *this; + } + + + void clear() { img.assign(); } + ~Image() override { clear(); } + + //accessors + cimg_library::CImgList& getCImgList() { return img; } + const cimg_library::CImgList& getCImgList() const { return img; } + + cimg_library::CImg& getCImg(const unsigned int t=0) { + if (t>=img.size()) { + assert(img._data != NULL); + return *img._data; + } + return img(t); + } + const cimg_library::CImg& getCImg(const unsigned int t=0) const { + if (t>=img.size()) { + assert(img._data != NULL); + return *img._data; + } + return img(t); + } + + inline bool isEmpty() const {return img.size()==0;} + + /// check if image coordinates are inside bounds + template + inline bool isInside( t x, t y, t z ) const + { + if(isEmpty()) return false; + if(x<0) return false; + if(y<0) return false; + if(z<0) return false; + if(x>=(t)img(0).width()) return false; + if(y>=(t)img(0).height()) return false; + if(z>=(t)img(0).depth()) return false; + return true; + } + + imCoord getDimensions() const + { + imCoord dim; + if(!img.size()) dim.fill(0); + else + { + dim[0]=img(0).width(); + dim[1]=img(0).height(); + dim[2]=img(0).depth(); + dim[3]=img(0).spectrum(); + dim[4]=img.size(); + } + return dim; + } + + //affectors + void setDimensions(const imCoord& dim) override + { + cimglist_for(img,l) img(l).resize(dim[0],dim[1],dim[2],dim[3]); + if(img.size()>dim[4]) img.remove(dim[4],img.size()-1); + else if(img.size()(dim[0],dim[1],dim[2],dim[3])); + } + + void fill(const SReal val) override + { + cimglist_for(img,l) img(l).fill((T)val); + } + + //iostream + inline friend std::istream& operator >> ( std::istream& in, Image& im ) + { + imCoord dim; in>>dim; + im.setDimensions(dim); + return in; + } + + friend std::ostream& operator << ( std::ostream& out, const Image& im ) + { + out<& other ) const + { + if( img.size() != other.img.size() ) return false; + for( unsigned t=0 ; t& other ) const + { + return !(*this==other); + } + + + + //basic functions to complement CImgList + + + /** + * Returns histograms of image channels (mergeChannels=false) or a single histogram of the norm (mergeChannels=true) + * the returned image size is [dimx,1,1,mergeChannels?1:nbChannels] + * Returns min / max values + */ + cimg_library::CImg get_histogram(T& value_min, T& value_max, const unsigned int dimx, const bool mergeChannels=false) const + { + if(!img.size()) return cimg_library::CImg(); + const unsigned int s=mergeChannels?1:img(0).spectrum(); + cimg_library::CImg res(dimx,1,1,s,0); + + if(mergeChannels) + { + value_min=cimg_library::cimg::type::max(); + value_max=cimg_library::cimg::type::min(); + cimglist_for(img,l) + cimg_forXYZ(img(l),x,y,z) + { + cimg_library::CImg vect=img(l).get_vector_at(x,y,z); + long double val=vect.magnitude(); + T tval=(T)val; + if(value_min>tval) value_min=tval; + if(value_max vect=img(l).get_vector_at(x,y,z); + long double val=vect.magnitude(); + long double v = ((long double)val-(long double)value_min)/((long double)value_max-(long double)value_min)*((long double)(dimx-1)); + if(v<0) v=0; + else if(v>(long double)(dimx-1)) v=(long double)(dimx-1); + ++res((int)(v),0,0,0); + } + } + else + { + value_min=img.min(); + value_max=img.max(); + if(value_max==value_min) value_max=value_min+(T)1; + cimglist_for(img,l) + cimg_forXYZC(img(l),x,y,z,c) + { + if((long double)value_max-(long double)value_min !=0) + { + const T val = img(l)(x,y,z,c); + long double v = ((long double)val-(long double)value_min)/((long double)value_max-(long double)value_min)*((long double)(dimx-1)); + if(v<0) v=0; + else if(v>(long double)(dimx-1)) v=(long double)(dimx-1); + ++res((int)(v),0,0,c); + } + } + } + return res; + } + + // returns an image corresponing to a plane indexed by "coord" along "axis" and inside a bounding box + cimg_library::CImg get_plane(const unsigned int coord,const unsigned int axis,const Mat<2,3,unsigned int>& ROI,const unsigned int t=0, const bool mergeChannels=false) const + { + if(mergeChannels) return get_plane(coord,axis,ROI,t,false).norm(); + else + { + if(axis==0) return getCImg(t).get_crop(coord,ROI[0][1],ROI[0][2],0,coord,ROI[1][1],ROI[1][2],getCImg(t).spectrum()-1).permute_axes("zyxc"); + else if(axis==1) return getCImg(t).get_crop(ROI[0][0],coord,ROI[0][2],0,ROI[1][0],coord,ROI[1][2],getCImg(t).spectrum()-1).permute_axes("xzyc"); + else return getCImg(t).get_crop(ROI[0][0],ROI[0][1],coord,0,ROI[1][0],ROI[1][1],coord,getCImg(t).spectrum()-1); + } + } + + // returns a binary image cutting through 3D input meshes, corresponding to a plane indexed by "coord" along "axis" and inside a bounding box + // positions are in image coordinates + template + cimg_library::CImg get_slicedModels(const unsigned int coord,const unsigned int axis,const Mat<2,3,unsigned int>& ROI,const ResizableExtVector >& position, const ResizableExtVector< component::visualmodel::VisualModelImpl::Triangle >& triangle, const ResizableExtVector< component::visualmodel::VisualModelImpl::Quad >& quad) const + { + const unsigned int dim[3]= {ROI[1][0]-ROI[0][0]+1,ROI[1][1]-ROI[0][1]+1,ROI[1][2]-ROI[0][2]+1}; + cimg_library::CImg ret; + if(axis==0) ret=cimg_library::CImg(dim[2],dim[1]); + else if(axis==1) ret=cimg_library::CImg(dim[0],dim[2]); + else ret=cimg_library::CImg(dim[0],dim[1]); + ret.fill(false); + + if(triangle.size()==0 && quad.size()==0) //pt visu + { + for (unsigned int i = 0; i < position.size() ; i++) + { + Vec<3,unsigned int> pt((unsigned int)helper::round(position[i][0]),(unsigned int)helper::round(position[i][1]),(unsigned int)helper::round(position[i][2])); + if(pt[axis]==coord) if(pt[0]>=ROI[0][0] && pt[0]<=ROI[1][0]) if(pt[1]>=ROI[0][1] && pt[1]<=ROI[1][1]) if(pt[2]>=ROI[0][2] && pt[2]<=ROI[1][2]) + { + if(axis==0) ret(pt[2]-ROI[0][2],pt[1]-ROI[0][1])=true; + else if(axis==1) ret(pt[0]-ROI[0][0],pt[2]-ROI[0][2])=true; + else ret(pt[0]-ROI[0][0],pt[1]-ROI[0][1])=true; + } + + } + } + else + { + //unsigned int count; + Real alpha; + Vec<3,Real> v[4]; + Vec<3,int> pt[4]; + bool tru=true; + + for (unsigned int i = 0; i < triangle.size() ; i++) // box/ triangle intersection -> polygon with a maximum of 5 edges, to draw + { + for (unsigned int j = 0; j < 3 ; j++) { v[j] = position[triangle[i][j]]; pt[j]=Vec<3,int>((int)helper::round(v[j][0]),(int)helper::round(v[j][1]),(int)helper::round(v[j][2])); } + + helper::vector > pts; + for (unsigned int j = 0; j < 3 ; j++) + { + if(pt[j][axis]==(int)coord) pts.push_back(pt[j]); + unsigned int k=(j==2)?0:j+1; + if(pt[j][axis]=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + } + else + { + alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + alpha=((Real)coord-0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + } + } + for (unsigned int j = 0; j < pts.size() ; j++) + { + unsigned int k=(j==pts.size()-1)?0:j+1; + { + if(axis==0) ret.draw_line(pts[j][2]-(int)ROI[0][2],pts[j][1]-(int)ROI[0][1],pts[k][2]-(int)ROI[0][2],pts[k][1]-(int)ROI[0][1],&tru); + else if(axis==1) ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][2]-(int)ROI[0][2],pts[k][0]-(int)ROI[0][0],pts[k][2]-(int)ROI[0][2],&tru); + else ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][1]-(int)ROI[0][1],pts[k][0]-(int)ROI[0][0],pts[k][1]-(int)ROI[0][1],&tru); + } + } + + } + for (unsigned int i = 0; i < quad.size() ; i++) + { + for (unsigned int j = 0; j < 4 ; j++) { v[j] = position[quad[i][j]]; pt[j]=Vec<3,int>((int)helper::round(v[j][0]),(int)helper::round(v[j][1]),(int)helper::round(v[j][2])); } + + helper::vector > pts; + for (unsigned int j = 0; j < 4 ; j++) + { + if(pt[j][axis]==(int)coord) pts.push_back(pt[j]); + unsigned int k=(j==3)?0:j+1; + if(pt[j][axis]=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + } + else + { + alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + alpha=((Real)coord-0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); + } + } + for (unsigned int j = 0; j < pts.size() ; j++) + { + unsigned int k=(j==pts.size()-1)?0:j+1; + { + if(axis==0) ret.draw_line(pts[j][2]-(int)ROI[0][2],pts[j][1]-(int)ROI[0][1],pts[k][2]-(int)ROI[0][2],pts[k][1]-(int)ROI[0][1],&tru); + else if(axis==1) ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][2]-(int)ROI[0][2],pts[k][0]-(int)ROI[0][0],pts[k][2]-(int)ROI[0][2],&tru); + else ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][1]-(int)ROI[0][1],pts[k][0]-(int)ROI[0][0],pts[k][1]-(int)ROI[0][1],&tru); + } + } + } + + } + return ret; + } + + /// \returns an approximative size in bytes, useful for debugging + size_t approximativeSizeInBytes() const + { + if( img.is_empty() ) return 0; + return img(0).width()*img(0).height()*img(0).depth()*img(0).spectrum()*img.size()*sizeof(T); + } + +}; + + +typedef Image ImageC; +typedef Image ImageUC; +typedef Image ImageI; +typedef Image ImageUI; +typedef Image ImageS; +typedef Image ImageUS; +typedef Image ImageL; +typedef Image ImageUL; +typedef Image ImageF; +typedef Image ImageD; +typedef Image ImageB; +typedef Image ImageR; + +template<> inline const char* ImageC::Name() { return "ImageC"; } +template<> inline const char* ImageUC::Name() { return "ImageUC"; } +template<> inline const char* ImageI::Name() { return "ImageI"; } +template<> inline const char* ImageUI::Name() { return "ImageUI"; } +template<> inline const char* ImageS::Name() { return "ImageS"; } +template<> inline const char* ImageUS::Name() { return "ImageUS"; } +template<> inline const char* ImageL::Name() { return "ImageL"; } +template<> inline const char* ImageUL::Name() { return "ImageUL"; } +template<> inline const char* ImageF::Name() { return "ImageF"; } +template<> inline const char* ImageD::Name() { return "ImageD"; } +template<> inline const char* ImageB::Name() { return "ImageB"; } + +// The next line hides all those methods from the doxygen documentation +/// \cond TEMPLATE_OVERRIDES + +template<> struct DataTypeName< defaulttype::ImageC > { static const char* name() { return "ImageC"; } }; +template<> struct DataTypeName< defaulttype::ImageUC > { static const char* name() { return "ImageUC"; } }; +template<> struct DataTypeName< defaulttype::ImageI > { static const char* name() { return "ImageI"; } }; +template<> struct DataTypeName< defaulttype::ImageUI > { static const char* name() { return "ImageUI"; } }; +template<> struct DataTypeName< defaulttype::ImageS > { static const char* name() { return "ImageS"; } }; +template<> struct DataTypeName< defaulttype::ImageUS > { static const char* name() { return "ImageUS"; } }; +template<> struct DataTypeName< defaulttype::ImageL > { static const char* name() { return "ImageL"; } }; +template<> struct DataTypeName< defaulttype::ImageUL > { static const char* name() { return "ImageUL"; } }; +template<> struct DataTypeName< defaulttype::ImageF > { static const char* name() { return "ImageF"; } }; +template<> struct DataTypeName< defaulttype::ImageD > { static const char* name() { return "ImageD"; } }; +template<> struct DataTypeName< defaulttype::ImageB > { static const char* name() { return "ImageB"; } }; + +/// \endcond + +//-----------------------------------------------------------------------------------------------// +// Transforms between image and space/time +//-----------------------------------------------------------------------------------------------// + +// generic interface +template +struct ImageTransform +{ + typedef _Real Real; + typedef Vec<3,Real> Coord; // 3d coords + +public: + virtual Coord fromImage(const Coord& ip) const {return ip;} // image coord to space transform + virtual Real fromImage(const Real& ip) const {return ip;} // image index to time transform + virtual Coord toImage(const Coord& p) const {return p;} // space coord to image transform + virtual Real toImage(const Real& p) const {return p;} // time to image index transform + virtual Coord toImageInt(const Coord& p) const { Coord p2 = toImage(p); return Coord( helper::round(p2.x()),helper::round(p2.y()),helper::round(p2.z()) );} // space coord to rounded image transform + virtual Real toImageInt(const Real& p) const { return helper::round(toImage(p));} // time to rounded image index transform + + virtual const Coord& getTranslation() const = 0; + virtual const Coord& getRotation() const = 0; + virtual const Coord& getScale() const = 0; + + virtual void update()=0; + +}; + + +// abstract class with vector and iostream +template +struct TImageTransform : public ImageTransform<_Real> +{ + typedef ImageTransform<_Real> Inherited; + typedef typename Inherited::Real Real; + typedef typename Inherited::Coord Coord; + enum {size = N}; + typedef Vec Params; // transform parameters + +protected: + Params P; + +public: + TImageTransform():P() { P.clear(); } + TImageTransform(const Params& _P):P(_P) {} + TImageTransform(const TImageTransform& T):P(T.getParams()) {} + + Params& getParams() {return P;} + const Params& getParams() const {return P;} + + static const char* Name(); + + inline friend std::istream& operator >> ( std::istream& in, TImageTransform& T ) { in>>T.getParams(); return in; } + friend std::ostream& operator << ( std::ostream& out, const TImageTransform& T ) { out<update(); return *this; } + void set(const Params& _P) { P=_P; this->update(); } +}; + + + +// implementation of linear (scale+rotation+translation) and perspective transforms +// for perspective transforms (only for 2D images), the pinhole camera is located at ( scalex(dimx-1)/2, scaley(dimy-1)/2, -scalez/2) + +template +struct ImageLPTransform : public TImageTransform<12,_Real> +{ + typedef TImageTransform<12,_Real> Inherited; // 12 params : translations,rotations,scales,timeOffset,timeScale,isPerspective + typedef typename Inherited::Real Real; + typedef typename Inherited::Params Params; + typedef typename Inherited::Coord Coord; + +protected: + Real camx; Real camy; // used only for perpective transforms (camera offset = c_x and c_y pinhole camera intrinsic parameters) + +public: + Coord& getTranslation() { return *reinterpret_cast(&this->P[0]); } + const Coord& getTranslation() const { return *reinterpret_cast(&this->P[0]); } + Coord& getRotation() { return *reinterpret_cast(&this->P[3]); } + const Coord& getRotation() const { return *reinterpret_cast(&this->P[3]); } + Coord& getScale() { return *reinterpret_cast(&this->P[6]); } + const Coord& getScale() const { return *reinterpret_cast(&this->P[6]); } + Real& getOffsetT() { return *reinterpret_cast(&this->P[9]); } + const Real& getOffsetT() const { return *reinterpret_cast(&this->P[9]); } + Real& getScaleT() { return *reinterpret_cast(&this->P[10]); } + const Real& getScaleT() const { return *reinterpret_cast(&this->P[10]); } + Real& isPerspective() { return *reinterpret_cast(&this->P[11]); } + const Real& isPerspective() const { return *reinterpret_cast(&this->P[11]); } + + ImageLPTransform() // identity + :Inherited() + { + getScale()[0]=getScale()[1]=getScale()[2]=getScaleT()=(Real)1.0; + camx = camy = (Real)0.0; + } + + virtual ~ImageLPTransform() {} + + //internal data + helper::Quater qrotation; Coord axisrotation; Real phirotation; // "rotation" in other formats + + void setCamPos(const Real& cx,const Real& cy) {this->camx=cx; this->camy=cy; } + + //internal data update + virtual void update() + { + Coord rot=getRotation() * (Real)M_PI / (Real)180.0; + qrotation = helper::Quater< Real >::createQuaterFromEuler(rot); + qrotation.quatToAxis(axisrotation,phirotation); + phirotation*=(Real)180.0/ (Real)M_PI; + } + + //transform functions + // note: for perpective transforms (f_x and f_y pinhole camera intrinsic parameters are scalez/2*scalex and scalez/2*scaley) + virtual Coord fromImage(const Coord& ip) const + { + if(isPerspective()==0) return qrotation.rotate( ip.linearProduct(getScale()) ) + getTranslation(); + else if(isPerspective()==1) + { + Coord sp=ip.linearProduct(getScale()); + sp[0]+=(Real)2.0*ip[2]*getScale()[0]*(ip[0]-camx); + sp[1]+=(Real)2.0*ip[2]*getScale()[1]*(ip[1]-camy); + return qrotation.rotate( sp ) + getTranslation(); + } + else if(isPerspective()==2) // half perspective, half orthographic + { + Coord sp=ip.linearProduct(getScale()); + sp[0]+=(Real)2.0*ip[2]*getScale()[0]*(ip[0]-camx); + return qrotation.rotate( sp ) + getTranslation(); + } + else // half perspective, half orthographic + { + Coord sp=ip.linearProduct(getScale()); + sp[1]+=(Real)2.0*ip[2]*getScale()[1]*(ip[1]-camy); + return qrotation.rotate( sp ) + getTranslation(); + } + } + virtual Real fromImage(const Real& ip) const { return ip*getScaleT() + getOffsetT(); } + virtual Coord toImage(const Coord& p) const + { + if(isPerspective()==0) return qrotation.inverseRotate( p-getTranslation() ).linearDivision(getScale()); + else if(isPerspective()==1) + { + Coord sp=qrotation.inverseRotate( p-getTranslation() ); + sp[0]=(sp[0]/getScale()[0] + (Real)2.0*sp[2]*camx/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); + sp[1]=(sp[1]/getScale()[1] + (Real)2.0*sp[2]*camy/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); + sp[2]=(Real)0.0; + return sp; + } + else if(isPerspective()==2) + { + Coord sp=qrotation.inverseRotate( p-getTranslation() ); + sp[0]=(sp[0]/getScale()[0] + (Real)2.0*sp[2]*camx/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); + sp[1]=sp[1]/getScale()[1]; + sp[2]=(Real)0.0; + return sp; + } + else + { + Coord sp=qrotation.inverseRotate( p-getTranslation() ); + sp[0]=sp[0]/getScale()[0]; + sp[1]=(sp[1]/getScale()[1] + (Real)2.0*sp[2]*camy/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); + sp[2]=(Real)0.0; + return sp; + } + } + + virtual Real toImage(const Real& p) const { return (p - getOffsetT())/getScaleT(); } + +}; + +////// infos for Data + +template +struct ImageTypeInfo +{ + typedef TDataType DataType; + typedef typename DataType::T BaseType; + typedef DataTypeInfo BaseTypeInfo; + typedef typename BaseTypeInfo::ValueType ValueType; + typedef DataTypeInfo ValueTypeInfo; + + enum { ValidInfo = BaseTypeInfo::ValidInfo }; ///< 1 if this type has valid infos + enum { FixedSize = 1 }; ///< 1 if this type has a fixed size -> always 1 Image + enum { ZeroConstructor = 0 }; ///< 1 if the constructor is equivalent to setting memory to 0 -> I guess so, a default Image is initialzed with nothing + enum { SimpleCopy = 0 }; ///< 1 if copying the data can be done with a memcpy + enum { SimpleLayout = 0 }; ///< 1 if the layout in memory is simply N values of the same base type + enum { Integer = 0 }; ///< 1 if this type uses integer values + enum { Scalar = 0 }; ///< 1 if this type uses scalar values + enum { Text = 0 }; ///< 1 if this type uses text values + enum { CopyOnWrite = 1 }; ///< 1 if this type uses copy-on-write -> it seems to be THE important option not to perform too many copies + enum { Container = 0 }; ///< 1 if this type is a container + + enum { Size = 1 }; ///< largest known fixed size for this type, as returned by size() + + static size_t size() { return 1; } + static size_t byteSize() { return 1; } + + static size_t size(const DataType& /*data*/) { return 1; } + + static bool setSize(DataType& /*data*/, size_t /*size*/) { return false; } + + template + static void getValue(const DataType &/*data*/, size_t /*index*/, T& /*value*/) + { + return; + } + + template + static void setValue(DataType &/*data*/, size_t /*index*/, const T& /*value*/ ) + { + return; + } + + static void getValueString(const DataType &data, size_t index, std::string& value) + { + if (index != 0) return; + std::ostringstream o; o << data; value = o.str(); + } + + static void setValueString(DataType &data, size_t index, const std::string& value ) + { + if (index != 0) return; + std::istringstream i(value); i >> data; + } + + static const void* getValuePtr(const DataType&) + { + return NULL; + } + + static void* getValuePtr(DataType&) + { + return NULL; + } +}; + + +template +struct DataTypeInfo< Image > : public ImageTypeInfo< Image > +{ + static std::string name() { std::ostringstream o; o << "Image<" << DataTypeName::name() << ">"; return o.str(); } +}; + + +} +} + diff --git a/applications/plugins/image/ImageTypes.h b/applications/plugins/image/ImageTypes.h index 2cbedb0b693..e9b022d0192 100644 --- a/applications/plugins/image/ImageTypes.h +++ b/applications/plugins/image/ImageTypes.h @@ -33,16 +33,11 @@ #endif #include -#include -#include -#include -#include -#include -#include -#include -#include + #include "VectorVis.h" -#include + +//(imports + Image data structure + others) are in here +#include namespace sofa { @@ -51,550 +46,6 @@ namespace defaulttype { - - - -/// a virtual, non templated Image class that can be allocated without knowing its exact type -struct BaseImage -{ - typedef Vec<5,unsigned int> imCoord; // [x,y,z,s,t] - virtual void setDimensions(const imCoord& dim) = 0; - virtual void fill(const SReal val)=0; - virtual ~BaseImage() {} -}; - - - - -//-----------------------------------------------------------------------------------------------// -/// 5d-image structure on top of a shared memory CImgList -//-----------------------------------------------------------------------------------------------// - - -template -struct Image : public BaseImage -{ - typedef _T T; - typedef cimg_library::CImg CImgT; - - /// the 5 dimension labels of an image ( x, y, z, spectrum=nb channels , time ) - typedef enum{ DIMENSION_X=0, DIMENSION_Y, DIMENSION_Z, DIMENSION_S /* spectrum = nb channels*/, DIMENSION_T /*4th dimension = time*/, NB_DimensionLabel } DimensionLabel; - -protected: - cimg_library::CImgList img; // list of images along temporal dimension. Each image is 4-dimensional (x,y,z,s) where s is the spectrum (e.g. channels for color images, vector or tensor values, etc.) - -public: - static const char* Name(); - - ///constructors/destructors - Image() {} - Image(const Image& _img, bool shared=false) : img(_img.getCImgList(), shared) {} - Image( const cimg_library::CImg& _img ) : img(_img) {} - - /// copy operators - Image& operator=(const Image& im) - { - if(im.getCImgList().size()) img.assign(im.getCImgList()); - return *this; - } - Image& assign(const Image& im, const bool shared=false) - { - if(im.getCImgList().size()) img.assign(im.getCImgList(),shared); - return *this; - } - - - void clear() { img.assign(); } - ~Image() override { clear(); } - - //accessors - cimg_library::CImgList& getCImgList() { return img; } - const cimg_library::CImgList& getCImgList() const { return img; } - - cimg_library::CImg& getCImg(const unsigned int t=0) { - if (t>=img.size()) { - assert(img._data != NULL); - return *img._data; - } - return img(t); - } - const cimg_library::CImg& getCImg(const unsigned int t=0) const { - if (t>=img.size()) { - assert(img._data != NULL); - return *img._data; - } - return img(t); - } - - inline bool isEmpty() const {return img.size()==0;} - - /// check if image coordinates are inside bounds - template - inline bool isInside( t x, t y, t z ) const - { - if(isEmpty()) return false; - if(x<0) return false; - if(y<0) return false; - if(z<0) return false; - if(x>=(t)img(0).width()) return false; - if(y>=(t)img(0).height()) return false; - if(z>=(t)img(0).depth()) return false; - return true; - } - - imCoord getDimensions() const - { - imCoord dim; - if(!img.size()) dim.fill(0); - else - { - dim[0]=img(0).width(); - dim[1]=img(0).height(); - dim[2]=img(0).depth(); - dim[3]=img(0).spectrum(); - dim[4]=img.size(); - } - return dim; - } - - //affectors - void setDimensions(const imCoord& dim) override - { - cimglist_for(img,l) img(l).resize(dim[0],dim[1],dim[2],dim[3]); - if(img.size()>dim[4]) img.remove(dim[4],img.size()-1); - else if(img.size()(dim[0],dim[1],dim[2],dim[3])); - } - - void fill(const SReal val) override - { - cimglist_for(img,l) img(l).fill((T)val); - } - - //iostream - inline friend std::istream& operator >> ( std::istream& in, Image& im ) - { - imCoord dim; in>>dim; - im.setDimensions(dim); - return in; - } - - friend std::ostream& operator << ( std::ostream& out, const Image& im ) - { - out<& other ) const - { - if( img.size() != other.img.size() ) return false; - for( unsigned t=0 ; t& other ) const - { - return !(*this==other); - } - - - - //basic functions to complement CImgList - - - /** - * Returns histograms of image channels (mergeChannels=false) or a single histogram of the norm (mergeChannels=true) - * the returned image size is [dimx,1,1,mergeChannels?1:nbChannels] - * Returns min / max values - */ - cimg_library::CImg get_histogram(T& value_min, T& value_max, const unsigned int dimx, const bool mergeChannels=false) const - { - if(!img.size()) return cimg_library::CImg(); - const unsigned int s=mergeChannels?1:img(0).spectrum(); - cimg_library::CImg res(dimx,1,1,s,0); - - if(mergeChannels) - { - value_min=cimg_library::cimg::type::max(); - value_max=cimg_library::cimg::type::min(); - cimglist_for(img,l) - cimg_forXYZ(img(l),x,y,z) - { - cimg_library::CImg vect=img(l).get_vector_at(x,y,z); - long double val=vect.magnitude(); - T tval=(T)val; - if(value_min>tval) value_min=tval; - if(value_max vect=img(l).get_vector_at(x,y,z); - long double val=vect.magnitude(); - long double v = ((long double)val-(long double)value_min)/((long double)value_max-(long double)value_min)*((long double)(dimx-1)); - if(v<0) v=0; - else if(v>(long double)(dimx-1)) v=(long double)(dimx-1); - ++res((int)(v),0,0,0); - } - } - else - { - value_min=img.min(); - value_max=img.max(); - if(value_max==value_min) value_max=value_min+(T)1; - cimglist_for(img,l) - cimg_forXYZC(img(l),x,y,z,c) - { - if((long double)value_max-(long double)value_min !=0) - { - const T val = img(l)(x,y,z,c); - long double v = ((long double)val-(long double)value_min)/((long double)value_max-(long double)value_min)*((long double)(dimx-1)); - if(v<0) v=0; - else if(v>(long double)(dimx-1)) v=(long double)(dimx-1); - ++res((int)(v),0,0,c); - } - } - } - return res; - } - - // returns an image corresponing to a plane indexed by "coord" along "axis" and inside a bounding box - cimg_library::CImg get_plane(const unsigned int coord,const unsigned int axis,const Mat<2,3,unsigned int>& ROI,const unsigned int t=0, const bool mergeChannels=false) const - { - if(mergeChannels) return get_plane(coord,axis,ROI,t,false).norm(); - else - { - if(axis==0) return getCImg(t).get_crop(coord,ROI[0][1],ROI[0][2],0,coord,ROI[1][1],ROI[1][2],getCImg(t).spectrum()-1).permute_axes("zyxc"); - else if(axis==1) return getCImg(t).get_crop(ROI[0][0],coord,ROI[0][2],0,ROI[1][0],coord,ROI[1][2],getCImg(t).spectrum()-1).permute_axes("xzyc"); - else return getCImg(t).get_crop(ROI[0][0],ROI[0][1],coord,0,ROI[1][0],ROI[1][1],coord,getCImg(t).spectrum()-1); - } - } - - // returns a binary image cutting through 3D input meshes, corresponding to a plane indexed by "coord" along "axis" and inside a bounding box - // positions are in image coordinates - template - cimg_library::CImg get_slicedModels(const unsigned int coord,const unsigned int axis,const Mat<2,3,unsigned int>& ROI,const ResizableExtVector >& position, const ResizableExtVector< component::visualmodel::VisualModelImpl::Triangle >& triangle, const ResizableExtVector< component::visualmodel::VisualModelImpl::Quad >& quad) const - { - const unsigned int dim[3]= {ROI[1][0]-ROI[0][0]+1,ROI[1][1]-ROI[0][1]+1,ROI[1][2]-ROI[0][2]+1}; - cimg_library::CImg ret; - if(axis==0) ret=cimg_library::CImg(dim[2],dim[1]); - else if(axis==1) ret=cimg_library::CImg(dim[0],dim[2]); - else ret=cimg_library::CImg(dim[0],dim[1]); - ret.fill(false); - - if(triangle.size()==0 && quad.size()==0) //pt visu - { - for (unsigned int i = 0; i < position.size() ; i++) - { - Vec<3,unsigned int> pt((unsigned int)helper::round(position[i][0]),(unsigned int)helper::round(position[i][1]),(unsigned int)helper::round(position[i][2])); - if(pt[axis]==coord) if(pt[0]>=ROI[0][0] && pt[0]<=ROI[1][0]) if(pt[1]>=ROI[0][1] && pt[1]<=ROI[1][1]) if(pt[2]>=ROI[0][2] && pt[2]<=ROI[1][2]) - { - if(axis==0) ret(pt[2]-ROI[0][2],pt[1]-ROI[0][1])=true; - else if(axis==1) ret(pt[0]-ROI[0][0],pt[2]-ROI[0][2])=true; - else ret(pt[0]-ROI[0][0],pt[1]-ROI[0][1])=true; - } - - } - } - else - { - //unsigned int count; - Real alpha; - Vec<3,Real> v[4]; - Vec<3,int> pt[4]; - bool tru=true; - - for (unsigned int i = 0; i < triangle.size() ; i++) // box/ triangle intersection -> polygon with a maximum of 5 edges, to draw - { - for (unsigned int j = 0; j < 3 ; j++) { v[j] = position[triangle[i][j]]; pt[j]=Vec<3,int>((int)helper::round(v[j][0]),(int)helper::round(v[j][1]),(int)helper::round(v[j][2])); } - - helper::vector > pts; - for (unsigned int j = 0; j < 3 ; j++) - { - if(pt[j][axis]==(int)coord) pts.push_back(pt[j]); - unsigned int k=(j==2)?0:j+1; - if(pt[j][axis]=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - } - else - { - alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - alpha=((Real)coord-0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - } - } - for (unsigned int j = 0; j < pts.size() ; j++) - { - unsigned int k=(j==pts.size()-1)?0:j+1; - { - if(axis==0) ret.draw_line(pts[j][2]-(int)ROI[0][2],pts[j][1]-(int)ROI[0][1],pts[k][2]-(int)ROI[0][2],pts[k][1]-(int)ROI[0][1],&tru); - else if(axis==1) ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][2]-(int)ROI[0][2],pts[k][0]-(int)ROI[0][0],pts[k][2]-(int)ROI[0][2],&tru); - else ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][1]-(int)ROI[0][1],pts[k][0]-(int)ROI[0][0],pts[k][1]-(int)ROI[0][1],&tru); - } - } - - } - for (unsigned int i = 0; i < quad.size() ; i++) - { - for (unsigned int j = 0; j < 4 ; j++) { v[j] = position[quad[i][j]]; pt[j]=Vec<3,int>((int)helper::round(v[j][0]),(int)helper::round(v[j][1]),(int)helper::round(v[j][2])); } - - helper::vector > pts; - for (unsigned int j = 0; j < 4 ; j++) - { - if(pt[j][axis]==(int)coord) pts.push_back(pt[j]); - unsigned int k=(j==3)?0:j+1; - if(pt[j][axis]=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - } - else - { - alpha=((Real)coord+0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - alpha=((Real)coord-0.5 -v[k][axis])/(v[j][axis]-v[k][axis]); if( alpha>=0 && alpha <=1) pts.push_back(Vec<3,int>((int)helper::round(v[j][0]*alpha + v[k][0]*(1.0-alpha)),(int)helper::round(v[j][1]*alpha + v[k][1]*(1.0-alpha)),(int)helper::round(v[j][2]*alpha + v[k][2]*(1.0-alpha)))); - } - } - for (unsigned int j = 0; j < pts.size() ; j++) - { - unsigned int k=(j==pts.size()-1)?0:j+1; - { - if(axis==0) ret.draw_line(pts[j][2]-(int)ROI[0][2],pts[j][1]-(int)ROI[0][1],pts[k][2]-(int)ROI[0][2],pts[k][1]-(int)ROI[0][1],&tru); - else if(axis==1) ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][2]-(int)ROI[0][2],pts[k][0]-(int)ROI[0][0],pts[k][2]-(int)ROI[0][2],&tru); - else ret.draw_line(pts[j][0]-(int)ROI[0][0],pts[j][1]-(int)ROI[0][1],pts[k][0]-(int)ROI[0][0],pts[k][1]-(int)ROI[0][1],&tru); - } - } - } - - } - return ret; - } - - /// \returns an approximative size in bytes, useful for debugging - size_t approximativeSizeInBytes() const - { - if( img.is_empty() ) return 0; - return img(0).width()*img(0).height()*img(0).depth()*img(0).spectrum()*img.size()*sizeof(T); - } - -}; - - -typedef Image ImageC; -typedef Image ImageUC; -typedef Image ImageI; -typedef Image ImageUI; -typedef Image ImageS; -typedef Image ImageUS; -typedef Image ImageL; -typedef Image ImageUL; -typedef Image ImageF; -typedef Image ImageD; -typedef Image ImageB; -typedef Image ImageR; - -template<> inline const char* ImageC::Name() { return "ImageC"; } -template<> inline const char* ImageUC::Name() { return "ImageUC"; } -template<> inline const char* ImageI::Name() { return "ImageI"; } -template<> inline const char* ImageUI::Name() { return "ImageUI"; } -template<> inline const char* ImageS::Name() { return "ImageS"; } -template<> inline const char* ImageUS::Name() { return "ImageUS"; } -template<> inline const char* ImageL::Name() { return "ImageL"; } -template<> inline const char* ImageUL::Name() { return "ImageUL"; } -template<> inline const char* ImageF::Name() { return "ImageF"; } -template<> inline const char* ImageD::Name() { return "ImageD"; } -template<> inline const char* ImageB::Name() { return "ImageB"; } - -// The next line hides all those methods from the doxygen documentation -/// \cond TEMPLATE_OVERRIDES - -template<> struct DataTypeName< defaulttype::ImageC > { static const char* name() { return "ImageC"; } }; -template<> struct DataTypeName< defaulttype::ImageUC > { static const char* name() { return "ImageUC"; } }; -template<> struct DataTypeName< defaulttype::ImageI > { static const char* name() { return "ImageI"; } }; -template<> struct DataTypeName< defaulttype::ImageUI > { static const char* name() { return "ImageUI"; } }; -template<> struct DataTypeName< defaulttype::ImageS > { static const char* name() { return "ImageS"; } }; -template<> struct DataTypeName< defaulttype::ImageUS > { static const char* name() { return "ImageUS"; } }; -template<> struct DataTypeName< defaulttype::ImageL > { static const char* name() { return "ImageL"; } }; -template<> struct DataTypeName< defaulttype::ImageUL > { static const char* name() { return "ImageUL"; } }; -template<> struct DataTypeName< defaulttype::ImageF > { static const char* name() { return "ImageF"; } }; -template<> struct DataTypeName< defaulttype::ImageD > { static const char* name() { return "ImageD"; } }; -template<> struct DataTypeName< defaulttype::ImageB > { static const char* name() { return "ImageB"; } }; - -/// \endcond - -//-----------------------------------------------------------------------------------------------// -// Transforms between image and space/time -//-----------------------------------------------------------------------------------------------// - -// generic interface -template -struct ImageTransform -{ - typedef _Real Real; - typedef Vec<3,Real> Coord; // 3d coords - -public: - virtual Coord fromImage(const Coord& ip) const {return ip;} // image coord to space transform - virtual Real fromImage(const Real& ip) const {return ip;} // image index to time transform - virtual Coord toImage(const Coord& p) const {return p;} // space coord to image transform - virtual Real toImage(const Real& p) const {return p;} // time to image index transform - virtual Coord toImageInt(const Coord& p) const { Coord p2 = toImage(p); return Coord( helper::round(p2.x()),helper::round(p2.y()),helper::round(p2.z()) );} // space coord to rounded image transform - virtual Real toImageInt(const Real& p) const { return helper::round(toImage(p));} // time to rounded image index transform - - virtual const Coord& getTranslation() const = 0; - virtual const Coord& getRotation() const = 0; - virtual const Coord& getScale() const = 0; - - virtual void update()=0; - -}; - - -// abstract class with vector and iostream -template -struct TImageTransform : public ImageTransform<_Real> -{ - typedef ImageTransform<_Real> Inherited; - typedef typename Inherited::Real Real; - typedef typename Inherited::Coord Coord; - enum {size = N}; - typedef Vec Params; // transform parameters - -protected: - Params P; - -public: - TImageTransform():P() { P.clear(); } - TImageTransform(const Params& _P):P(_P) {} - TImageTransform(const TImageTransform& T):P(T.getParams()) {} - - Params& getParams() {return P;} - const Params& getParams() const {return P;} - - static const char* Name(); - - inline friend std::istream& operator >> ( std::istream& in, TImageTransform& T ) { in>>T.getParams(); return in; } - friend std::ostream& operator << ( std::ostream& out, const TImageTransform& T ) { out<update(); return *this; } - void set(const Params& _P) { P=_P; this->update(); } -}; - - - -// implementation of linear (scale+rotation+translation) and perspective transforms -// for perspective transforms (only for 2D images), the pinhole camera is located at ( scalex(dimx-1)/2, scaley(dimy-1)/2, -scalez/2) - -template -struct ImageLPTransform : public TImageTransform<12,_Real> -{ - typedef TImageTransform<12,_Real> Inherited; // 12 params : translations,rotations,scales,timeOffset,timeScale,isPerspective - typedef typename Inherited::Real Real; - typedef typename Inherited::Params Params; - typedef typename Inherited::Coord Coord; - -protected: - Real camx; Real camy; // used only for perpective transforms (camera offset = c_x and c_y pinhole camera intrinsic parameters) - -public: - Coord& getTranslation() { return *reinterpret_cast(&this->P[0]); } - const Coord& getTranslation() const { return *reinterpret_cast(&this->P[0]); } - Coord& getRotation() { return *reinterpret_cast(&this->P[3]); } - const Coord& getRotation() const { return *reinterpret_cast(&this->P[3]); } - Coord& getScale() { return *reinterpret_cast(&this->P[6]); } - const Coord& getScale() const { return *reinterpret_cast(&this->P[6]); } - Real& getOffsetT() { return *reinterpret_cast(&this->P[9]); } - const Real& getOffsetT() const { return *reinterpret_cast(&this->P[9]); } - Real& getScaleT() { return *reinterpret_cast(&this->P[10]); } - const Real& getScaleT() const { return *reinterpret_cast(&this->P[10]); } - Real& isPerspective() { return *reinterpret_cast(&this->P[11]); } - const Real& isPerspective() const { return *reinterpret_cast(&this->P[11]); } - - ImageLPTransform() // identity - :Inherited() - { - getScale()[0]=getScale()[1]=getScale()[2]=getScaleT()=(Real)1.0; - camx = camy = (Real)0.0; - } - - virtual ~ImageLPTransform() {} - - //internal data - helper::Quater qrotation; Coord axisrotation; Real phirotation; // "rotation" in other formats - - void setCamPos(const Real& cx,const Real& cy) {this->camx=cx; this->camy=cy; } - - //internal data update - virtual void update() - { - Coord rot=getRotation() * (Real)M_PI / (Real)180.0; - qrotation = helper::Quater< Real >::createQuaterFromEuler(rot); - qrotation.quatToAxis(axisrotation,phirotation); - phirotation*=(Real)180.0/ (Real)M_PI; - } - - //transform functions - // note: for perpective transforms (f_x and f_y pinhole camera intrinsic parameters are scalez/2*scalex and scalez/2*scaley) - virtual Coord fromImage(const Coord& ip) const - { - if(isPerspective()==0) return qrotation.rotate( ip.linearProduct(getScale()) ) + getTranslation(); - else if(isPerspective()==1) - { - Coord sp=ip.linearProduct(getScale()); - sp[0]+=(Real)2.0*ip[2]*getScale()[0]*(ip[0]-camx); - sp[1]+=(Real)2.0*ip[2]*getScale()[1]*(ip[1]-camy); - return qrotation.rotate( sp ) + getTranslation(); - } - else if(isPerspective()==2) // half perspective, half orthographic - { - Coord sp=ip.linearProduct(getScale()); - sp[0]+=(Real)2.0*ip[2]*getScale()[0]*(ip[0]-camx); - return qrotation.rotate( sp ) + getTranslation(); - } - else // half perspective, half orthographic - { - Coord sp=ip.linearProduct(getScale()); - sp[1]+=(Real)2.0*ip[2]*getScale()[1]*(ip[1]-camy); - return qrotation.rotate( sp ) + getTranslation(); - } - } - virtual Real fromImage(const Real& ip) const { return ip*getScaleT() + getOffsetT(); } - virtual Coord toImage(const Coord& p) const - { - if(isPerspective()==0) return qrotation.inverseRotate( p-getTranslation() ).linearDivision(getScale()); - else if(isPerspective()==1) - { - Coord sp=qrotation.inverseRotate( p-getTranslation() ); - sp[0]=(sp[0]/getScale()[0] + (Real)2.0*sp[2]*camx/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); - sp[1]=(sp[1]/getScale()[1] + (Real)2.0*sp[2]*camy/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); - sp[2]=(Real)0.0; - return sp; - } - else if(isPerspective()==2) - { - Coord sp=qrotation.inverseRotate( p-getTranslation() ); - sp[0]=(sp[0]/getScale()[0] + (Real)2.0*sp[2]*camx/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); - sp[1]=sp[1]/getScale()[1]; - sp[2]=(Real)0.0; - return sp; - } - else - { - Coord sp=qrotation.inverseRotate( p-getTranslation() ); - sp[0]=sp[0]/getScale()[0]; - sp[1]=(sp[1]/getScale()[1] + (Real)2.0*sp[2]*camy/getScale()[2])/((Real)1.0 + (Real)2.0*sp[2]/getScale()[2]); - sp[2]=(Real)0.0; - return sp; - } - } - - virtual Real toImage(const Real& p) const { return (p - getOffsetT())/getScaleT(); } - -}; - - - //-----------------------------------------------------------------------------------------------// // Histogram structure //-----------------------------------------------------------------------------------------------// @@ -942,82 +393,6 @@ struct ImagePlane }; - -////// infos for Data - -template -struct ImageTypeInfo -{ - typedef TDataType DataType; - typedef typename DataType::T BaseType; - typedef DataTypeInfo BaseTypeInfo; - typedef typename BaseTypeInfo::ValueType ValueType; - typedef DataTypeInfo ValueTypeInfo; - - enum { ValidInfo = BaseTypeInfo::ValidInfo }; ///< 1 if this type has valid infos - enum { FixedSize = 1 }; ///< 1 if this type has a fixed size -> always 1 Image - enum { ZeroConstructor = 0 }; ///< 1 if the constructor is equivalent to setting memory to 0 -> I guess so, a default Image is initialzed with nothing - enum { SimpleCopy = 0 }; ///< 1 if copying the data can be done with a memcpy - enum { SimpleLayout = 0 }; ///< 1 if the layout in memory is simply N values of the same base type - enum { Integer = 0 }; ///< 1 if this type uses integer values - enum { Scalar = 0 }; ///< 1 if this type uses scalar values - enum { Text = 0 }; ///< 1 if this type uses text values - enum { CopyOnWrite = 1 }; ///< 1 if this type uses copy-on-write -> it seems to be THE important option not to perform too many copies - enum { Container = 0 }; ///< 1 if this type is a container - - enum { Size = 1 }; ///< largest known fixed size for this type, as returned by size() - - static size_t size() { return 1; } - static size_t byteSize() { return 1; } - - static size_t size(const DataType& /*data*/) { return 1; } - - static bool setSize(DataType& /*data*/, size_t /*size*/) { return false; } - - template - static void getValue(const DataType &/*data*/, size_t /*index*/, T& /*value*/) - { - return; - } - - template - static void setValue(DataType &/*data*/, size_t /*index*/, const T& /*value*/ ) - { - return; - } - - static void getValueString(const DataType &data, size_t index, std::string& value) - { - if (index != 0) return; - std::ostringstream o; o << data; value = o.str(); - } - - static void setValueString(DataType &data, size_t index, const std::string& value ) - { - if (index != 0) return; - std::istringstream i(value); i >> data; - } - - static const void* getValuePtr(const DataType&) - { - return NULL; - } - - static void* getValuePtr(DataType&) - { - return NULL; - } -}; - - -template -struct DataTypeInfo< Image > : public ImageTypeInfo< Image > -{ - static std::string name() { std::ostringstream o; o << "Image<" << DataTypeName::name() << ">"; return o.str(); } -}; - - - } // namespace defaulttype From 949bc74ce596d06fccbf06af4956a1ff4f5cd029 Mon Sep 17 00:00:00 2001 From: BOUKHRIS Mohamed Omar Date: Thu, 18 Jul 2019 13:40:30 +0200 Subject: [PATCH 2/4] removed commented includes in sources + unnecessary included targets in cmakelists (SofaSimulationCommon) --- .../CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp | 1 - applications/plugins/CGALPlugin/MeshGenerationFromImage.h | 1 - applications/plugins/CImgPlugin/CMakeLists.txt | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp b/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp index b228d5d6244..69c1af96f66 100644 --- a/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp +++ b/applications/plugins/CGALPlugin/CGALPlugin_test/MeshGenerationFromImage_test.cpp @@ -36,7 +36,6 @@ #define CGALPLUGIN_MESHGENERATIONFROMIMAGE_CPP #include -//#include namespace cgal { diff --git a/applications/plugins/CGALPlugin/MeshGenerationFromImage.h b/applications/plugins/CGALPlugin/MeshGenerationFromImage.h index d87b9910e5c..4f0328a1ac5 100644 --- a/applications/plugins/CGALPlugin/MeshGenerationFromImage.h +++ b/applications/plugins/CGALPlugin/MeshGenerationFromImage.h @@ -46,7 +46,6 @@ #include #include -//#include #include //CGAL diff --git a/applications/plugins/CImgPlugin/CMakeLists.txt b/applications/plugins/CImgPlugin/CMakeLists.txt index 4ff857be427..bd6a53f3534 100644 --- a/applications/plugins/CImgPlugin/CMakeLists.txt +++ b/applications/plugins/CImgPlugin/CMakeLists.txt @@ -87,7 +87,7 @@ add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) target_compile_options(${PROJECT_NAME} PUBLIC ${CIMG_CFLAGS}) target_compile_options(${PROJECT_NAME} PRIVATE "-DSOFA_BUILD_CIMGPLUGIN") -target_link_libraries(${PROJECT_NAME} SofaCore SofaSimulationCommon ${EXTERNAL_LIBS}) +target_link_libraries(${PROJECT_NAME} SofaCore ${EXTERNAL_LIBS}) target_include_directories(${PROJECT_NAME} PUBLIC "$") target_include_directories(${PROJECT_NAME} PUBLIC "$") target_include_directories(${PROJECT_NAME} PUBLIC "$") From ed3ca1529cdf5f55ab06df12aaf5e259bbf61c5a Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 24 Jul 2019 10:32:55 +0200 Subject: [PATCH 3/4] Fix indentation --- .../plugins/CGALPlugin/CMakeLists.txt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/applications/plugins/CGALPlugin/CMakeLists.txt b/applications/plugins/CGALPlugin/CMakeLists.txt index 413516da5ff..ccffc518df8 100644 --- a/applications/plugins/CGALPlugin/CMakeLists.txt +++ b/applications/plugins/CGALPlugin/CMakeLists.txt @@ -32,14 +32,15 @@ set(README_FILES CGALPlugin.txt) find_package(SofaFramework REQUIRED) find_package(CImgPlugin QUIET) + if(CImgPlugin_FOUND) - list(APPEND HEADER_FILES MeshGenerationFromImage.h) - list(APPEND HEADER_FILES MeshGenerationFromImage.inl) - list(APPEND SOURCE_FILES MeshGenerationFromImage.cpp) - find_package(CGAL REQUIRED COMPONENTS ImageIO) + list(APPEND HEADER_FILES MeshGenerationFromImage.h) + list(APPEND HEADER_FILES MeshGenerationFromImage.inl) + list(APPEND SOURCE_FILES MeshGenerationFromImage.cpp) + find_package(CGAL REQUIRED COMPONENTS ImageIO) else () - message (STATUS "CImgPlugin not found, won't build MeshGenerationFromImage") - find_package(CGAL REQUIRED) + message (STATUS "CImgPlugin not found, won't build MeshGenerationFromImage") + find_package(CGAL REQUIRED) endif() @@ -98,14 +99,14 @@ target_link_libraries(${PROJECT_NAME} SofaCore SofaSimulationCommon ${Boost_LIBR if(CImgPlugin_FOUND) - target_link_libraries(${PROJECT_NAME} ${CGAL_ImageIO_LIBRARY} CImgPlugin) + target_link_libraries(${PROJECT_NAME} ${CGAL_ImageIO_LIBRARY} CImgPlugin) else() - target_link_libraries(${PROJECT_NAME} ${CGAL_ImageIO_LIBRARY}) + target_link_libraries(${PROJECT_NAME} ${CGAL_ImageIO_LIBRARY}) endif() if(SOFA_BUILD_TESTS) - find_package(SofaTest QUIET) - add_subdirectory(CGALPlugin_test) + find_package(SofaTest QUIET) + add_subdirectory(CGALPlugin_test) endif() ## Install rules for the library and the headers; CMake package configurations files From aa9e3c8d8aa94b12e8f9794436defcbaa673d3bb Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 24 Jul 2019 10:43:48 +0200 Subject: [PATCH 4/4] Fix indentation --- applications/plugins/CImgPlugin/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/plugins/CImgPlugin/CMakeLists.txt b/applications/plugins/CImgPlugin/CMakeLists.txt index bd6a53f3534..7244f01723a 100644 --- a/applications/plugins/CImgPlugin/CMakeLists.txt +++ b/applications/plugins/CImgPlugin/CMakeLists.txt @@ -4,8 +4,8 @@ project(CImgPlugin VERSION 0.1) set(HEADER_FILES src/CImgPlugin/ImageCImg.h src/CImgPlugin/CImgPlugin.h - src/CImgPlugin/SOFACImg.h - src/CImgPlugin/CImgData.h + src/CImgPlugin/SOFACImg.h + src/CImgPlugin/CImgData.h ) set(SOURCE_FILES