├── Input ├── DUC129_1.png ├── cse013_0.png ├── cse013_5.png ├── image_01.bmp ├── Olin071_5.png └── image_163.bmp ├── TRW_S ├── errorFn.cpp ├── instances.inc ├── instances.h ├── treeProbabilities.def ├── ordering.def ├── MRFEnergy.def ├── MRFEnergy.h ├── typeBinaryFast.h ├── typeBinary.h ├── typePotts.h ├── typeTruncatedLinear.h └── typeTruncatedLinear2D.h ├── cv_utils ├── ProposalGenerator.h ├── CostFunctor.h ├── CMakeLists.txt ├── MatrixOperations.cpp ├── FusionSpaceSolver.h ├── Histogram.h ├── PointCloudOperations.cpp ├── CommonOperations.cpp ├── ImageMask.h ├── StatisticsCalculations.cpp ├── FusionSpaceSolver.cpp ├── cv_utils.h └── ImageOperations.cpp ├── CMakeLists.txt ├── DataStructure.h ├── StructureFinder.h ├── README.md ├── ConcaveHullFinder.h ├── BSplineSurface.h ├── TRWSFusion.h ├── utils.h ├── LayerDepthRepresenter.h ├── main.cpp ├── ProposalDesigner.h ├── Segment.h ├── StructureFinder.cpp ├── BSplineSurface.cpp └── ConcaveHullFinder.cpp /Input/DUC129_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/art-programmer/LayeredSceneDecomposition/HEAD/Input/DUC129_1.png -------------------------------------------------------------------------------- /Input/cse013_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/art-programmer/LayeredSceneDecomposition/HEAD/Input/cse013_0.png -------------------------------------------------------------------------------- /Input/cse013_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/art-programmer/LayeredSceneDecomposition/HEAD/Input/cse013_5.png -------------------------------------------------------------------------------- /Input/image_01.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/art-programmer/LayeredSceneDecomposition/HEAD/Input/image_01.bmp -------------------------------------------------------------------------------- /Input/Olin071_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/art-programmer/LayeredSceneDecomposition/HEAD/Input/Olin071_5.png -------------------------------------------------------------------------------- /Input/image_163.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/art-programmer/LayeredSceneDecomposition/HEAD/Input/image_163.bmp -------------------------------------------------------------------------------- /TRW_S/errorFn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "MRFEnergy.h" 6 | 7 | #include "instances.inc" 8 | 9 | using namespace std; 10 | 11 | inline void DefaultErrorFn(char* msg) 12 | { 13 | fprintf(stderr, "%s\n", msg); 14 | exit(1); 15 | } 16 | -------------------------------------------------------------------------------- /cv_utils/ProposalGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef PROPOSAL_GENERATOR_H__ 2 | #define PROPOSAL_GENERATOR_H__ 3 | 4 | #include 5 | 6 | 7 | class ProposalGenerator 8 | { 9 | public: 10 | virtual void setCurrentSolution(const std::vector ¤t_solution) = 0; 11 | virtual std::vector > getProposal() const = 0; 12 | 13 | protected: 14 | std::vector current_solution_; 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /TRW_S/instances.inc: -------------------------------------------------------------------------------- 1 | 2 | #include "MRFEnergy.h" 3 | 4 | //template class MRFEnergy; 5 | //template class MRFEnergy; 6 | //template class MRFEnergy; 7 | template class MRFEnergy; 8 | //template class MRFEnergy; 9 | //template class MRFEnergy; 10 | //template class MRFEnergy; 11 | //template class MRFEnergy; 12 | 13 | -------------------------------------------------------------------------------- /cv_utils/CostFunctor.h: -------------------------------------------------------------------------------- 1 | #ifndef COST_FUNCTOR_H__ 2 | #define COST_FUNCTOR_H__ 3 | 4 | class CostFunctor 5 | { 6 | public: 7 | virtual double operator()(const int node_index, const int label) const = 0; 8 | virtual double operator()(const int node_index_1, const int node_index_2, const int label_1, const int label_2) const = 0; 9 | virtual void setCurrentSolution(const std::vector ¤t_solution) {}; 10 | virtual double getLabelCost() const { return 0; }; 11 | virtual double getLabelIndicatorConflictCost() const { return 0; }; 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /TRW_S/instances.h: -------------------------------------------------------------------------------- 1 | #ifndef __INSTANCES_H__ 2 | #define __INSTANCES_H__ 3 | 4 | 5 | #if defined(_MSC_VER) 6 | 7 | // C4661: '...' : no suitable definition provided for explicit template instantiation request 8 | #pragma warning(disable: 4661) 9 | 10 | #endif 11 | 12 | #include "typeBinary.h" 13 | #include "typeBinaryFast.h" 14 | #include "typePotts.h" 15 | #include "typeGeneral.h" 16 | #include "typeTruncatedLinear.h" 17 | #include "typeTruncatedQuadratic.h" 18 | #include "typeTruncatedLinear2D.h" 19 | #include "typeTruncatedQuadratic2D.h" 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project (LayeredSceneDecomposition) 3 | find_package(OpenCV REQUIRED) 4 | find_package(gflags REQUIRED) 5 | 6 | set(CMAKE_BUILD_TYPE Release) 7 | set(CMAKE_CXX_FLAGS "-std=c++0x -w") 8 | 9 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 10 | add_subdirectory(cv_utils) 11 | 12 | #link_directories(cv_utils) 13 | #} /opt/gurobi650/linux64/include) 14 | file(GLOB SOURCES "*.cpp") 15 | add_executable(LayeredSceneDecomposition ${SOURCES}) 16 | target_link_libraries(LayeredSceneDecomposition ${OpenCV_LIBS} ${GFlags_LIBS} gflags cv_utils) 17 | -------------------------------------------------------------------------------- /cv_utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project (cv_utils) 3 | set(CMAKE_BUILD_TYPE Release) 4 | set(CMAKE_CXX_FLAGS "-std=c++0x") 5 | #add_definitions(-std=c++11) 6 | #set(CMAKE_CXX_STANDARD 11) 7 | find_package(OpenCV REQUIRED) 8 | find_package(PCL REQUIRED COMPONENTS features kdtree) 9 | include_directories(${PCL_LIBRARY_DIRS}) 10 | link_directories(${PCL_LIBRARY_DIRS}) 11 | add_definitions(${PCL_DEFINITIONS}) 12 | file(GLOB SOURCES "*.cpp") 13 | add_library(cv_utils SHARED ${SOURCES} TRW_S/errorFn.cpp) 14 | target_link_libraries(cv_utils ${OpenCV_LIBS}) 15 | target_link_libraries(cv_utils ${PCL_FEATURES_LIBRARIES} ${PCL_KDTREE_LIBRARIES}) 16 | -------------------------------------------------------------------------------- /cv_utils/MatrixOperations.cpp: -------------------------------------------------------------------------------- 1 | #include "cv_utils.h" 2 | 3 | using namespace std; 4 | using namespace Eigen; 5 | 6 | namespace cv_utils 7 | { 8 | vector > calcInverse(const vector > &matrix) 9 | { 10 | assert(matrix.size() > 0 && matrix.size() == matrix.begin()->size()); 11 | const int NUM_DIMENSIONS = matrix.size(); 12 | MatrixXd matrix_eigen(NUM_DIMENSIONS, NUM_DIMENSIONS); 13 | for (int c = 0; c < NUM_DIMENSIONS; c++) 14 | for (int d = 0; d < NUM_DIMENSIONS; d++) 15 | matrix_eigen(c, d) = matrix[c][d]; 16 | MatrixXd inverse_matrix_eigen = matrix_eigen.inverse(); 17 | vector > inverse_matrix(NUM_DIMENSIONS, vector(NUM_DIMENSIONS)); 18 | for (int c = 0; c < NUM_DIMENSIONS; c++) 19 | for (int d = 0; d < NUM_DIMENSIONS; d++) 20 | inverse_matrix[c][d] = inverse_matrix_eigen(c, d); 21 | return inverse_matrix; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cv_utils/FusionSpaceSolver.h: -------------------------------------------------------------------------------- 1 | #ifndef FUSION_SPACE_SOLVER_H__ 2 | #define FUSION_SPACE_SOLVER_H__ 3 | 4 | #include 5 | 6 | #include "CostFunctor.h" 7 | #include "ProposalGenerator.h" 8 | 9 | 10 | class FusionSpaceSolver 11 | { 12 | public: 13 | 14 | FusionSpaceSolver(const int NUM_NODES, const std::vector > &node_neighbors, CostFunctor &cost_functor, ProposalGenerator &proposal_generator, const int NUM_ITERATIONS = 1000, const bool CONSIDER_LABEL_COST = false); 15 | 16 | // void setNeighbors(); 17 | //void setNeighbors(const int width, const int height, const int neighbor_system = 8); 18 | 19 | std::vector solve(const int NUM_ITERATIONS, const std::vector &initial_solution); 20 | 21 | private: 22 | const int NUM_NODES_; 23 | const int NUM_ITERATIONS_; 24 | const bool CONSIDER_LABEL_COST_; 25 | 26 | const std::vector > node_neighbors_; 27 | CostFunctor &cost_functor_; 28 | ProposalGenerator &proposal_generator_; 29 | 30 | std::vector fuse(const std::vector > &proposal_labels, std::vector &energy_info); 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /DataStructure.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__DataStructure__ 2 | #define __LayerDepthMap__DataStructure__ 3 | 4 | #include 5 | #include 6 | 7 | struct RepresenterPenalties { 8 | double data_depth_pen; 9 | double data_color_pen; 10 | double data_normal_pen; 11 | double data_non_plane_pen; 12 | 13 | double surface_pen; 14 | 15 | double smoothness_pen; 16 | double smoothness_small_constant_pen; 17 | double smoothness_concave_shape_pen; 18 | double smoothness_anisotropic_diffusion_pen; 19 | 20 | double other_viewpoint_smoothness_pen; 21 | double other_viewpoint_depth_conflict_pen; 22 | 23 | double smoothness_empty_non_empty_ratio; 24 | 25 | double huge_pen; 26 | }; 27 | 28 | struct DataStatistics { 29 | double pixel_fitting_distance_threshold; 30 | double pixel_fitting_angle_threshold; 31 | double pixel_fitting_color_likelihood_threshold; 32 | double depth_diff_var; 33 | double similar_angle_threshold; 34 | double depth_conflict_tolerance; 35 | double depth_change_smoothness_threshold; 36 | double viewpoint_movement; 37 | double bspline_surface_num_pixels_threshold; 38 | double background_depth_diff_tolerance; 39 | }; 40 | 41 | #endif /* defined(__LayerDepthMap__DataStructure__) */ 42 | -------------------------------------------------------------------------------- /TRW_S/treeProbabilities.def: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "MRFEnergy.h" 7 | 8 | //#include "instances.inc" 9 | 10 | /////////////////////////////////////////////////////////////////////////// 11 | /////////////////////////////////////////////////////////////////////////// 12 | /////////////////////////////////////////////////////////////////////////// 13 | 14 | template void MRFEnergy::SetMonotonicTrees() 15 | { 16 | Node* i; 17 | MRFEdge* e; 18 | 19 | if (!m_isEnergyConstructionCompleted) 20 | { 21 | CompleteGraphConstruction(); 22 | } 23 | 24 | for (i=m_nodeFirst; i; i=i->m_next) 25 | { 26 | REAL mu; 27 | 28 | int nForward = 0, nBackward = 0; 29 | for (e=i->m_firstForward; e; e=e->m_nextForward) 30 | { 31 | nForward ++; 32 | } 33 | for (e=i->m_firstBackward; e; e=e->m_nextBackward) 34 | { 35 | nBackward ++; 36 | } 37 | int ni = (nForward > nBackward) ? nForward : nBackward; 38 | 39 | mu = (REAL)1 / ni; 40 | for (e=i->m_firstBackward; e; e=e->m_nextBackward) 41 | { 42 | e->m_gammaBackward = mu; 43 | } 44 | for (e=i->m_firstForward; e; e=e->m_nextForward) 45 | { 46 | e->m_gammaForward = mu; 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /StructureFinder.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__StructureFinder__ 2 | #define __LayerDepthMap__StructureFinder__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "DataStructure.h" 10 | #include "TRW_S/MRFEnergy.h" 11 | #include "Segment.h" 12 | 13 | class StructureFinder{ 14 | 15 | public: 16 | StructureFinder(const int image_width, const int image_height, const std::map &segments, const std::vector &candidate_segment_mask, const std::vector visible_segmentation, const std::vector &visible_depths, const std::vector &background_depths, const std::vector &segment_backmost_layer_index_map, const RepresenterPenalties penalties, const DataStatistics statistics); 17 | 18 | std::vector > > getStructures() const; 19 | 20 | private: 21 | const int IMAGE_WIDTH_; 22 | const int IMAGE_HEIGHT_; 23 | 24 | const int NUM_SURFACES_; 25 | const int NUM_PIXELS_; 26 | 27 | const RepresenterPenalties penalties_; 28 | const DataStatistics statistics_; 29 | 30 | const std::map segments_; 31 | const std::vector visible_segmentation_; 32 | const std::vector candidate_segment_mask_; 33 | const std::vector visible_depths_; 34 | const std::vector background_depths_; 35 | const std::vector &segment_backmost_layer_index_map_; 36 | 37 | std::vector > > structure_score_surface_ids_pairs_; 38 | 39 | 40 | void findTwoOrthogonalSurfaceStructures(); 41 | }; 42 | 43 | #endif /* defined(__LayerDepthMap__StructureFinder__) */ 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Layered Scene Decomposition via the Occlusion-CRF 2 | 3 | By Chen Liu, Yasutaka Furukawa, and Pushmeet Kohli 4 | 5 | ### Introduction 6 | 7 | This paper proposes a novel layered depth map representation and its inference algorithm which is able to infer invisible surfaces behind occlusions. To learn more, please see our CVPR 2016 [paper](http://www.cse.wustl.edu/~furukawa/papers/2016-cvpr-layer.pdf) or visit our [project website](http://sites.wustl.edu/chenliu/layered-scene) 8 | 9 | This code implements the algorithm described in our paper in C++. 10 | 11 | ### Requirements 12 | 13 | 0. OpenCV 14 | 1. PCL 15 | 2. gflags 16 | 17 | ### Usages 18 | 19 | To compile the program: 20 | 21 | 0. mkdir build 22 | 1. cd build 23 | 2. cmake .. 24 | 3. make 25 | 26 | To run the program on your own data: 27 | 28 | ./LayeredSceneDecomposition --image_path=*"your image path"* --point_cloud_path=*"your point cloud path"* --result_folder=*"where you want to save results"* --cache_folder=*"where you want to save cache"* 29 | 30 | To run the program on the demo data: 31 | 32 | ./LayeredSceneDecomposition --image_path=../Input/image_01.txt --point_cloud_path=../Input/point_cloud_01.txt --result_folder=../Result --cache_folder=../Cache 33 | 34 | Point cloud file format: 35 | 36 | The point cloud file stores a 3D point cloud, each of which corresponds to one image pixel. 37 | The number in the first row equals to image_width * image_height. 38 | Then, each row stores 3D coordinates for a point which corresponds to a pixel (indexed by y * image_width + x). 39 | 40 | ### Contact 41 | 42 | If you have any questions, please contact me at chenliu@wustl.edu. 43 | -------------------------------------------------------------------------------- /ConcaveHullFinder.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__ConcaveHullFinder__ 2 | #define __LayerDepthMap__ConcaveHullFinder__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "DataStructure.h" 10 | #include "TRW_S/MRFEnergy.h" 11 | #include "Segment.h" 12 | 13 | class ConcaveHullFinder{ 14 | 15 | public: 16 | ConcaveHullFinder(const int image_width, const int image_height, const std::vector &point_cloud, const std::vector &segmentation, const std::map &segments, const std::vector &ROI_mask, const RepresenterPenalties penalties, const DataStatistics statistics, const bool consider_background); 17 | 18 | ~ConcaveHullFinder(); 19 | 20 | //get concave hull 21 | std::vector getConcaveHull(); 22 | 23 | 24 | private: 25 | const std::vector segmentation_; 26 | const std::vector point_cloud_; 27 | const int IMAGE_WIDTH_; 28 | const int IMAGE_HEIGHT_; 29 | 30 | 31 | std::map > surface_point_clouds_; 32 | std::map > surface_depths_; 33 | std::map > surface_relations_; 34 | std::map segment_type_map_; 35 | std::map segment_direction_map_; 36 | std::vector surface_normals_angles_; 37 | 38 | const std::vector ROI_mask_; 39 | const int NUM_SURFACES_; 40 | const int NUM_PIXELS_; 41 | 42 | const RepresenterPenalties penalties_; 43 | const DataStatistics statistics_; 44 | 45 | std::vector concave_hull_labels_; 46 | std::set concave_hull_surfaces_; 47 | 48 | 49 | //calculate concave hull 50 | void calcConcaveHull(); 51 | }; 52 | 53 | #endif /* defined(__LayerDepthMap__ConcaveHullFinder__) */ 54 | -------------------------------------------------------------------------------- /BSplineSurface.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__BSplineSurface__ 2 | #define __LayerDepthMap__BSplineSurface__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "DataStructure.h" 12 | //#include "BSpline.h" 13 | 14 | 15 | class BSplineSurface{ 16 | 17 | public: 18 | BSplineSurface(const std::vector &point_cloud, const std::vector &pixels, const int image_width, const int image_heigth, const double stride_x, const double stride_y, const int bspline_order); 19 | 20 | //get depth map 21 | std::vector getDepthMap() const; 22 | 23 | private: 24 | const int IMAGE_WIDTH_; 25 | const int IMAGE_HEIGHT_; 26 | const int NUM_PIXELS_; 27 | const double STRIDE_X_; 28 | const double STRIDE_Y_; 29 | const int BSPLINE_ORDER_; 30 | 31 | std::vector segment_pixels_; 32 | std::vector control_point_xs_; 33 | std::vector control_point_ys_; 34 | 35 | std::vector depth_map_; 36 | 37 | 38 | //initialize control points 39 | void initControlPoints(); 40 | 41 | //fit b-spline surface 42 | void fitBSplineSurface(const std::vector &point_cloud, const std::vector &pixels); 43 | 44 | //calculate 2D basis function value 45 | double calcBasisFunctionValue2D(const double x, const double y, const double control_point_x, const double control_point_y, const double stride_x, const double stride_y, const int order); 46 | 47 | //calculate 1D basis function value 48 | double calcBasisFunctionValue1D(const double &x, const double &control_point_x, const double &stride_x, const int &order); 49 | }; 50 | 51 | #endif /* defined(__LayerDepthMap__BSplineSurface__) */ 52 | -------------------------------------------------------------------------------- /cv_utils/Histogram.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace cv_utils 5 | { 6 | template class Histogram 7 | { 8 | public: 9 | Histogram(const int NUM_GRAMS, const T MIN_VALUE, const T MAX_VALUE, const std::vector &values = std::vector()) : NUM_GRAMS_(NUM_GRAMS), MIN_VALUE_(MIN_VALUE), MAX_VALUE_(MAX_VALUE), num_values_(values.size()), histos_(std::vector(NUM_GRAMS, 0)) 10 | { 11 | //std::cout << MIN_VALUE_ << '\t' << MAX_VALUE_ << std::endl; 12 | assert(MIN_VALUE_ < MAX_VALUE_); 13 | //std::cout << NUM_GRAMS_ << std::endl; 14 | for (typename std::vector::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) { 15 | if (*value_it >= MIN_VALUE_ && *value_it <= MAX_VALUE) { 16 | histos_[calcHistoIndex(*value_it)]++; 17 | //std::cout << calcHistoIndex(*value_it) << std::endl; 18 | } 19 | } 20 | }; 21 | double getEntropy() 22 | { 23 | double entropy = 0; 24 | for (std::vector::const_iterator histo_it = histos_.begin(); histo_it != histos_.end(); histo_it++) 25 | entropy += -1.0 * *histo_it / num_values_ * log(1.0 * *histo_it / num_values_); 26 | return entropy; 27 | }; 28 | double getProbability(const T &value) 29 | { 30 | if (value < MIN_VALUE_ || value > MAX_VALUE_) 31 | return 0; 32 | return histos_[calcHistoIndex(value)]; 33 | }; 34 | 35 | private: 36 | const int NUM_GRAMS_; 37 | const T MIN_VALUE_, MAX_VALUE_; 38 | int num_values_; 39 | std::vector histos_; 40 | 41 | 42 | double calcHistoIndex(const T &value) 43 | { 44 | return std::min(std::max(static_cast(1.0 * (value - MIN_VALUE_) / (MAX_VALUE_ - MIN_VALUE_) * NUM_GRAMS_), 0), NUM_GRAMS_ - 1); 45 | }; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /cv_utils/PointCloudOperations.cpp: -------------------------------------------------------------------------------- 1 | #include "cv_utils.h" 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | namespace cv_utils 8 | { 9 | // void segmentPointCloudRansac(const vector &point_cloud, const vector > &neighbors, vector > &planes, vector &assignment, const double DENOTED_FITTING_ERROR_THRESHOLD, const int DENOTED_NUM_PLANES_THRESHOLD, const double DENOTED_FITTING_RATIO_THRESHOLD) 10 | // { 11 | // const double FITTING_ERROR_THRESHOLD = DENOTED_FITTING_ERROR_THRESHOLD; 12 | // const int NUM_PLANES_THRESHOLD = DENOTED_NUM_PLANES_THRESHOLD > 0 ? DENOTED_NUM_PLANES_THRESHOLD : point_cloud.size() / 3; 13 | // for (int plane_index = 0; plane_index < NUM_PLANES_THRESHOLD; plane_index++) { 14 | // } 15 | // } 16 | 17 | 18 | bool writePointCloud(const string &filename, const vector &point_cloud, const int IMAGE_WIDTH, const int IMAGE_HEIGHT) 19 | { 20 | ofstream out_str(filename); 21 | if (!out_str) 22 | return false; 23 | out_str << IMAGE_WIDTH << '\t' << IMAGE_HEIGHT << endl; 24 | for (int pixel = 0; pixel < IMAGE_WIDTH * IMAGE_HEIGHT; pixel++) 25 | out_str << point_cloud[pixel * 3 + 0] << '\t' << point_cloud[pixel * 3 + 1] << '\t' << point_cloud[pixel * 3 + 2] << endl; 26 | out_str.close(); 27 | return true; 28 | } 29 | 30 | bool readPointCloud(const string &filename, vector &point_cloud) 31 | { 32 | ifstream in_str(filename); 33 | if (!in_str) 34 | return false; 35 | int image_width, image_height; 36 | in_str >> image_width >> image_height; 37 | point_cloud.assign(image_width * image_height * 3, 0); 38 | for (int pixel = 0; pixel < image_width * image_height; pixel++) 39 | in_str >> point_cloud[pixel * 3 + 0] >> point_cloud[pixel * 3 + 1] >> point_cloud[pixel * 3 + 2]; 40 | in_str.close(); 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TRWSFusion.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__TRWSFusion__ 2 | #define __LayerDepthMap__TRWSFusion__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "DataStructure.h" 12 | #include "TRW_S/MRFEnergy.h" 13 | #include "Segment.h" 14 | 15 | using namespace std; 16 | 17 | class TRWSFusion 18 | { 19 | public: 20 | 21 | TRWSFusion(const cv::Mat &image, const vector &point_cloud, const vector &normals, const RepresenterPenalties &penalties, const DataStatistics &statistics, const bool consider_surface_cost = true); 22 | 23 | // Destructor 24 | ~TRWSFusion(); 25 | 26 | 27 | //find the best configuration in all proposals and use it to update the current solution 28 | vector fuse(const vector > &proposal_labels, const int proposal_num_surfaces, const int proposal_num_layers, const map &proposal_segments, const vector &previous_solution_indices, const vector &proposal_ROI_mask = vector()); 29 | 30 | //get information about optimization 31 | std::vector getEnergyInfo(); 32 | 33 | 34 | private: 35 | const int IMAGE_WIDTH_, IMAGE_HEIGHT_, NUM_PIXELS_; 36 | const cv::Mat image_; 37 | cv::Mat blurred_hsv_image_; 38 | const vector point_cloud_; 39 | const vector normals_; 40 | const RepresenterPenalties penalties_; 41 | const DataStatistics statistics_; 42 | const bool consider_surface_cost_; 43 | 44 | int proposal_num_surfaces_; 45 | int proposal_num_layers_; 46 | map proposal_segments_; 47 | map > proposal_surface_depths_; 48 | vector proposal_ROI_mask_; 49 | vector proposal_distance_to_boundaries_; 50 | 51 | 52 | double energy_; 53 | double lower_bound_; 54 | 55 | vector solution_; 56 | vector ori_labels_; 57 | 58 | 59 | double color_diff_var_; 60 | 61 | 62 | //calculate unary cost of a specific label a specific pixel 63 | double calcUnaryCost(const int pixel, const int label); 64 | 65 | //calculate pairwise cost 66 | double calcPairwiseCost(const int pixel_1, const int pixel_2, const int label_1, const int label_2); 67 | 68 | //check solution energy (mainly for debug purpose) 69 | double checkSolutionEnergy(const vector &solution_for_check); 70 | 71 | //calculate the variance of color difference 72 | void calcColorDiffVar(); 73 | 74 | //calculate color difference 75 | double calcColorDiff(const int pixel_1, const int pixel_2); 76 | 77 | //calculate overlap region after the viewpoint is moved to either left, right, up or down 78 | std::vector > > calcOverlapPixels(const vector > &proposal_labels); 79 | }; 80 | 81 | #endif /* defined(__LayerDepthMap__TRWSFusion__) */ 82 | -------------------------------------------------------------------------------- /cv_utils/CommonOperations.cpp: -------------------------------------------------------------------------------- 1 | #include "cv_utils.h" 2 | 3 | using namespace std; 4 | 5 | namespace cv_utils 6 | { 7 | std::vector findNeighbors(const int pixel, const int WIDTH, const int HEIGHT, const bool USE_PANORAMA, const int NEIGHBOR_SYSTEM) 8 | { 9 | int x = pixel % WIDTH; 10 | int y = pixel / WIDTH; 11 | std::vector neighbors; 12 | if (x > 0) 13 | neighbors.push_back(pixel - 1); 14 | if (x < WIDTH - 1) 15 | neighbors.push_back(pixel + 1); 16 | if (y > 0) 17 | neighbors.push_back(pixel - WIDTH); 18 | if (y < HEIGHT - 1) 19 | neighbors.push_back(pixel + WIDTH); 20 | 21 | if (USE_PANORAMA && x == 0) 22 | neighbors.push_back(pixel + (WIDTH - 1)); 23 | if (USE_PANORAMA && x == WIDTH - 1) 24 | neighbors.push_back(pixel - (WIDTH - 1)); 25 | 26 | if (NEIGHBOR_SYSTEM == 8) { 27 | if (x > 0 && y > 0) 28 | neighbors.push_back(pixel - 1 - WIDTH); 29 | if (x > 0 && y < HEIGHT - 1) 30 | neighbors.push_back(pixel - 1 + WIDTH); 31 | if (x < WIDTH - 1 && y > 0) 32 | neighbors.push_back(pixel + 1 - WIDTH); 33 | if (x < WIDTH - 1 && y < HEIGHT - 1) 34 | neighbors.push_back(pixel + 1 + WIDTH); 35 | 36 | if (USE_PANORAMA && x == 0) { 37 | if (y > 0) 38 | neighbors.push_back(pixel + (WIDTH - 1) - WIDTH); 39 | if (y < HEIGHT - 1) 40 | neighbors.push_back(pixel + (WIDTH - 1) + WIDTH); 41 | } 42 | if (USE_PANORAMA && x == WIDTH - 1) { 43 | if (y > 0) 44 | neighbors.push_back(pixel - (WIDTH - 1) - WIDTH); 45 | if (y < HEIGHT - 1) 46 | neighbors.push_back(pixel - (WIDTH - 1) + WIDTH); 47 | } 48 | } 49 | return neighbors; 50 | } 51 | 52 | std::vector > findNeighborsForAllPixels(const int WIDTH, const int HEIGHT, const int NEIGHBOR_SYSTEM) 53 | { 54 | vector > pixel_neighbors(WIDTH * HEIGHT); 55 | for (int pixel = 0; pixel < WIDTH * HEIGHT; pixel++) 56 | pixel_neighbors[pixel] = findNeighbors(pixel, WIDTH, HEIGHT, NEIGHBOR_SYSTEM); 57 | return pixel_neighbors; 58 | } 59 | 60 | std::vector findWindowPixels(const int pixel, const int WIDTH, const int HEIGHT, const int WINDOW_SIZE, const bool USE_PANORAMA) 61 | { 62 | vector window_pixels; 63 | int x = pixel % WIDTH; 64 | int y = pixel / WIDTH; 65 | for (int offset_x = -(WINDOW_SIZE - 1) / 2; offset_x <= (WINDOW_SIZE - 1) / 2; offset_x++) { 66 | for (int offset_y = -(WINDOW_SIZE - 1) / 2; offset_y <= (WINDOW_SIZE - 1) / 2; offset_y++) { 67 | if (x + offset_x >= 0 && x + offset_x < WIDTH && y + offset_y >= 0 && y + offset_y < HEIGHT) 68 | window_pixels.push_back((y + offset_y) * WIDTH + (x + offset_x)); 69 | if (USE_PANORAMA && (x + offset_x < 0 || x + offset_x >= WIDTH) && (y + offset_y >= 0 && y + offset_y < HEIGHT)) 70 | window_pixels.push_back((y + offset_y) * WIDTH + (x + offset_x + WIDTH) % WIDTH); 71 | } 72 | } 73 | return window_pixels; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | // utils.h 2 | // SurfaceStereo 3 | // 4 | // Created by Chen Liu on 9/30/14. 5 | // Copyright (c) 2014 Chen Liu. All rights reserved. 6 | // 7 | 8 | #ifndef SurfaceStereo_utils_h 9 | #define SurfaceStereo_utils_h 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include "Segment.h" 22 | 23 | 24 | using namespace std; 25 | using cv::Mat; 26 | using Eigen::MatrixXd; 27 | using Eigen::Matrix3d; 28 | using Eigen::VectorXd; 29 | using Eigen::Vector3d; 30 | 31 | 32 | //read point cloud from a .obj file 33 | vector readPointCloudFromObj(const string filename, const int image_width, const int image_height, const double rotation_angle); 34 | 35 | //save point cloud in a .ply file 36 | void savePointCloudAsPly(const cv::Mat &image, const vector &point_cloud, const char *filename); 37 | 38 | //save point cloud as a mesh in a .ply file 39 | void savePointCloudAsMesh(const vector &point_cloud, const char *filename); 40 | 41 | //load point cloud from a text file 42 | vector loadPointCloud(const string &filename); 43 | 44 | //save point cloud to a text file 45 | void savePointCloud(const vector &point_cloud, const char *filename); 46 | 47 | //draw a disp (inverse depth) image based on point cloud 48 | Mat drawDispImage(const vector &point_cloud, const int width, const MatrixXd &projection_matrix); 49 | 50 | //draw a disp (inverse depth) image based on point cloud 51 | Mat drawDispImage(const vector &point_cloud, const int width, const int height); 52 | 53 | //normalize point cloud on depth direction 54 | vector normalizePointCloudByZ(const vector &point_cloud); 55 | 56 | //zoom image and point cloud 57 | void zoomScene(Mat &image, vector &point_cloud, const double scale_x, const double scale_y); 58 | 59 | //crop image and point cloud 60 | void cropScene(Mat &image, vector &point_cloud, const int start_x, const int start_y, const int end_x, const int end_y); 61 | 62 | //inpaint empty point in a point cloud 63 | vector inpaintPointCloud(const vector &point_cloud, const int image_width, const int image_height); 64 | 65 | //read point cloud from a .ptx file 66 | bool readPtxFile(const string &filename, cv::Mat &image, vector &point_cloud, vector &camera_parameters); 67 | 68 | //unproject a pixel to 3D given depth 69 | vector unprojectPixel(const int pixel, const double depth, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const vector &CAMERA_PARAMETERS, const bool USE_PANORAMA); 70 | 71 | //project a 3D point to image domain 72 | int projectPoint(const vector &point, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const vector &CAMERA_PARAMETERS, const bool USE_PANORAMA); 73 | 74 | //calculate plane depth at pixel given plane parameters 75 | double calcPlaneDepthAtPixel(const vector &plane, const int pixel, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const vector &CAMERA_PARAMETERS, const bool USE_PANORAMA); 76 | 77 | //normalize values based on mean and svar 78 | double normalizeStatistically(const double value, const double mean, const double svar, const double normalized_value_for_mean, const double scale_factor); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /cv_utils/ImageMask.h: -------------------------------------------------------------------------------- 1 | #ifndef IMAGE_MASK_H__ 2 | #define IMAGE_MASK_H__ 3 | 4 | #include 5 | #include 6 | 7 | namespace cv_utils 8 | { 9 | class ImageMask 10 | { 11 | public: 12 | ImageMask(); 13 | ImageMask(const std::vector &mask, const int width, const int height); 14 | ImageMask(const bool value, const int width, const int height); 15 | ImageMask(const std::vector &pixels, const int width, const int height); 16 | ImageMask(const cv::Mat &image); 17 | 18 | ImageMask &operator = (const ImageMask &image_mask); 19 | 20 | // ImageMask clone(); 21 | 22 | void setMask(const std::vector &mask, const int width, const int height); 23 | 24 | void resize(const int new_width, const int new_height); 25 | void resizeByRatio(const double x_ratio, const double y_ratio); 26 | void resizeWithBias(const int new_width, const int new_height, const bool desired_value); 27 | 28 | void dilate(const int num_iterations = 1, const bool USE_PANORAMA = false, const int NEIGHBOR_SYSTEM = 8); 29 | void erode(const int num_iterations = 1, const bool USE_PANORAMA = false, const int NEIGHBOR_SYSTEM = 8); 30 | 31 | void smooth(const std::string type, const int window_size, const double sigma = 0); 32 | 33 | bool at(const int &pixel) const; 34 | void set(const int &pixel, const bool value); 35 | std::vector getPixels() const; 36 | int getNumPixels() const; 37 | std::vector getCenter() const; 38 | 39 | cv::Mat drawMaskImage(const int num_channels = 1) const; 40 | cv::Mat drawImageWithMask(const cv::Mat &image, const bool use_mask_color = true, const cv::Vec3b mask_color = cv::Vec3b(255, 255, 255), const bool use_outside_color = false, const cv::Vec3b outside_color = cv::Vec3b(0, 0, 0)) const; 41 | void readMaskImage(const cv::Mat &mask_image); 42 | 43 | std::vector calcDistanceMapOutside(const bool USE_PANORAMA = false, const int NEIGHBOR_SYSTEM = 8) const; 44 | std::vector calcDistanceMapInside(const bool USE_PANORAMA = false, const int NEIGHBOR_SYSTEM = 8) const; 45 | 46 | void calcBoundaryDistanceMap(std::vector &boundary_map, std::vector &distance_map, const bool USE_PANORAMA = false, const int NEIGHBOR_SYSTEM = 8) const; 47 | 48 | std::vector > findConnectedComponents(const bool USE_PANORAMA = false, const int NEIGHBOR_SYSTEM = 8); 49 | 50 | void printMask(); 51 | 52 | void addPixels(const std::vector &pixels); 53 | void subtractPixels(const std::vector &pixels); 54 | 55 | ImageMask &operator +=(const ImageMask &image_mask); 56 | ImageMask &operator -=(const ImageMask &image_mask); 57 | friend ImageMask operator +(const ImageMask &image_mask_1, const ImageMask &image_mask_2); 58 | friend ImageMask operator -(const ImageMask &image_mask_1, const ImageMask &image_mask_2); 59 | friend std::ostream & operator <<(std::ostream &out_str, const ImageMask &image_mask); 60 | friend std::istream & operator >>(std::istream &in_str, ImageMask &image_mask); 61 | 62 | std::vector findMaskWindowPixels(const int pixel, const int WINDOW_SIZE, const int USE_PANORAMA = false) const; 63 | 64 | private: 65 | std::vector mask_; 66 | int width_; 67 | int height_; 68 | }; 69 | } 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /LayerDepthRepresenter.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__LayerDepthRepresenter__ 2 | #define __LayerDepthMap__LayerDepthRepresenter__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | //#include "ProposalGenerator.h" 9 | #include "Segment.h" 10 | 11 | #include 12 | 13 | 14 | class LayerDepthRepresenter { 15 | 16 | public: 17 | LayerDepthRepresenter(const cv::Mat &image, const std::vector &point_cloud, const RepresenterPenalties &penalties, const DataStatistics &statistics, const cv::Mat &ori_image, const std::vector &ori_point_cloud, const int num_layers); 18 | 19 | ~LayerDepthRepresenter(); 20 | 21 | 22 | private: 23 | const cv::Mat image_; 24 | const cv::Mat ori_image_; 25 | const std::vector point_cloud_; 26 | const std::vector ori_point_cloud_; 27 | std::vector normals_; 28 | const int IMAGE_WIDTH_; 29 | const int IMAGE_HEIGHT_; 30 | const int NUM_PIXELS_; 31 | 32 | const RepresenterPenalties PENALTIES_; 33 | const DataStatistics STATISTICS_; 34 | 35 | 36 | std::map > surface_depths_; 37 | std::map surface_colors_; 38 | double max_depth_; 39 | 40 | // vector labels_; 41 | 42 | std::vector ROI_mask_; 43 | int num_surfaces_; 44 | int num_layers_; 45 | 46 | //unique_ptr proposal_generator_; 47 | 48 | std::vector > layers_; 49 | 50 | std::map > layer_surfaces_; 51 | std::map > layer_front_surfaces_; 52 | std::map > layer_back_surfaces_; 53 | 54 | std::vector camera_parameters_; 55 | 56 | double disp_image_numerator_; 57 | 58 | 59 | //optimize layer representation 60 | void optimizeLayerRepresentation(); 61 | 62 | //write rendering information 63 | void writeRenderingInfo(const std::vector &solution, const int solution_num_surfaces, const std::map &solution_segments); 64 | 65 | //generate a HTML page containing result images 66 | void generateLayerImageHTML(const std::map > &iteration_statistics_map, const std::map &iteration_proposal_type_map); 67 | 68 | //upsample results to original resolution 69 | void upsampleSolution(const std::vector &solution_labels, const int solution_num_surfaces, const std::map &solution_segments, std::vector &upsampled_solution_labels, int &upsampled_solution_num_surfaces, std::map &upsampled_solution_segments); 70 | }; 71 | 72 | //write intermediate results to cache 73 | void writeLayers(const cv::Mat &image, const int image_width, const int image_height, const std::vector &point_cloud, const std::vector &camera_parameters, const int num_layers, const std::vector &solution, const int solution_num_surfaces, const std::map &solution_segments, const int result_index, const cv::Mat &ori_image, const std::vector &ori_point_cloud); 74 | 75 | //read intermediate results from cache 76 | bool readLayers(const int image_width, const int image_height, const std::vector &camera_parameters, const RepresenterPenalties &penalties, const DataStatistics &statistics, const int num_layers, std::vector &solution, int &solution_num_surfaces, std::map &solution_segments, const int result_index); 77 | 78 | 79 | #endif /* defined(__LayerDepthMap__LayerDepthRepresenter__) */ 80 | -------------------------------------------------------------------------------- /cv_utils/StatisticsCalculations.cpp: -------------------------------------------------------------------------------- 1 | #include "cv_utils.h" 2 | 3 | using namespace std; 4 | 5 | 6 | namespace cv_utils 7 | { 8 | vector calcMeanAndSVar(const vector &values) 9 | { 10 | double sum = 0, sum2 = 0; 11 | for (std::vector::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) { 12 | sum += *value_it; 13 | sum2 += pow(*value_it, 2); 14 | } 15 | double mean = sum / values.size(); 16 | double svar = sqrt(sum2 / values.size() - pow(mean, 2)); 17 | vector mean_and_svar; 18 | mean_and_svar.push_back(mean); 19 | mean_and_svar.push_back(svar); 20 | return mean_and_svar; 21 | } 22 | 23 | void calcMeanAndSVar(const vector > &values, vector &mean, vector > &var) 24 | { 25 | assert(values.size() > 0); 26 | const int NUM_DIMENSIONS = values.begin()->size(); 27 | vector sums(NUM_DIMENSIONS, 0); 28 | vector > sum2s(NUM_DIMENSIONS, vector(NUM_DIMENSIONS, 0)); 29 | for (std::vector >::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) { 30 | for (std::vector::const_iterator c_it = value_it->begin(); c_it != value_it->end(); c_it++) { 31 | sums[c_it - value_it->begin()] += *c_it; 32 | for (std::vector::const_iterator d_it = value_it->begin(); d_it != value_it->end(); d_it++) 33 | sum2s[c_it - value_it->begin()][d_it - value_it->begin()] += *c_it * *d_it; 34 | } 35 | } 36 | mean.assign(NUM_DIMENSIONS, 0); 37 | for (int c = 0; c < NUM_DIMENSIONS; c++) 38 | mean[c] = sums[c] / values.size(); 39 | var.assign(NUM_DIMENSIONS, vector(NUM_DIMENSIONS)); 40 | for (int c = 0; c < NUM_DIMENSIONS; c++) 41 | for (int d = 0; d < NUM_DIMENSIONS; d++) 42 | var[c][d] = sum2s[c][d] / values.size() - mean[c] * mean[d]; 43 | } 44 | 45 | vector > findAllCombinations(const vector &candidates, const int num_elements) 46 | { 47 | if (num_elements == 0) 48 | return vector >(1, vector()); 49 | vector > combinations; 50 | int num_candidates = candidates.size(); 51 | if (num_candidates < num_elements) 52 | return combinations; 53 | 54 | vector selected_element_mask(num_candidates, false); 55 | for (int index = num_candidates - num_elements; index < num_candidates; index++) 56 | selected_element_mask[index] = true; 57 | while (true) { 58 | vector combination; 59 | for (int index = 0; index < num_candidates; index++) { 60 | if (selected_element_mask[index] == true) { 61 | combination.push_back(candidates[index]); 62 | } 63 | } 64 | combinations.push_back(combination); 65 | if (next_permutation(selected_element_mask.begin(), selected_element_mask.end()) == false) 66 | break; 67 | } 68 | return combinations; 69 | 70 | for (int configuration = 0; configuration < pow(2, num_candidates); configuration++) { 71 | vector selected_element_mask(num_candidates, false); 72 | int num_selected_elements = 0; 73 | int configuration_temp = configuration; 74 | for (int j = 0; j < num_candidates; j++) { 75 | if (configuration_temp % 2 == 1) { 76 | selected_element_mask[j] = true; 77 | num_selected_elements++; 78 | if (num_selected_elements > num_elements) 79 | break; 80 | } 81 | configuration_temp /= 2; 82 | } 83 | if (num_selected_elements != num_elements) 84 | continue; 85 | vector combination; 86 | for (int j = 0; j < num_candidates; j++) 87 | if (selected_element_mask[j] == true) 88 | combination.push_back(candidates[j]); 89 | combinations.push_back(combination); 90 | } 91 | return combinations; 92 | } 93 | 94 | int calcNumDistinctValues(const vector &values) 95 | { 96 | vector sorted_values = values; 97 | sort(sorted_values.begin(), sorted_values.end()); 98 | vector::iterator unique_end = unique(sorted_values.begin(), sorted_values.end()); 99 | return distance(sorted_values.begin(), unique_end); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #include "LayerDepthRepresenter.h" 13 | #include "utils.h" 14 | #include "TRW_S/MRFEnergy.h" 15 | 16 | 17 | using namespace std; 18 | using namespace cv; 19 | 20 | DEFINE_string(image_path, "", "The path to the RGB image."); 21 | //Point cloud format: 22 | //The first number indicates the number equals to image_width * image_height. 23 | //Each row stores a 3D point for each pixel (ordered by y * image_width + x). 24 | DEFINE_string(point_cloud_path, "", "The path to the point cloud."); 25 | DEFINE_int32(num_layers, 4, "The number of layers."); 26 | 27 | 28 | int main(int argc, char* argv[]) { 29 | 30 | google::ParseCommandLineFlags(&argc, &argv, true); 31 | 32 | srand(time(0)); 33 | 34 | Mat ori_image = imread(FLAGS_image_path, 1); 35 | assert(ori_image); 36 | vector ori_point_cloud = loadPointCloud(FLAGS_point_cloud_path); 37 | assert(ori_point_cloud.size() == ori_image.cols * ori_image.rows * 3); 38 | 39 | double zoom_scale = min(200.0 / max(ori_image.cols, ori_image.rows), 1.0); 40 | Mat image = ori_image.clone(); 41 | vector point_cloud = ori_point_cloud; 42 | zoomScene(image, point_cloud, zoom_scale, zoom_scale); 43 | 44 | 45 | RepresenterPenalties penalties; 46 | 47 | penalties.data_depth_pen = 2000; //data cost for depth difference 48 | penalties.data_normal_pen = 200; //data cost for color difference 49 | penalties.data_color_pen = 10; //data cost for normal difference 50 | penalties.data_non_plane_pen = 100; //parameter in data cost 51 | 52 | 53 | penalties.smoothness_pen = 10000; //smoothness cost for depth change 54 | penalties.smoothness_small_constant_pen = 1; //small constant smoothness cost for smooth boundary (with label changes) 55 | penalties.smoothness_concave_shape_pen = 5000; //smoothness cost for concave shape 56 | penalties.smoothness_anisotropic_diffusion_pen = 500; //smoothness cost based on color difference (anisotropic diffusion) 57 | 58 | penalties.other_viewpoint_smoothness_pen = 2000; //smoothness cost for neighboring pixels from other viewpoint 59 | penalties.other_viewpoint_depth_conflict_pen = 200000; //depth conflict penalty for different layers at the same pixel from other viewpoint 60 | 61 | penalties.surface_pen = 20000; //label cost for the occurrence of a surface 62 | 63 | penalties.smoothness_empty_non_empty_ratio = 0.05; //the ratio of smoothness cost between a empty pixel and a non-empty pixel over the smoothness cost for a depth change of statistics.depth_change_smoothness_threshold 64 | 65 | penalties.huge_pen = 1000000; //a huge penalty for cases with conflicts 66 | 67 | 68 | DataStatistics statistics; 69 | 70 | statistics.pixel_fitting_distance_threshold = 0.03; //the 3D distance threshold when fitting a surface model 71 | statistics.pixel_fitting_angle_threshold = 30 * M_PI / 180; //the angle threshold when fitting a surface model 72 | statistics.pixel_fitting_color_likelihood_threshold = -20; //the color likelihood threshold when fitting a surface model 73 | statistics.depth_diff_var = 0.01; //the variance of depth difference for unary cost calculation 74 | statistics.similar_angle_threshold = 20 * M_PI / 180; //the angle threshold for two vectors to be regarded as parallel or vertical 75 | 76 | statistics.viewpoint_movement = 0.1; //the amount of viewpoint movement for parallex term calculation 77 | 78 | statistics.depth_conflict_tolerance = 0.03; //the tolerance for depth conflict between two layers at the same pixel 79 | statistics.depth_change_smoothness_threshold = 0.02; //depth change threshold for two surfaces to be regarded as smooth at the intersection 80 | statistics.bspline_surface_num_pixels_threshold = image.cols * image.rows / 50; //the number pixels allowed to appear in a b-spline surface 81 | statistics.background_depth_diff_tolerance = 0.05; //small amount of depth difference allowed without penalty in the background layer 82 | 83 | LayerDepthRepresenter representer(image, point_cloud, penalties, statistics, ori_image, ori_point_cloud, FLAGS_num_layers); 84 | } 85 | -------------------------------------------------------------------------------- /TRW_S/ordering.def: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "MRFEnergy.h" 6 | 7 | //#include "instances.inc" 8 | 9 | template void MRFEnergy::SetAutomaticOrdering() 10 | { 11 | int dMin; 12 | Node* i; 13 | Node* iMin; 14 | Node* list; 15 | Node* listBoundary; 16 | MRFEdge* e; 17 | 18 | if (m_isEnergyConstructionCompleted) 19 | { 20 | m_errorFn("Error in SetAutomaticOrdering(): function cannot be called after graph construction is completed"); 21 | } 22 | 23 | printf("Setting automatic ordering... "); 24 | 25 | list = m_nodeFirst; 26 | listBoundary = NULL; 27 | m_nodeFirst = m_nodeLast = NULL; 28 | for (i=list; i; i=i->m_next) 29 | { 30 | i->m_ordering = 2*m_nodeNum; // will contain remaining degree mod m_nodeNum (i.e. number of edges connecting to nodes in 'listBoundary' and 'list') 31 | // if i->m_ordering \in [2*m_nodeNum; 3*m_nodeNum) - not assigned yet, belongs to 'list' 32 | // if i->m_ordering \in [m_nodeNum; 2*m_nodeNum) - not assigned yet, belongs to 'listBoundary' 33 | // if i->m_ordering \in [0; m_nodeNum ) - assigned, belongs to 'm_nodeFirst' 34 | for (e=i->m_firstForward; e; e=e->m_nextForward) 35 | { 36 | i->m_ordering ++; 37 | } 38 | for (e=i->m_firstBackward; e; e=e->m_nextBackward) 39 | { 40 | i->m_ordering ++; 41 | } 42 | } 43 | 44 | while (list) 45 | { 46 | // find node with the smallest remaining degree in list 47 | dMin = m_nodeNum; 48 | for (i=list; i; i=i->m_next) 49 | { 50 | assert(i->m_ordering >= 2*m_nodeNum); 51 | if (dMin > i->m_ordering - 2*m_nodeNum) 52 | { 53 | dMin = i->m_ordering - 2*m_nodeNum; 54 | iMin = i; 55 | } 56 | } 57 | i = iMin; 58 | 59 | // remove i from list 60 | if (i->m_prev) i->m_prev->m_next = i->m_next; 61 | else list = i->m_next; 62 | if (i->m_next) i->m_next->m_prev = i->m_prev; 63 | 64 | // add i to listBoundary 65 | listBoundary = i; 66 | i->m_prev = NULL; 67 | i->m_next = NULL; 68 | i->m_ordering -= m_nodeNum; 69 | 70 | while (listBoundary) 71 | { 72 | // find node with the smallest remaining degree in listBoundary 73 | dMin = m_nodeNum; 74 | for (i=listBoundary; i; i=i->m_next) 75 | { 76 | assert(i->m_ordering >= m_nodeNum && i->m_ordering < 2*m_nodeNum); 77 | if (dMin > i->m_ordering - m_nodeNum) 78 | { 79 | dMin = i->m_ordering - m_nodeNum; 80 | iMin = i; 81 | } 82 | } 83 | i = iMin; 84 | 85 | // remove i from listBoundary 86 | if (i->m_prev) i->m_prev->m_next = i->m_next; 87 | else listBoundary = i->m_next; 88 | if (i->m_next) i->m_next->m_prev = i->m_prev; 89 | 90 | // add i to m_nodeFirst 91 | if (m_nodeLast) 92 | { 93 | m_nodeLast->m_next = i; 94 | i->m_ordering = m_nodeLast->m_ordering + 1; 95 | } 96 | else 97 | { 98 | m_nodeFirst = i; 99 | i->m_ordering = 0; 100 | } 101 | i->m_prev = m_nodeLast; 102 | m_nodeLast = i; 103 | i->m_next = NULL; 104 | 105 | // process neighbors of i=m_nodeLast: decrease their remaining degree, 106 | // put them into listBoundary (if they are in list) 107 | for (e=m_nodeLast->m_firstForward; e; e=e->m_nextForward) 108 | { 109 | assert(m_nodeLast == e->m_tail); 110 | i = e->m_head; 111 | if (i->m_ordering >= m_nodeNum) 112 | { 113 | i->m_ordering --; // decrease remaining degree of i 114 | if (i->m_ordering >= 2*m_nodeNum) 115 | { 116 | // remove i from list 117 | if (i->m_prev) i->m_prev->m_next = i->m_next; 118 | else list = i->m_next; 119 | if (i->m_next) i->m_next->m_prev = i->m_prev; 120 | 121 | // add i to listBoundary 122 | if (listBoundary) listBoundary->m_prev = i; 123 | i->m_prev = NULL; 124 | i->m_next = listBoundary; 125 | listBoundary = i; 126 | i->m_ordering -= m_nodeNum; 127 | } 128 | } 129 | } 130 | for (e=m_nodeLast->m_firstBackward; e; e=e->m_nextBackward) 131 | { 132 | assert(m_nodeLast == e->m_head); 133 | i = e->m_tail; 134 | if (i->m_ordering >= m_nodeNum) 135 | { 136 | i->m_ordering --; // decrease remaining degree of i 137 | if (i->m_ordering >= 2*m_nodeNum) 138 | { 139 | // remove i from list 140 | if (i->m_prev) i->m_prev->m_next = i->m_next; 141 | else list = i->m_next; 142 | if (i->m_next) i->m_next->m_prev = i->m_prev; 143 | 144 | // add i to listBoundary 145 | if (listBoundary) listBoundary->m_prev = i; 146 | i->m_prev = NULL; 147 | i->m_next = listBoundary; 148 | listBoundary = i; 149 | i->m_ordering -= m_nodeNum; 150 | } 151 | } 152 | } 153 | } 154 | } 155 | 156 | printf("done\n"); 157 | 158 | CompleteGraphConstruction(); 159 | } 160 | -------------------------------------------------------------------------------- /ProposalDesigner.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__ProposalDesigner__ 2 | #define __LayerDepthMap__ProposalDesigner__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //#include "LayerInpainter.h" 12 | //#include "GraphRepresenter.h" 13 | //#include "LayerEstimator.h" 14 | #include "Segment.h" 15 | 16 | //using namespace cv; 17 | //using namespace Eigen; 18 | using Eigen::MatrixXd; 19 | using Eigen::Matrix3d; 20 | using Eigen::VectorXd; 21 | using Eigen::Vector3d; 22 | 23 | 24 | struct MeanshiftParams { 25 | double spatial_bandwidth; 26 | double range_bandwidth; 27 | int minimum_regions_area; 28 | }; 29 | 30 | const std::string EDISON_PATH = "edison"; 31 | const std::string EDISON_EXE = "edison/edison edison/config.txt"; 32 | 33 | class ProposalDesigner{ 34 | 35 | public: 36 | ProposalDesigner(const cv::Mat &image, const std::vector &point_cloud, const std::vector &normals, const std::vector &camera_parameters, const int num_layers, const RepresenterPenalties penalties, const DataStatistics statistics); 37 | 38 | ~ProposalDesigner(); 39 | 40 | //generate a proposal and return 41 | bool getProposal(int &iteration, std::vector > &proposal_labels, int &proposal_num_surfaces, std::map &proposal_segments, std::string &proposal_type); 42 | 43 | //set current solution which might be used to generate new proposals 44 | void setCurrentSolution(const std::vector ¤t_solution_labels, const int current_solution_num_surfaces, const std::map ¤t_solution_segments); 45 | 46 | //initialize current solution which might be used to generate new proposals 47 | void initializeCurrentSolution(); 48 | 49 | //get the indices (pixel-wise) of the current solution inside all proposals 50 | std::vector getCurrentSolutionIndices(); 51 | 52 | 53 | private: 54 | const cv::Mat image_; 55 | const std::vector point_cloud_; 56 | const std::vector normals_; 57 | const Eigen::MatrixXd projection_matrix_; 58 | const int IMAGE_WIDTH_; 59 | const int IMAGE_HEIGHT_; 60 | const std::vector CAMERA_PARAMETERS_; 61 | const RepresenterPenalties penalties_; 62 | const DataStatistics statistics_; 63 | 64 | cv::Mat blurred_hsv_image_; 65 | 66 | std::vector ROI_mask_; 67 | int NUM_LAYERS_; 68 | const int NUM_PIXELS_; 69 | 70 | std::vector current_solution_labels_; 71 | int current_solution_num_surfaces_; 72 | std::map current_solution_segments_; 73 | 74 | std::vector > proposal_labels_; 75 | int proposal_num_surfaces_; 76 | std::map proposal_segments_; 77 | std::string proposal_type_; 78 | 79 | int num_confident_segments_threshold_; 80 | double segment_confidence_threshold_; 81 | 82 | 83 | std::vector > segmentations_; 84 | 85 | std::set > used_confident_segment_layer_maps_; 86 | 87 | std::vector current_solution_indices_; 88 | 89 | std::vector single_surface_candidate_pixels_; 90 | 91 | std::vector proposal_type_indices_; 92 | int proposal_type_index_ptr_; 93 | int all_proposal_iteration_; 94 | const int NUM_ALL_PROPOSAL_ITERATIONS_; 95 | 96 | //generate segment refitting proposal 97 | bool generateSegmentRefittingProposal(); 98 | 99 | //generate single surface expansion proposal (provide segment_id to expand specific segment) 100 | bool generateSingleSurfaceExpansionProposal(const int segment_id = -1); 101 | 102 | //generate single surface expansion proposal 103 | bool generateLayerSwapProposal(); 104 | 105 | //generate concave hull proposal 106 | bool generateConcaveHullProposal(const bool consider_background = true); 107 | 108 | //generate segment adding proposal 109 | bool generateSegmentAddingProposal(const int denoted_segment_adding_type = -1); 110 | 111 | //generate structure expansion proposal 112 | bool generateStructureExpansionProposal(const int layer_index = -1, const int pixel = -1); 113 | 114 | //generate backward merging proposal 115 | bool generateBackwardMergingProposal(const int denoted_target_layer_index = -1); 116 | 117 | //generate desired proposal (for debug) 118 | bool generateDesiredProposal(); 119 | 120 | //generate a proposal identical with current solution (for debug) 121 | bool generateSingleProposal(); 122 | 123 | //calculate possible proposals for a pixel given which surfaces will appear in which layers 124 | std::vector calcPixelProposals(const int num_surfaces, const std::map > &pixel_layer_surfaces_map); 125 | 126 | //add surface indicator variables (for formulating label cost) 127 | void addIndicatorVariables(const int num_indicator_variables = -1); 128 | 129 | //check the validity of a label 130 | bool checkLabelValidity(const int pixel, const int label, const int num_surfaces, const std::map &segments); 131 | 132 | //convert a current solution label to a proposal label 133 | int convertToProposalLabel(const int current_solution_label); 134 | }; 135 | 136 | 137 | #endif /* defined(__LayerDepthMap__ProposalDesigner__) */ 138 | -------------------------------------------------------------------------------- /Segment.h: -------------------------------------------------------------------------------- 1 | #ifndef __LayerDepthMap__Segment__ 2 | #define __LayerDepthMap__Segment__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "DataStructure.h" 13 | //#include "BSpline.h" 14 | 15 | 16 | class Segment{ 17 | 18 | public: 19 | Segment(const cv::Mat &image, const std::vector &point_cloud, const std::vector &normals, const std::vector &camera_parameters, const std::vector &pixels, const RepresenterPenalties &penalties, const DataStatistics &input_statistics = DataStatistics(), const int segment_type = 0); 20 | Segment(const int image_width, const int image_height, const std::vector &camera_parameters, const RepresenterPenalties &penalties, const DataStatistics &statistics); 21 | //Segment(const Segment &segment); 22 | Segment(); 23 | 24 | //~Segment(); 25 | 26 | //write segment to file 27 | friend std::ostream & operator <<(std::ostream &out_str, const Segment &segment); 28 | 29 | //read segment from file 30 | friend std::istream & operator >>(std::istream &in_str, Segment &segment); 31 | 32 | //segment assignment 33 | Segment &operator = (const Segment &segment); 34 | 35 | 36 | //predict color likelihood based on the GMM model 37 | double predictColorLikelihood(const int pixel, const cv::Vec3f hsv_color) const; 38 | 39 | //set GMM model based on saved file. 40 | void setGMM(const cv::FileNode GMM_file_node); 41 | 42 | //get GMM model in order to save to file. 43 | cv::Ptr getGMM() const; 44 | 45 | //get depth map 46 | std::vector getDepthMap() const; 47 | 48 | //get depth at specific pixel 49 | double getDepth(const int pixel) const; 50 | 51 | //get depth at pixel specified by ratios 52 | double getDepth(const double x_ratio, const double y_ratio) const; 53 | 54 | //get plane parameters 55 | std::vector getDepthPlane() const; 56 | 57 | //get segment pixels 58 | std::vector getSegmentPixels() const; 59 | 60 | //get segment type 61 | int getType() const; 62 | 63 | //check whether the segment fits the specific pixel or not 64 | bool checkPixelFitting(const cv::Mat &hsv_image, const std::vector &point_cloud, const std::vector &normals, const int pixel) const; 65 | 66 | //calculate the angle between normals of the input visible surface and the segment 67 | double calcAngle(const std::vector &normals, const int pixel); 68 | 69 | //calculate the difference of the distance between two pixels and the segment. 70 | int calcDistanceOffset(const int pixel_1, const int pixel_2); 71 | 72 | //bool buildSubSegment(const cv::Mat &image, const std::vector &point_cloud, const std::vector &normals, const std::vector &visible_pixels); 73 | 74 | //project the segmnet to different viewpoints 75 | std::vector projectToOtherViewpoints(const int pixel, const double viewpoint_movement); 76 | 77 | //get the segment type 78 | int getSegmentType() const; 79 | 80 | //calculate 3D distance between the 3D point at specific pixel and the segment 81 | double calcDistance(const std::vector &point_cloud, const int pixel); 82 | 83 | 84 | private: 85 | int IMAGE_WIDTH_; 86 | int IMAGE_HEIGHT_; 87 | 88 | int NUM_PIXELS_; 89 | std::vector CAMERA_PARAMETERS_; 90 | 91 | 92 | RepresenterPenalties penalties_; 93 | DataStatistics input_statistics_; 94 | 95 | std::vector segment_pixels_; 96 | std::vector disp_plane_; 97 | std::vector depth_plane_; 98 | std::vector depth_map_; 99 | std::vector normals_; 100 | 101 | int segment_type_; 102 | 103 | cv::Ptr GMM_; 104 | 105 | double segment_confidence_; 106 | 107 | std::vector segment_mask_; 108 | double segment_radius_; 109 | double segment_center_x_; 110 | double segment_center_y_; 111 | 112 | std::vector distance_map_; 113 | 114 | 115 | //fit a plane segment 116 | void fitDepthPlane(const cv::Mat &image, const std::vector &point_cloud, const std::vector &normals, const std::vector &pixels); 117 | 118 | //fit a b-spline segment 119 | void fitBSplineSurface(const cv::Mat &image, const std::vector &point_cloud, const std::vector &normals, const std::vector &pixels); 120 | 121 | //fit a plane segment which is parallel to the image plane 122 | void fitParallelSurface(const std::vector &point_cloud, const std::vector &normals, const std::vector &pixels); 123 | 124 | //calculate depth map for this segment 125 | void calcDepthMap(const std::vector &point_cloud = std::vector(), const std::vector &fitted_pixels = std::vector()); 126 | 127 | //calculate color statistics for this segment 128 | void calcColorStatistics(const cv::Mat &image, const std::vector &pixels); 129 | 130 | //calculate mask info for this segment 131 | void calcSegmentMaskInfo(); 132 | 133 | //the distance map stores the distance between any pixel and the segment on image domain 134 | void calcDistanceMap(); 135 | 136 | //find largest connected component 137 | std::vector findLargestConnectedComponent(const std::vector &point_cloud, const std::vector &pixels); 138 | 139 | //calculate point cloud map for this segment. 140 | std::vector calcPointCloud(); 141 | 142 | //delete invalid pixels which have no depth values 143 | std::vector deleteInvalidPixels(const std::vector &point_cloud, const std::vector &pixels); 144 | }; 145 | 146 | #endif /* defined(__LayerDepthMap__Segment__) */ 147 | -------------------------------------------------------------------------------- /cv_utils/FusionSpaceSolver.cpp: -------------------------------------------------------------------------------- 1 | #include "FusionSpaceSolver.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "TRW_S/MRFEnergy.h" 9 | 10 | using namespace std; 11 | 12 | FusionSpaceSolver::FusionSpaceSolver(const int NUM_NODES, const std::vector > &node_neighbors, CostFunctor &cost_functor, ProposalGenerator &proposal_generator, const int NUM_ITERATIONS, const bool CONSIDER_LABEL_COST) : NUM_NODES_(NUM_NODES), node_neighbors_(node_neighbors), cost_functor_(cost_functor), proposal_generator_(proposal_generator), NUM_ITERATIONS_(NUM_ITERATIONS), CONSIDER_LABEL_COST_(CONSIDER_LABEL_COST) 13 | { 14 | } 15 | 16 | vector FusionSpaceSolver::fuse(const std::vector > &node_labels, std::vector &energy_info) 17 | { 18 | cout << "fuse" << endl; 19 | 20 | unique_ptr > energy(new MRFEnergy(TypeGeneral::GlobalSize())); 21 | map label_indicator_index_map; 22 | if (CONSIDER_LABEL_COST_) { 23 | int label_indicator_index = NUM_NODES_; 24 | for (vector >::const_iterator node_it = node_labels.begin(); node_it != node_labels.end(); node_it++) 25 | for (vector::const_iterator label_it = node_it->begin(); label_it != node_it->end(); label_it++) 26 | if (label_indicator_index_map.count(*label_it) == 0) 27 | label_indicator_index_map[*label_it] = label_indicator_index++; 28 | } 29 | int NUM_LABEL_INDICATORS = label_indicator_index_map.size(); 30 | vector::NodeId> nodes(NUM_NODES_ + NUM_LABEL_INDICATORS); 31 | 32 | //add unary cost 33 | for (int node_index = 0; node_index < NUM_NODES_; node_index++) { 34 | vector labels = node_labels[node_index]; 35 | const int NUM_LABELS = labels.size(); 36 | if (NUM_LABELS == 0) { 37 | cout << "empty proposal error: " << node_index << endl; 38 | exit(1); 39 | } 40 | vector unary_cost(NUM_LABELS); 41 | for (int label_index = 0; label_index < NUM_LABELS; label_index++) 42 | unary_cost[label_index] = cost_functor_(node_index, labels[label_index]); 43 | nodes[node_index] = energy->AddNode(TypeGeneral::LocalSize(NUM_LABELS), TypeGeneral::NodeData(&unary_cost[0])); 44 | } 45 | 46 | //add label indicator cost 47 | if (CONSIDER_LABEL_COST_ == true) { 48 | for (int label_indicator_index = 0; label_indicator_index < NUM_LABEL_INDICATORS; label_indicator_index++) { 49 | vector label_cost(2, 0); 50 | label_cost[1] = cost_functor_.getLabelCost(); 51 | nodes[label_indicator_index + NUM_NODES_] = energy->AddNode(TypeGeneral::LocalSize(2), TypeGeneral::NodeData(&label_cost[0])); 52 | } 53 | } 54 | 55 | //add pairwise cost 56 | for (int node_index = 0; node_index < NUM_NODES_; node_index++) { 57 | vector labels = node_labels[node_index]; 58 | vector neighbors = node_neighbors_[node_index]; 59 | for (vector::const_iterator neighbor_it = neighbors.begin(); neighbor_it != neighbors.end(); neighbor_it++) { 60 | vector neighbor_labels = node_labels[*neighbor_it]; 61 | vector pairwise_cost(labels.size() * neighbor_labels.size(), 0); 62 | for (int label_index = 0; label_index < labels.size(); label_index++) 63 | for (int neighbor_label_index = 0; neighbor_label_index < neighbor_labels.size(); neighbor_label_index++) 64 | pairwise_cost[label_index + neighbor_label_index * labels.size()] = cost_functor_(node_index, *neighbor_it, labels[label_index], neighbor_labels[neighbor_label_index]); 65 | bool has_non_zero_cost = false; 66 | for (int i = 0; i < pairwise_cost.size(); i++) 67 | if (pairwise_cost[i] > 0) 68 | has_non_zero_cost = true; 69 | if (has_non_zero_cost == true) 70 | energy->AddEdge(nodes[node_index], nodes[*neighbor_it], TypeGeneral::EdgeData(TypeGeneral::GENERAL, &pairwise_cost[0])); 71 | } 72 | } 73 | 74 | //add label indicator constraints 75 | if (CONSIDER_LABEL_COST_) { 76 | for (int node_index = 0; node_index < NUM_NODES_; node_index++) { 77 | vector labels = node_labels[node_index]; 78 | for (int label_index = 0; label_index < labels.size(); label_index++) { 79 | int label = labels[label_index]; 80 | int label_indicator_index = label_indicator_index_map[label]; 81 | vector label_indicator_conflict_cost(labels.size() * 2, 0); 82 | label_indicator_conflict_cost[label_index] = cost_functor_.getLabelIndicatorConflictCost(); 83 | 84 | energy->AddEdge(nodes[node_index], nodes[label_indicator_index + NUM_NODES_], TypeGeneral::EdgeData(TypeGeneral::GENERAL, &label_indicator_conflict_cost[0])); 85 | } 86 | } 87 | } 88 | 89 | MRFEnergy::Options options; 90 | options.m_iterMax = NUM_ITERATIONS_; 91 | options.m_printIter = NUM_ITERATIONS_ / 5; 92 | options.m_printMinIter = 0; 93 | options.m_eps = 0.1; 94 | 95 | double lower_bound, solution_energy; 96 | energy->Minimize_TRW_S(options, lower_bound, solution_energy); 97 | 98 | vector fused_labels(NUM_NODES_); 99 | for (int node_index = 0; node_index < NUM_NODES_; node_index++) { 100 | int label = energy->GetSolution(nodes[node_index]); 101 | fused_labels[node_index] = node_labels[node_index][label]; 102 | } 103 | energy_info.assign(2, 0); 104 | energy_info[0] = solution_energy; 105 | energy_info[1] = lower_bound; 106 | return fused_labels; 107 | } 108 | 109 | vector FusionSpaceSolver::solve(const int NUM_ITERATIONS, const vector &initial_solution) 110 | { 111 | vector current_solution = initial_solution; 112 | double current_solution_energy = numeric_limits::max(); 113 | proposal_generator_.setCurrentSolution(current_solution); 114 | cost_functor_.setCurrentSolution(current_solution); 115 | 116 | for (int iteration = 0; iteration < NUM_ITERATIONS; iteration++) { 117 | vector > pixel_labels = proposal_generator_.getProposal(); 118 | vector energy_info; 119 | vector solution = fuse(pixel_labels, energy_info); 120 | if (energy_info[0] >= current_solution_energy) 121 | continue; 122 | current_solution = solution; 123 | current_solution_energy = energy_info[0]; 124 | if (iteration < NUM_ITERATIONS - 1) { 125 | proposal_generator_.setCurrentSolution(current_solution); 126 | cost_functor_.setCurrentSolution(current_solution); 127 | } 128 | } 129 | return current_solution; 130 | } 131 | 132 | -------------------------------------------------------------------------------- /TRW_S/MRFEnergy.def: -------------------------------------------------------------------------------- 1 | template MRFEnergy::MRFEnergy(GlobalSize Kglobal, ErrorFunction errorFn) 2 | : m_errorFn(errorFn ? errorFn : DefaultErrorFn), 3 | m_mallocBlockFirst(NULL), 4 | m_nodeFirst(NULL), 5 | m_nodeLast(NULL), 6 | m_nodeNum(0), 7 | m_edgeNum(0), 8 | m_Kglobal(Kglobal), 9 | m_vectorMaxSizeInBytes(0), 10 | m_isEnergyConstructionCompleted(false), 11 | m_buf(NULL) 12 | { 13 | } 14 | 15 | template MRFEnergy::~MRFEnergy() 16 | { 17 | while (m_mallocBlockFirst) 18 | { 19 | MallocBlock* next = m_mallocBlockFirst->m_next; 20 | delete m_mallocBlockFirst; 21 | m_mallocBlockFirst = next; 22 | } 23 | } 24 | 25 | template typename MRFEnergy::NodeId MRFEnergy::AddNode(LocalSize K, NodeData data) 26 | { 27 | if (m_isEnergyConstructionCompleted) 28 | { 29 | m_errorFn("Error in AddNode(): graph construction completed - nodes cannot be added"); 30 | } 31 | 32 | int actualVectorSize = Vector::GetSizeInBytes(m_Kglobal, K); 33 | if (actualVectorSize < 0) 34 | { 35 | m_errorFn("Error in AddNode() (invalid parameter?)"); 36 | } 37 | if (m_vectorMaxSizeInBytes < actualVectorSize) 38 | { 39 | m_vectorMaxSizeInBytes = actualVectorSize; 40 | } 41 | int nodeSize = sizeof(Node) - sizeof(Vector) + actualVectorSize; 42 | Node* i = (Node *) Malloc(nodeSize); 43 | 44 | i->m_K = K; 45 | i->m_D.Initialize(m_Kglobal, K, data); 46 | 47 | i->m_firstForward = NULL; 48 | i->m_firstBackward = NULL; 49 | i->m_prev = m_nodeLast; 50 | if (m_nodeLast) 51 | { 52 | m_nodeLast->m_next = i; 53 | } 54 | else 55 | { 56 | m_nodeFirst = i; 57 | } 58 | m_nodeLast = i; 59 | i->m_next = NULL; 60 | 61 | i->m_ordering = m_nodeNum ++; 62 | return i; 63 | } 64 | 65 | template void MRFEnergy::AddNodeData(NodeId i, NodeData data) 66 | { 67 | i->m_D.Add(m_Kglobal, i->m_K, data); 68 | } 69 | 70 | template void MRFEnergy::AddEdge(NodeId i, NodeId j, EdgeData data) 71 | { 72 | if (m_isEnergyConstructionCompleted) 73 | { 74 | m_errorFn("Error in AddNode(): graph construction completed - nodes cannot be added"); 75 | } 76 | 77 | MRFEdge* e; 78 | 79 | int actualEdgeSize = Edge::GetSizeInBytes(m_Kglobal, i->m_K, j->m_K, data); 80 | if (actualEdgeSize < 0) 81 | { 82 | m_errorFn("Error in AddEdge() (invalid parameter?)"); 83 | } 84 | int MRFedgeSize = sizeof(MRFEdge) - sizeof(Edge) + actualEdgeSize; 85 | e = (MRFEdge*) Malloc(MRFedgeSize); 86 | 87 | e->m_message.Initialize(m_Kglobal, i->m_K, j->m_K, data, &i->m_D, &j->m_D); 88 | 89 | e->m_tail = i; 90 | e->m_nextForward = i->m_firstForward; 91 | i->m_firstForward = e; 92 | 93 | e->m_head = j; 94 | e->m_nextBackward = j->m_firstBackward; 95 | j->m_firstBackward = e; 96 | 97 | m_edgeNum ++; 98 | } 99 | 100 | ///////////////////////////////////////////////////////////////////////////////// 101 | 102 | template void MRFEnergy::ZeroMessages() 103 | { 104 | Node* i; 105 | MRFEdge* e; 106 | 107 | if (!m_isEnergyConstructionCompleted) 108 | { 109 | CompleteGraphConstruction(); 110 | } 111 | 112 | for (i=m_nodeFirst; i; i=i->m_next) 113 | { 114 | for (e=i->m_firstForward; e; e=e->m_nextForward) 115 | { 116 | e->m_message.GetMessagePtr()->SetZero(m_Kglobal, i->m_K); 117 | } 118 | } 119 | } 120 | 121 | template void MRFEnergy::AddRandomMessages(unsigned int random_seed, REAL min_value, REAL max_value) 122 | { 123 | Node* i; 124 | MRFEdge* e; 125 | int k; 126 | 127 | if (!m_isEnergyConstructionCompleted) 128 | { 129 | CompleteGraphConstruction(); 130 | } 131 | 132 | srand(random_seed); 133 | 134 | for (i=m_nodeFirst; i; i=i->m_next) 135 | { 136 | for (e=i->m_firstForward; e; e=e->m_nextForward) 137 | { 138 | Vector* M = e->m_message.GetMessagePtr(); 139 | for (k=0; kGetArraySize(m_Kglobal, i->m_K); k++) 140 | { 141 | REAL x = (REAL)( min_value + rand()/((double)RAND_MAX) * (max_value - min_value) ); 142 | x += M->GetArrayValue(m_Kglobal, i->m_K, k); 143 | M->SetArrayValue(m_Kglobal, i->m_K, k, x); 144 | } 145 | } 146 | } 147 | } 148 | 149 | ///////////////////////////////////////////////////////////////////////////////// 150 | 151 | template void MRFEnergy::CompleteGraphConstruction() 152 | { 153 | Node* i; 154 | Node* j; 155 | MRFEdge* e; 156 | MRFEdge* ePrev; 157 | 158 | if (m_isEnergyConstructionCompleted) 159 | { 160 | m_errorFn("Fatal error in CompleteGraphConstruction"); 161 | } 162 | 163 | printf("Completing graph construction... "); 164 | 165 | if (m_buf) 166 | { 167 | m_errorFn("CompleteGraphConstruction(): fatal error"); 168 | } 169 | 170 | m_buf = (char *) Malloc(m_vectorMaxSizeInBytes + 171 | ( m_vectorMaxSizeInBytes > Edge::GetBufSizeInBytes(m_vectorMaxSizeInBytes) ? 172 | m_vectorMaxSizeInBytes : Edge::GetBufSizeInBytes(m_vectorMaxSizeInBytes) ) ); 173 | 174 | // set forward and backward edges properly 175 | #ifdef _DEBUG 176 | int ordering; 177 | for (i=m_nodeFirst, ordering=0; i; i=i->m_next, ordering++) 178 | { 179 | if ( (i->m_ordering != ordering) 180 | || (i->m_ordering == 0 && i->m_prev) 181 | || (i->m_ordering != 0 && i->m_prev->m_ordering != ordering-1) ) 182 | { 183 | m_errorFn("CompleteGraphConstruction(): fatal error (wrong ordering)"); 184 | } 185 | } 186 | if (ordering != m_nodeNum) 187 | { 188 | m_errorFn("CompleteGraphConstruction(): fatal error"); 189 | } 190 | #endif 191 | for (i=m_nodeFirst; i; i=i->m_next) 192 | { 193 | i->m_firstBackward = NULL; 194 | } 195 | for (i=m_nodeFirst; i; i=i->m_next) 196 | { 197 | ePrev = NULL; 198 | for (e=i->m_firstForward; e; ) 199 | { 200 | assert(i == e->m_tail); 201 | j = e->m_head; 202 | 203 | if (i->m_ordering < j->m_ordering) 204 | { 205 | e->m_nextBackward = j->m_firstBackward; 206 | j->m_firstBackward = e; 207 | 208 | ePrev = e; 209 | e = e->m_nextForward; 210 | } 211 | else 212 | { 213 | e->m_message.Swap(m_Kglobal, i->m_K, j->m_K); 214 | e->m_tail = j; 215 | e->m_head = i; 216 | 217 | MRFEdge* eNext = e->m_nextForward; 218 | 219 | if (ePrev) 220 | { 221 | ePrev->m_nextForward = e->m_nextForward; 222 | } 223 | else 224 | { 225 | i->m_firstForward = e->m_nextForward; 226 | } 227 | 228 | e->m_nextForward = j->m_firstForward; 229 | j->m_firstForward = e; 230 | 231 | e->m_nextBackward = i->m_firstBackward; 232 | i->m_firstBackward = e; 233 | 234 | e = eNext; 235 | } 236 | } 237 | } 238 | 239 | m_isEnergyConstructionCompleted = true; 240 | 241 | // ZeroMessages(); 242 | 243 | printf("done\n"); 244 | } 245 | -------------------------------------------------------------------------------- /StructureFinder.cpp: -------------------------------------------------------------------------------- 1 | #include "StructureFinder.h" 2 | 3 | #include 4 | #include 5 | 6 | // #include "OpenGM/mplp.hxx" 7 | // #include 8 | // #include 9 | // #include 10 | // #include 11 | #include "utils.h" 12 | #include 13 | 14 | 15 | using namespace std; 16 | using namespace cv; 17 | 18 | 19 | StructureFinder::StructureFinder(const int image_width, const int image_height, const map &segments, const vector &candidate_segment_mask, const std::vector visible_segmentation, const vector &visible_depths, const vector &background_depths, const vector &segment_backmost_layer_index_map, const RepresenterPenalties penalties, const DataStatistics statistics) : IMAGE_WIDTH_(image_width), IMAGE_HEIGHT_(image_height), NUM_PIXELS_(image_width * image_height), segments_(segments), NUM_SURFACES_(segments.size()), candidate_segment_mask_(candidate_segment_mask), visible_segmentation_(visible_segmentation), visible_depths_(visible_depths), background_depths_(background_depths), segment_backmost_layer_index_map_(segment_backmost_layer_index_map), penalties_(penalties), statistics_(statistics) 20 | { 21 | findTwoOrthogonalSurfaceStructures(); 22 | //optimizeConcaveHull(); 23 | } 24 | 25 | vector > > StructureFinder::getStructures() const 26 | { 27 | return structure_score_surface_ids_pairs_; 28 | } 29 | 30 | void StructureFinder::findTwoOrthogonalSurfaceStructures() 31 | { 32 | vector > surface_occluding_relations(NUM_SURFACES_, vector(NUM_SURFACES_, 0)); 33 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 34 | int segment_id = visible_segmentation_[pixel]; 35 | if (candidate_segment_mask_[segment_id] == false) 36 | continue; 37 | double depth = segments_.at(segment_id).getDepth(pixel); 38 | for (int other_segment_id = 0; other_segment_id < NUM_SURFACES_; other_segment_id++) { 39 | if (other_segment_id == segment_id) 40 | continue; 41 | if (candidate_segment_mask_[other_segment_id] == false) 42 | continue; 43 | double other_depth = segments_.at(other_segment_id).getDepth(pixel); 44 | if (other_depth > depth || other_depth < 0) 45 | surface_occluding_relations[segment_id][other_segment_id]++; 46 | else if (other_depth < depth) 47 | surface_occluding_relations[segment_id][other_segment_id]--; 48 | } 49 | } 50 | 51 | vector surface_normals_angles(NUM_SURFACES_ * NUM_SURFACES_); 52 | for (int segment_id_1 = 0; segment_id_1 < NUM_SURFACES_; segment_id_1++) { 53 | if (candidate_segment_mask_[segment_id_1] == false) 54 | continue; 55 | for (int segment_id_2 = segment_id_1 + 1; segment_id_2 < NUM_SURFACES_; segment_id_2++) { 56 | if (candidate_segment_mask_[segment_id_2] == false) 57 | continue; 58 | vector depth_plane_1 = segments_.at(segment_id_1).getDepthPlane(); 59 | vector depth_plane_2 = segments_.at(segment_id_2).getDepthPlane(); 60 | double cos_value = 0; 61 | for (int c = 0; c < 3; c++) 62 | cos_value += depth_plane_1[c] * depth_plane_2[c]; 63 | double angle = acos(min(abs(cos_value), 1.0)); 64 | surface_normals_angles[segment_id_1 * NUM_SURFACES_ + segment_id_2] = angle; 65 | surface_normals_angles[segment_id_2 * NUM_SURFACES_ + segment_id_1] = angle; 66 | } 67 | } 68 | 69 | vector > segment_pixels_vec(NUM_SURFACES_); 70 | vector > segment_ranges(NUM_SURFACES_); 71 | for (int segment_id = 0; segment_id < NUM_SURFACES_; segment_id++) { 72 | if (candidate_segment_mask_[segment_id] == false) 73 | continue; 74 | vector segment_pixels = segments_.at(segment_id).getSegmentPixels(); 75 | segment_pixels_vec[segment_id] = segment_pixels; 76 | 77 | vector range(4); 78 | for (int c = 0; c < 2; c++) { 79 | range[c * 2 + 0] = 1000000; 80 | range[c * 2 + 1] = -1000000; 81 | } 82 | for (vector::const_iterator pixel_it = segment_pixels.begin(); pixel_it != segment_pixels.end(); pixel_it++) { 83 | int x = *pixel_it % IMAGE_WIDTH_; 84 | int y = *pixel_it / IMAGE_WIDTH_; 85 | if (x < range[0]) 86 | range[0] = x; 87 | if (x > range[1]) 88 | range[1] = x; 89 | if (y < range[2]) 90 | range[2] = y; 91 | if (y < range[3]) 92 | range[3] = y; 93 | } 94 | segment_ranges[segment_id] = range; 95 | } 96 | 97 | 98 | for (int segment_id_1 = 0; segment_id_1 < NUM_SURFACES_; segment_id_1++) { 99 | if (candidate_segment_mask_[segment_id_1] == false) 100 | continue; 101 | for (int segment_id_2 = segment_id_1 + 1; segment_id_2 < NUM_SURFACES_; segment_id_2++) { 102 | if (candidate_segment_mask_[segment_id_2] == false) 103 | continue; 104 | if (max(segment_backmost_layer_index_map_[segment_id_1], segment_backmost_layer_index_map_[segment_id_2]) == 0) 105 | continue; 106 | 107 | bool concavity_or_convexity = surface_occluding_relations[segment_id_1][segment_id_2] + surface_occluding_relations[segment_id_2][segment_id_1] >= 0; 108 | // if (segment_id_1 != 8 || segment_id_2 != 9) 109 | // continue; 110 | double angle = surface_normals_angles[segment_id_1 * NUM_SURFACES_ + segment_id_2]; 111 | if (M_PI / 2 - angle >= statistics_.similar_angle_threshold) 112 | continue; 113 | 114 | vector range_1 = segment_ranges[segment_id_1]; 115 | vector range_2 = segment_ranges[segment_id_2]; 116 | if ((range_1[0] > range_2[1] || range_2[0] > range_1[1]) && (range_1[2] > range_2[3] || range_2[2] > range_1[3])) 117 | continue; 118 | 119 | vector structure_surface_ids(NUM_PIXELS_); 120 | vector structure_depths(NUM_PIXELS_); 121 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 122 | double depth_1 = segments_.at(segment_id_1).getDepth(pixel); 123 | double depth_2 = segments_.at(segment_id_2).getDepth(pixel); 124 | //cout << *concave_hull_surface_it << '\t' << depth << endl; 125 | if (concavity_or_convexity) { 126 | if (depth_1 < depth_2 && depth_1 > 0) { 127 | structure_surface_ids[pixel] = segment_id_1; 128 | structure_depths[pixel] = depth_1; 129 | } 130 | if (depth_2 < depth_1 && depth_2 > 0) { 131 | structure_surface_ids[pixel] = segment_id_2; 132 | structure_depths[pixel] = depth_2; 133 | } 134 | } else { 135 | if (depth_1 > depth_2 && depth_1 > 0) { 136 | structure_surface_ids[pixel] = segment_id_1; 137 | structure_depths[pixel] = depth_1; 138 | } 139 | if (depth_2 > depth_1 && depth_2 > 0) { 140 | structure_surface_ids[pixel] = segment_id_2; 141 | structure_depths[pixel] = depth_2; 142 | } 143 | } 144 | } 145 | 146 | int num_consistent_pixels = 0; 147 | int num_inpainting_pixels = 0; 148 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 149 | if (structure_surface_ids[pixel] == visible_segmentation_[pixel]) 150 | num_consistent_pixels++; 151 | else { 152 | double depth = structure_depths[pixel]; 153 | if (depth >= visible_depths_[pixel] - statistics_.depth_conflict_tolerance && depth <= background_depths_[pixel] + statistics_.depth_conflict_tolerance) { 154 | num_inpainting_pixels++; 155 | } 156 | } 157 | } 158 | double score = 1.0 * (num_consistent_pixels + num_inpainting_pixels) / NUM_PIXELS_; 159 | structure_score_surface_ids_pairs_.push_back(make_pair(score, structure_surface_ids)); 160 | } 161 | } 162 | sort(structure_score_surface_ids_pairs_.begin(), structure_score_surface_ids_pairs_.end()); 163 | 164 | for (int pair_index = 0; pair_index < structure_score_surface_ids_pairs_.size(); pair_index++) { 165 | double score = structure_score_surface_ids_pairs_[pair_index].first; 166 | vector surface_ids = structure_score_surface_ids_pairs_[pair_index].second; 167 | 168 | Mat structure_image = Mat::zeros(IMAGE_HEIGHT_, IMAGE_WIDTH_, CV_8UC1); 169 | map color_table; 170 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 171 | int segment_id = surface_ids[pixel]; 172 | if (segment_id == -1) 173 | continue; 174 | if (color_table.count(segment_id) == 0) 175 | color_table[segment_id] = rand() % 256; 176 | structure_image.at(pixel / IMAGE_WIDTH_, pixel % IMAGE_WIDTH_) = color_table[segment_id]; 177 | } 178 | 179 | // stringstream structure_image_filename; 180 | // structure_image_filename << "Test/structure_image_ " << pair_index << ".bmp"; 181 | // imwrite(structure_image_filename.str(), structure_image); 182 | 183 | cout << "structure: "; 184 | for (map::const_iterator segment_it = color_table.begin(); segment_it != color_table.end(); segment_it++) 185 | cout << segment_it->first << '\t'; 186 | cout << "score:" << score << endl; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /BSplineSurface.cpp: -------------------------------------------------------------------------------- 1 | #include "BSplineSurface.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | using namespace std; 10 | using namespace cv; 11 | using namespace Eigen; 12 | 13 | 14 | BSplineSurface::BSplineSurface(const vector &point_cloud, const vector &pixels, const int image_width, const int image_height, const double stride_x, const double stride_y, const int bspline_order) : IMAGE_WIDTH_(image_width), IMAGE_HEIGHT_(image_height), NUM_PIXELS_(image_width * image_height), STRIDE_X_(stride_x), STRIDE_Y_(stride_y), BSPLINE_ORDER_(bspline_order) 15 | { 16 | initControlPoints(); 17 | fitBSplineSurface(point_cloud, pixels); 18 | } 19 | 20 | double BSplineSurface::calcBasisFunctionValue2D(const double x, const double y, const double control_point_x, const double control_point_y, const double stride_x, const double stride_y, const int order) 21 | { 22 | if (x < control_point_x || x >= control_point_x + stride_x * (order + 1) || y < control_point_y || y >= control_point_y + stride_y * (order + 1)) 23 | return 0; 24 | return calcBasisFunctionValue1D(x, control_point_x, stride_x, order) * calcBasisFunctionValue1D(y, control_point_y, stride_y, order); 25 | } 26 | 27 | double BSplineSurface::calcBasisFunctionValue1D(const double &x, const double &control_point_x, const double &stride_x, const int &order) 28 | { 29 | if (order == 0) { 30 | if (x >= control_point_x && x < control_point_x + stride_x) 31 | return 1; 32 | else 33 | return 0; 34 | } 35 | double weight_1 = (x - control_point_x) / (stride_x * order); 36 | double weight_2 = (control_point_x + stride_x * (order + 1) - x) / (stride_x * order); 37 | return weight_1 * calcBasisFunctionValue1D(x, control_point_x, stride_x, order - 1) + weight_2 * calcBasisFunctionValue1D(x, control_point_x + stride_x, stride_x, order - 1); 38 | } 39 | 40 | void BSplineSurface::initControlPoints() 41 | { 42 | { 43 | int num_controls_points_x = IMAGE_WIDTH_ / STRIDE_X_ + BSPLINE_ORDER_ + 1; 44 | control_point_xs_.assign(num_controls_points_x, 0); 45 | double control_point_start_x = -STRIDE_X_ * BSPLINE_ORDER_; 46 | for (int i = 0; i < num_controls_points_x; i++) 47 | control_point_xs_[i] = control_point_start_x + STRIDE_X_ * i; 48 | } 49 | { 50 | int num_controls_points_y = IMAGE_HEIGHT_ / STRIDE_Y_ + BSPLINE_ORDER_ + 1; 51 | control_point_ys_.assign(num_controls_points_y, 0); 52 | double control_point_start_y = -STRIDE_Y_ * BSPLINE_ORDER_; 53 | for (int i = 0; i < num_controls_points_y; i++) 54 | control_point_ys_[i] = control_point_start_y + STRIDE_Y_ * i; 55 | } 56 | } 57 | 58 | void BSplineSurface::fitBSplineSurface(const vector &point_cloud, const vector &pixels) 59 | { 60 | const double DATA_WEIGHT = 3; 61 | const double SMOOTHNESS_SECOND_DERIVATIVE_WEIGHT = 1; 62 | const double SMOOTHNESS_FIRST_DERIVATIVE_WEIGHT = 1; 63 | 64 | const int NUM_CONTROL_POINTS_X = control_point_xs_.size(); 65 | const int NUM_CONTROL_POINTS_Y = control_point_ys_.size(); 66 | 67 | int num_valid_pixels = 0; 68 | for (vector::const_iterator pixel_it = pixels.begin(); pixel_it != pixels.end(); pixel_it++) 69 | if (point_cloud[*pixel_it * 3 + 2] > 0) 70 | num_valid_pixels++; 71 | 72 | const int NUM_DATA_TERMS = num_valid_pixels; 73 | const int NUM_SMOOTHNESS_SECOND_DERIVATIVE_TERMS = NUM_CONTROL_POINTS_X * NUM_CONTROL_POINTS_Y; 74 | const int NUM_SMOOTHNESS_FIRST_DERIVATIVE_TERMS = (NUM_CONTROL_POINTS_X - 2) * NUM_CONTROL_POINTS_Y + NUM_CONTROL_POINTS_X * (NUM_CONTROL_POINTS_Y - 2); 75 | 76 | SparseMatrix A(NUM_DATA_TERMS + NUM_SMOOTHNESS_SECOND_DERIVATIVE_TERMS + NUM_SMOOTHNESS_FIRST_DERIVATIVE_TERMS, NUM_CONTROL_POINTS_X * NUM_CONTROL_POINTS_Y); 77 | VectorXd b(NUM_DATA_TERMS + NUM_SMOOTHNESS_SECOND_DERIVATIVE_TERMS + NUM_SMOOTHNESS_FIRST_DERIVATIVE_TERMS); 78 | vector > triplets; 79 | 80 | int valid_pixel_index = 0; 81 | for (vector::const_iterator pixel_it = pixels.begin(); pixel_it != pixels.end(); pixel_it++) { 82 | if (point_cloud[*pixel_it * 3 + 2] < 0) 83 | continue; 84 | int x = *pixel_it % IMAGE_WIDTH_; 85 | int y = *pixel_it / IMAGE_WIDTH_; 86 | //double sum_basis_function_values = 0; 87 | for (vector::const_iterator control_point_x_it = control_point_xs_.begin(); control_point_x_it != control_point_xs_.end(); control_point_x_it++) { 88 | for (vector::const_iterator control_point_y_it = control_point_ys_.begin(); control_point_y_it != control_point_ys_.end(); control_point_y_it++) { 89 | double basis_function_value = calcBasisFunctionValue2D(x, y, *control_point_x_it, *control_point_y_it, STRIDE_X_, STRIDE_Y_, BSPLINE_ORDER_); 90 | if (basis_function_value < 0.0001) 91 | continue; 92 | triplets.push_back(Eigen::Triplet(valid_pixel_index, (control_point_y_it - control_point_ys_.begin()) * NUM_CONTROL_POINTS_X + (control_point_x_it - control_point_xs_.begin()), basis_function_value * DATA_WEIGHT)); 93 | //sum_basis_function_values += basis_function_value; 94 | } 95 | } 96 | b[valid_pixel_index] = point_cloud[*pixel_it * 3 + 2] * DATA_WEIGHT; 97 | valid_pixel_index++; 98 | } 99 | for (vector::const_iterator control_point_y_it = control_point_ys_.begin(); control_point_y_it != control_point_ys_.end(); control_point_y_it++) { 100 | for (vector::const_iterator control_point_x_it = control_point_xs_.begin(); control_point_x_it != control_point_xs_.end(); control_point_x_it++) { 101 | int index_x = control_point_x_it - control_point_xs_.begin(); 102 | int index_y = control_point_y_it - control_point_ys_.begin(); 103 | int index = index_y * NUM_CONTROL_POINTS_X + index_x; 104 | vector neighbor_indices; 105 | if (index_x > 0) 106 | neighbor_indices.push_back(index - 1); 107 | if (index_x < NUM_CONTROL_POINTS_X - 1) 108 | neighbor_indices.push_back(index + 1); 109 | if (index_y > 0) 110 | neighbor_indices.push_back(index - NUM_CONTROL_POINTS_X); 111 | if (index_y < NUM_CONTROL_POINTS_Y - 1) 112 | neighbor_indices.push_back(index + NUM_CONTROL_POINTS_X); 113 | for (vector::const_iterator neighbor_index_it = neighbor_indices.begin(); neighbor_index_it != neighbor_indices.end(); neighbor_index_it++) 114 | triplets.push_back(Eigen::Triplet(NUM_DATA_TERMS + index, *neighbor_index_it, -1.0 * SMOOTHNESS_SECOND_DERIVATIVE_WEIGHT / neighbor_indices.size())); 115 | triplets.push_back(Eigen::Triplet(NUM_DATA_TERMS + index, index, SMOOTHNESS_SECOND_DERIVATIVE_WEIGHT)); 116 | b[NUM_DATA_TERMS + index] = 0; 117 | 118 | if (index_x > 0 && index_x < NUM_CONTROL_POINTS_X - 1) { 119 | int term_index = NUM_DATA_TERMS + NUM_SMOOTHNESS_SECOND_DERIVATIVE_TERMS + index_y * (NUM_CONTROL_POINTS_X - 2) + (index_x - 1); 120 | triplets.push_back(Eigen::Triplet(term_index, index - 1, 1 * SMOOTHNESS_FIRST_DERIVATIVE_WEIGHT)); 121 | triplets.push_back(Eigen::Triplet(term_index, index + 1, -1 * SMOOTHNESS_FIRST_DERIVATIVE_WEIGHT)); 122 | // triplets.push_back(Eigen::Triplet(term_index, index, SMOOTHNESS_FIRST_DERIVATIVE_WEIGHT)); 123 | b[term_index] = 0; 124 | } 125 | if (index_y > 0 && index_y < NUM_CONTROL_POINTS_Y - 1) { 126 | int term_index = NUM_DATA_TERMS + NUM_SMOOTHNESS_SECOND_DERIVATIVE_TERMS + (NUM_CONTROL_POINTS_X - 2) * NUM_CONTROL_POINTS_Y + (index_y - 1) * NUM_CONTROL_POINTS_X + index_x; 127 | triplets.push_back(Eigen::Triplet(term_index, index - NUM_CONTROL_POINTS_X, 1 * SMOOTHNESS_FIRST_DERIVATIVE_WEIGHT)); 128 | triplets.push_back(Eigen::Triplet(term_index, index + NUM_CONTROL_POINTS_X, -1 * SMOOTHNESS_FIRST_DERIVATIVE_WEIGHT)); 129 | // triplets.push_back(Eigen::Triplet(term_index, index, SMOOTHNESS_FIRST_DERIVATIVE_WEIGHT)); 130 | b[term_index] = 0; 131 | } 132 | } 133 | } 134 | A.setFromTriplets(triplets.begin(), triplets.end()); 135 | 136 | VectorXd control_point_depths = SparseQR, NaturalOrdering >(A).solve(b); 137 | 138 | depth_map_.assign(NUM_PIXELS_, 0); 139 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 140 | double depth = 0; 141 | int x = pixel % IMAGE_WIDTH_; 142 | int y = pixel / IMAGE_WIDTH_; 143 | for (vector::const_iterator control_point_x_it = control_point_xs_.begin(); control_point_x_it != control_point_xs_.end(); control_point_x_it++) { 144 | for (vector::const_iterator control_point_y_it = control_point_ys_.begin(); control_point_y_it != control_point_ys_.end(); control_point_y_it++) { 145 | double basis_function_value = calcBasisFunctionValue2D(x, y, *control_point_x_it, *control_point_y_it, STRIDE_X_, STRIDE_Y_, BSPLINE_ORDER_); 146 | depth += control_point_depths[(control_point_y_it - control_point_ys_.begin()) * NUM_CONTROL_POINTS_X + (control_point_x_it - control_point_xs_.begin())] * basis_function_value; 147 | } 148 | } 149 | depth_map_[pixel] = depth; 150 | } 151 | 152 | 153 | // double fitting_error = 0; 154 | // for (vector::const_iterator pixel_it = pixels.begin(); pixel_it != pixels.end(); pixel_it++) 155 | // fitting_error += pow(depth_map_[*pixel_it] - point_cloud[*pixel_it * 3 + 2], 2); 156 | // // cout << depth_map_[*pixel_it] << '\t' << point_cloud[*pixel_it * 3 + 2] << endl; 157 | // cout << sqrt(fitting_error / pixels.size()) << endl; 158 | 159 | // Mat disp_image(IMAGE_HEIGHT_, IMAGE_WIDTH_, CV_8UC1); 160 | // for (int y = 0; y < IMAGE_HEIGHT_; y++) { 161 | // for (int x = 0; x < IMAGE_WIDTH_; x++) { 162 | // int pixel = y * IMAGE_WIDTH_ + x; 163 | // double depth = depth_map_[pixel]; 164 | // disp_image.at(y, x) = 100 / depth; 165 | // } 166 | // } 167 | // imwrite("Test/bspline_image.bmp", disp_image); 168 | // exit(1); 169 | } 170 | 171 | vector BSplineSurface::getDepthMap() const 172 | { 173 | return depth_map_; 174 | } 175 | -------------------------------------------------------------------------------- /TRW_S/MRFEnergy.h: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | Vladimir Kolmogorov, 2005 3 | vnk@microsoft.com 4 | 5 | (c) Microsoft Corporation. All rights reserved. 6 | *******************************************************************/ 7 | 8 | #ifndef __MRFENERGY_H__ 9 | #define __MRFENERGY_H__ 10 | 11 | #include "instances.h" 12 | 13 | #include 14 | 15 | 16 | 17 | // After MRFEnergy is allocated, there are two phases: 18 | // 1. Energy construction. Only AddNode(), AddNodeData() and AddEdge() may be called. 19 | // 20 | // Any call ZeroMessages(), SetAutomaticOrdering(), Minimize_TRW_S() or Minimize_BP() 21 | // completes graph construction; MRFEnergy goes to the second phase: 22 | // 2. Only functions AddNodeData(), ZeroMessages(), Minimize_TRW_S(), Minimize_BP() 23 | // or GetSolution() may be called. (The last function can be called only after 24 | // Minimize_TRW_S() or Minimize_BP()). 25 | 26 | 27 | template class MRFEnergy 28 | { 29 | private: 30 | struct Node; 31 | 32 | public: 33 | typedef typename T::Label Label; 34 | typedef typename T::REAL REAL; 35 | typedef typename T::GlobalSize GlobalSize; 36 | typedef typename T::LocalSize LocalSize; 37 | typedef typename T::NodeData NodeData; 38 | typedef typename T::EdgeData EdgeData; 39 | 40 | typedef Node* NodeId; 41 | typedef void (*ErrorFunction)(char* msg); 42 | 43 | // Constructor. Function errorFn is called with an error message, if an error occurs. 44 | MRFEnergy(GlobalSize Kglobal, ErrorFunction errorFn = NULL); 45 | 46 | // Destructor. 47 | ~MRFEnergy(); 48 | 49 | ////////////////////////////////////////////////////////// 50 | // Energy construction // 51 | ////////////////////////////////////////////////////////// 52 | 53 | // Adds a node with parameters K and data 54 | // (see the corresponding message*.h file for description). 55 | // Note: information in data is copied into internal memory. 56 | // Cannot be called after energy construction is completed. 57 | NodeId AddNode(LocalSize K, NodeData data); 58 | 59 | // Modifies node parameter for existing node (namely, add information 60 | // in data to existing parameter). May be called at any time. 61 | // Node i must be NodeId returned by AddNode(). 62 | void AddNodeData(NodeId i, NodeData data); 63 | 64 | // Adds an edge between i and j. data determins edge parameters 65 | // (see the corresponding message*.h file for description). 66 | // Note: information in data is copied into internal memory. 67 | // Cannot be called after energy construction is completed. 68 | void AddEdge(NodeId i, NodeId j, EdgeData data); 69 | 70 | ////////////////////////////////////////////////////////// 71 | // Energy construction end // 72 | ////////////////////////////////////////////////////////// 73 | 74 | // Clears all messages. Completes energy construction (if not completed yet). 75 | void ZeroMessages(); 76 | 77 | // Adds to all message entries a value drawn uniformly from [min_value, max_value]. 78 | // Normally, min_value can be set to 0 (except for TypeBinaryFast, in which case min_value = -max_value) 79 | void AddRandomMessages(unsigned int random_seed, REAL min_value, REAL max_value); 80 | 81 | // The algorithm depends on the order of nodes. 82 | // By default nodes are processed in the order in which they were added. 83 | // The function below permutes this order using certain heuristics. 84 | // It may speed up the algorithm if, for example, the original order is random. 85 | // 86 | // Completes energy construction. 87 | // Cannot be called after energy construction is completed. 88 | void SetAutomaticOrdering(); 89 | 90 | // The structure below specifies (1) stopping criteria and 91 | // (2) how often to compute solution and print its energy. 92 | struct Options 93 | { 94 | Options() 95 | { 96 | // default parameters 97 | m_eps = -1; // not used 98 | m_iterMax = 1000000; 99 | m_printIter = 5; // After 10 iterations start printing the lower bound 100 | m_printMinIter = 10; // and the energy every 5 iterations. 101 | } 102 | 103 | // stopping criterion 104 | REAL m_eps; // stop if the increase in the lower bound during one iteration is less or equal than m_eps. 105 | // Used only if m_eps >= 0, and only for TRW-S algorithm. 106 | int m_iterMax; // maximum number of iterations 107 | 108 | // Option for printing lower bound and the energy. 109 | // Note: computing solution and its energy is slow 110 | // (it is comparable to the cost of one iteration). 111 | int m_printIter; // print lower bound and energy every m_printIter iterations 112 | int m_printMinIter; // do not print lower bound and energy before m_printMinIter iterations 113 | }; 114 | 115 | // Returns number of iterations. Sets lowerBound and energy. 116 | // If the user provides array min_marginals, then the code 117 | // sets this array accordingly. (The size of the array depends on the type 118 | // used. Normally, it's (# nodes)*(# labels). Exception: for TypeBinaryFast it's (# nodes). 119 | int Minimize_TRW_S(Options& options, REAL& lowerBound, REAL& energy, REAL* min_marginals = NULL); 120 | 121 | // Returns number of iterations. Sets energy. 122 | int Minimize_BP(Options& options, REAL& energy, REAL* min_marginals = NULL); 123 | 124 | // Returns an integer in [0,Ki). Can be called only after Minimize(). 125 | Label GetSolution(NodeId i); 126 | 127 | 128 | REAL ComputeSolutionAndEnergy(const int start_index); 129 | int changeOrdering(const std::vector &ordering); 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | ////////////////////////////////////////////////////////// 139 | ////////////////////////////////////////////////////////// 140 | ////////////////////////////////////////////////////////// 141 | // Implementation // 142 | ////////////////////////////////////////////////////////// 143 | ////////////////////////////////////////////////////////// 144 | ////////////////////////////////////////////////////////// 145 | private: 146 | 147 | typedef typename T::Vector Vector; 148 | typedef typename T::Edge Edge; 149 | 150 | struct MRFEdge; 151 | struct MallocBlock; 152 | 153 | ErrorFunction m_errorFn; 154 | MallocBlock* m_mallocBlockFirst; 155 | Node* m_nodeFirst; 156 | Node* m_nodeLast; 157 | int m_nodeNum; 158 | int m_edgeNum; 159 | GlobalSize m_Kglobal; 160 | int m_vectorMaxSizeInBytes; 161 | 162 | bool m_isEnergyConstructionCompleted; 163 | 164 | char* m_buf; // buffer of size m_vectorMaxSizeInBytes 165 | // + max(m_vectorMaxSizeInBytes, Edge::GetBufSizeInBytes(m_vectorMaxSizeInBytes)) 166 | 167 | void CompleteGraphConstruction(); // nodes and edges cannot be added after calling this function 168 | void SetMonotonicTrees(); 169 | 170 | REAL ComputeSolutionAndEnergy(); // sets Node::m_solution, returns value of the energy 171 | 172 | 173 | 174 | struct Node 175 | { 176 | int m_ordering; // unique integer in [0,m_nodeNum-1) 177 | 178 | MRFEdge* m_firstForward; // first edge going to nodes with greater m_ordering 179 | MRFEdge* m_firstBackward; // first edge going to nodes with smaller m_ordering 180 | 181 | Node* m_prev; // previous and next 182 | Node* m_next; // nodes according to m_ordering 183 | 184 | Label m_solution; // integer in [0,m_D.m_K) 185 | LocalSize m_K; // local information about number of labels 186 | 187 | Vector m_D; // must be the last member in the struct since its size is not fixed 188 | }; 189 | 190 | struct MRFEdge 191 | { 192 | MRFEdge* m_nextForward; // next forward edge with the same tail 193 | MRFEdge* m_nextBackward; // next backward edge with the same head 194 | Node* m_tail; 195 | Node* m_head; 196 | 197 | REAL m_gammaForward; // = rho_{ij} / rho_{i} where i=m_tail, j=m_head 198 | REAL m_gammaBackward; // = rho_{ij} / rho_{j} where i=m_tail, j=m_head 199 | 200 | Edge m_message; // must be the last member in the struct since its size is not fixed. 201 | // Stores edge information and either forward or backward message. 202 | // Most of the time it's the backward message; it gets replaced 203 | // by the forward message only temporarily inside Minimize_TRW_S() and Minimize_BP(). 204 | }; 205 | 206 | // Use our own Malloc since 207 | // (a) new in C++ is slow and allocates minimum memory of 64 bytes (in Visual C++) 208 | // (b) we want simple (one function) deallocation instead of going through every allocated element 209 | struct MallocBlock 210 | { 211 | static const int minBlockSizeInBytes = 4096 - 3*sizeof(void*); 212 | MallocBlock* m_next; 213 | char* m_current; // first element of available memory in this block 214 | char* m_last; // first element outside of allocated memory for this block 215 | }; 216 | char* Malloc(int bytesNum); 217 | }; 218 | 219 | 220 | 221 | 222 | template inline char* MRFEnergy::Malloc(int bytesNum) 223 | { 224 | if (!m_mallocBlockFirst || m_mallocBlockFirst->m_current+bytesNum > m_mallocBlockFirst->m_last) 225 | { 226 | int size = (bytesNum > MallocBlock::minBlockSizeInBytes) ? bytesNum : MallocBlock::minBlockSizeInBytes; 227 | MallocBlock* b = (MallocBlock*) new char[sizeof(MallocBlock) + size]; 228 | if (!b) m_errorFn("Not enough memory"); 229 | b->m_current = (char*) b + sizeof(MallocBlock); 230 | b->m_last = b->m_current + size; 231 | 232 | b->m_next = m_mallocBlockFirst; 233 | m_mallocBlockFirst = b; 234 | } 235 | 236 | char* ptr = m_mallocBlockFirst->m_current; 237 | m_mallocBlockFirst->m_current += bytesNum; 238 | return ptr; 239 | } 240 | 241 | template inline typename T::Label MRFEnergy::GetSolution(NodeId i) 242 | { 243 | return i->m_solution; 244 | } 245 | 246 | void DefaultErrorFn(char* msg); 247 | 248 | 249 | #include "MRFEnergy.def" 250 | #include "minimize.def" 251 | #include "treeProbabilities.def" 252 | #include "ordering.def" 253 | 254 | #endif 255 | -------------------------------------------------------------------------------- /ConcaveHullFinder.cpp: -------------------------------------------------------------------------------- 1 | #include "ConcaveHullFinder.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | #include "utils.h" 8 | #include 9 | 10 | #include "cv_utils/cv_utils.h" 11 | 12 | 13 | using namespace std; 14 | using namespace cv; 15 | 16 | 17 | ConcaveHullFinder::ConcaveHullFinder(const int image_width, const int image_height, const vector &point_cloud, const vector &segmentation, const std::map &segments, const vector &ROI_mask, const RepresenterPenalties penalties, const DataStatistics statistics, const bool consider_background) : point_cloud_(point_cloud), segmentation_(segmentation), ROI_mask_(ROI_mask), IMAGE_WIDTH_(image_width), IMAGE_HEIGHT_(image_height), NUM_PIXELS_(segmentation.size()), NUM_SURFACES_(segments.size()), penalties_(penalties), statistics_(statistics) 18 | { 19 | for (map::const_iterator segment_it = segments.begin(); segment_it != segments.end(); segment_it++) 20 | surface_depths_[segment_it->first] = segment_it->second.getDepthMap(); 21 | 22 | for (map::const_iterator segment_it = segments.begin(); segment_it != segments.end(); segment_it++) 23 | segment_type_map_[segment_it->first] = segment_it->second.getType(); 24 | 25 | surface_normals_angles_ = vector(NUM_SURFACES_ * NUM_SURFACES_); 26 | for (int segment_id_1 = 0; segment_id_1 < NUM_SURFACES_; segment_id_1++) { 27 | if (segment_type_map_[segment_id_1] != 0) 28 | continue; 29 | for (int segment_id_2 = segment_id_1; segment_id_2 < NUM_SURFACES_; segment_id_2++) { 30 | if (segment_type_map_[segment_id_2] != 0) 31 | continue; 32 | vector depth_plane_1 = segments.at(segment_id_1).getDepthPlane(); 33 | vector depth_plane_2 = segments.at(segment_id_2).getDepthPlane(); 34 | double cos_value = 0; 35 | for (int c = 0; c < 3; c++) 36 | cos_value += depth_plane_1[c] * depth_plane_2[c]; 37 | double angle = acos(min(abs(cos_value), 1.0)); 38 | surface_normals_angles_[segment_id_1 * NUM_SURFACES_ + segment_id_2] = angle; 39 | surface_normals_angles_[segment_id_2 * NUM_SURFACES_ + segment_id_1] = angle; 40 | } 41 | } 42 | 43 | for (int segment_id = 0; segment_id < NUM_SURFACES_; segment_id++) { 44 | if (segment_type_map_[segment_id] != 0) 45 | continue; 46 | vector depth_plane = segments.at(segment_id).getDepthPlane(); 47 | double cos_value = depth_plane[1]; 48 | double angle = acos(min(abs(cos_value), 1.0)); 49 | if (angle < statistics_.similar_angle_threshold) 50 | segment_direction_map_[segment_id] = 0; 51 | else if ((M_PI / 2 - angle) < statistics_.similar_angle_threshold) 52 | segment_direction_map_[segment_id] = 1; 53 | else 54 | segment_direction_map_[segment_id] = -1; 55 | } 56 | 57 | calcConcaveHull(); 58 | } 59 | 60 | ConcaveHullFinder::~ConcaveHullFinder() 61 | { 62 | } 63 | 64 | vector ConcaveHullFinder::getConcaveHull() 65 | { 66 | return concave_hull_labels_; 67 | } 68 | 69 | void ConcaveHullFinder::calcConcaveHull() 70 | { 71 | vector visible_depths(NUM_PIXELS_); 72 | vector > surface_occluding_relations(NUM_SURFACES_, vector(NUM_SURFACES_, 0)); 73 | set ROI_segment_ids_set; 74 | int num_ROI_pixels = 0; 75 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 76 | if (ROI_mask_[pixel] == false) 77 | continue; 78 | int segment_id = segmentation_[pixel]; 79 | assert(segment_id >= 0 && segment_id < NUM_SURFACES_); 80 | ROI_segment_ids_set.insert(segment_id); 81 | double depth = surface_depths_[segment_id][pixel]; 82 | visible_depths[pixel] = depth; 83 | 84 | for (int other_segment_id = 0; other_segment_id < NUM_SURFACES_; other_segment_id++) { 85 | if (other_segment_id == segment_id) 86 | continue; 87 | double other_depth = surface_depths_[other_segment_id][pixel]; 88 | if (other_depth > depth || other_depth < 0) 89 | surface_occluding_relations[segment_id][other_segment_id]++; 90 | else if (other_depth < depth) 91 | surface_occluding_relations[segment_id][other_segment_id]--; 92 | } 93 | 94 | num_ROI_pixels++; 95 | } 96 | 97 | vector horizontal_segment_ids_vec; 98 | vector vertical_segment_ids_vec; 99 | for (set::const_iterator segment_it = ROI_segment_ids_set.begin(); segment_it != ROI_segment_ids_set.end(); segment_it++) { 100 | if (segment_type_map_[*segment_it] != 0) 101 | continue; 102 | if (segment_direction_map_[*segment_it] == 0) 103 | horizontal_segment_ids_vec.push_back(*segment_it); 104 | else if (segment_direction_map_[*segment_it] == 1) 105 | vertical_segment_ids_vec.push_back(*segment_it); 106 | } 107 | 108 | //cout << horizontal_segment_ids_vec.size() << '\t' << vertical_segment_ids_vec.size() << endl; 109 | vector best_score_concave_hull; 110 | double best_score = 0; 111 | for (int num_horizontal_surfaces = 0; num_horizontal_surfaces <= min(2, static_cast(horizontal_segment_ids_vec.size())); num_horizontal_surfaces++) { 112 | vector > horizontal_surfaces_vec = cv_utils::findAllCombinations(horizontal_segment_ids_vec, num_horizontal_surfaces); 113 | for (int num_vertical_surfaces = 0; num_vertical_surfaces <= min(3, static_cast(vertical_segment_ids_vec.size())); num_vertical_surfaces++) { 114 | if (num_vertical_surfaces == 0 && num_horizontal_surfaces == 0) 115 | continue; 116 | vector > vertical_surfaces_vec = cv_utils::findAllCombinations(vertical_segment_ids_vec, num_vertical_surfaces); 117 | for (vector >::const_iterator horizontal_surfaces_it = horizontal_surfaces_vec.begin(); horizontal_surfaces_it != horizontal_surfaces_vec.end(); horizontal_surfaces_it++) { 118 | for (vector >::const_iterator vertical_surfaces_it = vertical_surfaces_vec.begin(); vertical_surfaces_it != vertical_surfaces_vec.end(); vertical_surfaces_it++) { 119 | vector concave_hull_surfaces = *horizontal_surfaces_it; 120 | concave_hull_surfaces.insert(concave_hull_surfaces.end(), vertical_surfaces_it->begin(), vertical_surfaces_it->end()); 121 | 122 | vector concave_hull(NUM_PIXELS_); 123 | vector depths(NUM_PIXELS_); 124 | int num_invalid_pixels = 0; 125 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 126 | if (ROI_mask_[pixel] == false) 127 | continue; 128 | int selected_surface_id = concave_hull_surfaces[0]; 129 | double selected_depth = surface_depths_[concave_hull_surfaces[0]][pixel]; 130 | //cout << selected_surface_id << '\t' << selected_depth << endl; 131 | for (vector::const_iterator concave_hull_surface_it = concave_hull_surfaces.begin() + 1; concave_hull_surface_it != concave_hull_surfaces.end(); concave_hull_surface_it++) { 132 | double depth = surface_depths_[*concave_hull_surface_it][pixel]; 133 | //cout << *concave_hull_surface_it << '\t' << depth << endl; 134 | if (surface_occluding_relations[*concave_hull_surface_it][selected_surface_id] + surface_occluding_relations[selected_surface_id][*concave_hull_surface_it] >= 0) { 135 | if ((depth < selected_depth || selected_depth < 0) && depth > 0) { 136 | selected_surface_id = *concave_hull_surface_it; 137 | selected_depth = depth; 138 | } 139 | } else { 140 | if (depth > selected_depth && selected_depth > 0) { 141 | selected_surface_id = *concave_hull_surface_it; 142 | selected_depth = depth; 143 | } 144 | } 145 | } 146 | concave_hull[pixel] = selected_surface_id; 147 | depths[pixel] = selected_depth; 148 | } 149 | 150 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 151 | if (ROI_mask_[pixel] == false) 152 | continue; 153 | double depth = depths[pixel]; 154 | if (depth < visible_depths[pixel] - statistics_.depth_conflict_tolerance) { 155 | num_invalid_pixels++; 156 | } 157 | } 158 | 159 | int num_ROI_pixels = 0; 160 | int num_consistent_pixels = 0; 161 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 162 | if (ROI_mask_[pixel] == false) 163 | continue; 164 | num_ROI_pixels++; 165 | if (segmentation_[pixel] == concave_hull[pixel]) 166 | num_consistent_pixels++; 167 | } 168 | 169 | double score = 1.0 * (num_consistent_pixels - num_invalid_pixels * 10) / num_ROI_pixels; 170 | 171 | if (best_score_concave_hull.size() == 0 || score > best_score) { 172 | best_score_concave_hull = concave_hull; 173 | best_score = score; 174 | } 175 | } 176 | } 177 | } 178 | } 179 | // exit(1); 180 | 181 | concave_hull_labels_ = best_score_concave_hull; 182 | if (concave_hull_labels_.size() == 0) { 183 | cout << "Background concave hull not found." << endl; 184 | return; 185 | } 186 | 187 | concave_hull_surfaces_.clear(); 188 | for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) 189 | if (ROI_mask_[pixel] == true) 190 | concave_hull_surfaces_.insert(concave_hull_labels_[pixel]); 191 | 192 | 193 | // map color_table; 194 | // Mat ori_region_image(IMAGE_HEIGHT_, IMAGE_WIDTH_, CV_8UC3); 195 | // Mat concave_hull_image(IMAGE_HEIGHT_, IMAGE_WIDTH_, CV_8UC3); 196 | // for (int pixel = 0; pixel < NUM_PIXELS_; pixel++) { 197 | // if (ROI_mask_[pixel] == false) { 198 | // ori_region_image.at(pixel / IMAGE_WIDTH_, pixel % IMAGE_WIDTH_) = Vec3b(255, 0, 0); 199 | // concave_hull_image.at(pixel / IMAGE_WIDTH_, pixel % IMAGE_WIDTH_) = Vec3b(255, 0, 0); 200 | // continue; 201 | // } 202 | // int segment_id = segmentation_[pixel]; 203 | // if (color_table.count(segment_id) == 0) { 204 | // int gray_value = rand() % 256; 205 | // color_table[segment_id] = Vec3b(gray_value, gray_value, gray_value); 206 | // } 207 | // ori_region_image.at(pixel / IMAGE_WIDTH_, pixel % IMAGE_WIDTH_) = color_table[segment_id]; 208 | // int concave_hull_segment_id = concave_hull_labels_[pixel]; 209 | // if (color_table.count(concave_hull_segment_id) == 0) { 210 | // int gray_value = rand() % 256; 211 | // color_table[concave_hull_segment_id] = Vec3b(gray_value, gray_value, gray_value); 212 | // } 213 | // concave_hull_image.at(pixel / IMAGE_WIDTH_, pixel % IMAGE_WIDTH_) = color_table[concave_hull_segment_id]; 214 | // } 215 | 216 | // static int index = 0; 217 | // stringstream ori_region_image_filename; 218 | // ori_region_image_filename << "Test/background_ori_region_image_.bmp"; 219 | // imwrite(ori_region_image_filename.str(), ori_region_image); 220 | // stringstream concave_hull_image_filename; 221 | // concave_hull_image_filename << "Test/background_concave_hull_image.bmp"; 222 | // imwrite(concave_hull_image_filename.str(), concave_hull_image); 223 | // // index++; 224 | } 225 | 226 | -------------------------------------------------------------------------------- /TRW_S/typeBinaryFast.h: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | typeBinaryFast.h 3 | 4 | Same energy and interface as in typeBinary.h. 5 | Faster implementation; however, values of lower bound and energy are computed 6 | incorrectly. (Note that the solution is the same as with typeBinary.h). 7 | 8 | For example usage, see typeBinary.h (only replace TypeBinary with TypeBinaryFast). 9 | *******************************************************************/ 10 | 11 | 12 | 13 | 14 | 15 | 16 | #ifndef __TYPEBINARYFAST_H__ 17 | #define __TYPEBINARYFAST_H__ 18 | 19 | #include 20 | #include 21 | 22 | 23 | template class MRFEnergy; 24 | 25 | 26 | class TypeBinaryFast 27 | { 28 | private: 29 | struct Vector; // node parameters and messages 30 | struct Edge; // stores edge information and either forward or backward message 31 | 32 | public: 33 | // types declarations 34 | typedef int Label; 35 | typedef double REAL; 36 | struct GlobalSize; // global information about number of labels 37 | struct LocalSize; // local information about number of labels (stored at each node) 38 | struct NodeData; // argument to MRFEnergy::AddNode() 39 | struct EdgeData; // argument to MRFEnergy::AddEdge() 40 | 41 | 42 | struct GlobalSize // always 2 labels - no need to store it 43 | { 44 | }; 45 | 46 | struct LocalSize // always 2 labels - no need to store it 47 | { 48 | }; 49 | 50 | struct NodeData 51 | { 52 | NodeData(REAL D0, REAL D1); 53 | 54 | private: 55 | friend struct Vector; 56 | friend struct Edge; 57 | REAL m_data[2]; 58 | }; 59 | 60 | struct EdgeData 61 | { 62 | EdgeData(REAL V00, REAL V01, REAL V10, REAL V11); 63 | 64 | private: 65 | friend struct Vector; 66 | friend struct Edge; 67 | REAL m_V[2][2]; 68 | }; 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | ////////////////////////////////////////////////////////////////////////////////// 77 | ////////////////////////// Visible only to MRFEnergy ///////////////////////////// 78 | ////////////////////////////////////////////////////////////////////////////////// 79 | 80 | private: 81 | friend class MRFEnergy; 82 | 83 | struct Vector 84 | { 85 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize K); // returns -1 if invalid K's 86 | void Initialize(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user adds a node 87 | void Add(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user calls MRFEnergy::AddNodeData() 88 | 89 | void SetZero(GlobalSize Kglobal, LocalSize K); // set this[k] = 0 90 | void Copy(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = V[k] 91 | void Add(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = this[k] + V[k] 92 | REAL GetValue(GlobalSize Kglobal, LocalSize K, Label k); // return this[k] 93 | REAL ComputeMin(GlobalSize Kglobal, LocalSize K, Label& kMin); // return min_k { this[k] }, set kMin 94 | REAL ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K); // same as previous, but additionally set this[k] -= vMin (and kMin is not returned) 95 | 96 | static int GetArraySize(GlobalSize Kglobal, LocalSize K); 97 | REAL GetArrayValue(GlobalSize Kglobal, LocalSize K, int k); // note: k is an integer in [0..GetArraySize()-1]. 98 | // For Potts functions GetArrayValue() and GetValue() are the same, 99 | // but they are different for, say, 2-dimensional labels. 100 | void SetArrayValue(GlobalSize Kglobal, LocalSize K, int k, REAL x); 101 | 102 | private: 103 | friend struct Edge; 104 | REAL m_data; // = D[1] - D[0] 105 | }; 106 | 107 | struct Edge 108 | { 109 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data); // returns -1 if invalid data 110 | static int GetBufSizeInBytes(int vectorMaxSizeInBytes); // returns size of buffer need for UpdateMessage() 111 | void Initialize(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data, Vector* Di, Vector* Dj); // called once when user adds an edge 112 | Vector* GetMessagePtr(); 113 | void Swap(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj); // if the client calls this function, then the meaning of 'dir' 114 | // in distance transform functions is swapped 115 | 116 | // When UpdateMessage() is called, edge contains message from dest to source. 117 | // The function must replace it with the message from source to dest. 118 | // The update rule is given below assuming that source corresponds to tail (i) and dest corresponds 119 | // to head (j) (which is the case if dir==0). 120 | // 121 | // 1. Compute Di[ki] = gamma*source[ki] - message[ki]. (Note: message = message from j to i). 122 | // 2. Compute distance transform: set 123 | // message[kj] = min_{ki} (Di[ki] + V(ki,kj)). (Note: message = message from i to j). 124 | // 3. Compute vMin = min_{kj} m_message[kj]. 125 | // 4. Set m_message[kj] -= vMin. 126 | // 5. Return vMin. 127 | // 128 | // If dir==1 then source corresponds to j, sink corresponds to i. Then the update rule is 129 | // 130 | // 1. Compute Dj[kj] = gamma*source[kj] - message[kj]. (Note: message = message from i to j). 131 | // 2. Compute distance transform: set 132 | // message[ki] = min_{kj} (Dj[kj] + V(ki,kj)). (Note: message = message from j to i). 133 | // 3. Compute vMin = min_{ki} m_message[ki]. 134 | // 4. Set m_message[ki] -= vMin. 135 | // 5. Return vMin. 136 | // 137 | // If Edge::Swap has been called odd number of times, then the meaning of dir is swapped. 138 | // 139 | // Vector 'source' must not be modified. Function may use 'buf' as a temporary storage. 140 | REAL UpdateMessage(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Vector* source, REAL gamma, int dir, void* buf); 141 | 142 | // If dir==0, then sets dest[kj] += V(ksource,kj). 143 | // If dir==1, then sets dest[ki] += V(ki,ksource). 144 | // If Swap() has been called odd number of times, then the meaning of dir is swapped. 145 | void AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir); 146 | 147 | private: 148 | // edge information 149 | REAL m_lambdaIsing; 150 | 151 | // message 152 | Vector m_message; 153 | }; 154 | }; 155 | 156 | 157 | 158 | 159 | ////////////////////////////////////////////////////////////////////////////////// 160 | /////////////////////////////// Implementation /////////////////////////////////// 161 | ////////////////////////////////////////////////////////////////////////////////// 162 | 163 | 164 | 165 | ///////////////////// NodeData and EdgeData /////////////////////// 166 | 167 | inline TypeBinaryFast::NodeData::NodeData(REAL D0, REAL D1) 168 | { 169 | m_data[0] = D0; 170 | m_data[1] = D1; 171 | } 172 | 173 | inline TypeBinaryFast::EdgeData::EdgeData(REAL V00, REAL V01, REAL V10, REAL V11) 174 | { 175 | m_V[0][0] = V00; 176 | m_V[0][1] = V01; 177 | m_V[1][0] = V10; 178 | m_V[1][1] = V11; 179 | } 180 | 181 | ///////////////////// Vector /////////////////////// 182 | 183 | inline int TypeBinaryFast::Vector::GetSizeInBytes(GlobalSize Kglobal, LocalSize K) 184 | { 185 | return sizeof(Vector); 186 | } 187 | inline void TypeBinaryFast::Vector::Initialize(GlobalSize Kglobal, LocalSize K, NodeData data) 188 | { 189 | m_data = data.m_data[1] - data.m_data[0]; 190 | } 191 | 192 | inline void TypeBinaryFast::Vector::Add(GlobalSize Kglobal, LocalSize K, NodeData data) 193 | { 194 | m_data += data.m_data[1] - data.m_data[0]; 195 | } 196 | 197 | inline void TypeBinaryFast::Vector::SetZero(GlobalSize Kglobal, LocalSize K) 198 | { 199 | m_data = 0; 200 | } 201 | 202 | inline void TypeBinaryFast::Vector::Copy(GlobalSize Kglobal, LocalSize K, Vector* V) 203 | { 204 | m_data = V->m_data; 205 | } 206 | 207 | inline void TypeBinaryFast::Vector::Add(GlobalSize Kglobal, LocalSize K, Vector* V) 208 | { 209 | m_data += V->m_data; 210 | } 211 | 212 | inline TypeBinaryFast::REAL TypeBinaryFast::Vector::GetValue(GlobalSize Kglobal, LocalSize K, Label k) 213 | { 214 | assert(k>=0 && k<2); 215 | return (k == 0) ? 0 : m_data; 216 | } 217 | 218 | inline TypeBinaryFast::REAL TypeBinaryFast::Vector::ComputeMin(GlobalSize Kglobal, LocalSize K, Label& kMin) 219 | { 220 | kMin = (m_data >= 0) ? 0 : 1; 221 | return 0; 222 | } 223 | 224 | inline TypeBinaryFast::REAL TypeBinaryFast::Vector::ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K) 225 | { 226 | return 0; 227 | } 228 | 229 | inline int TypeBinaryFast::Vector::GetArraySize(GlobalSize Kglobal, LocalSize K) 230 | { 231 | return 1; 232 | } 233 | 234 | inline TypeBinaryFast::REAL TypeBinaryFast::Vector::GetArrayValue(GlobalSize Kglobal, LocalSize K, int k) 235 | { 236 | assert(k==0); 237 | return m_data; 238 | } 239 | 240 | inline void TypeBinaryFast::Vector::SetArrayValue(GlobalSize Kglobal, LocalSize K, int k, REAL x) 241 | { 242 | assert(k==0); 243 | m_data = x; 244 | } 245 | 246 | ///////////////////// EdgeDataAndMessage implementation ///////////////////////// 247 | 248 | inline int TypeBinaryFast::Edge::GetSizeInBytes(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data) 249 | { 250 | return sizeof(Edge); 251 | } 252 | 253 | inline int TypeBinaryFast::Edge::GetBufSizeInBytes(int vectorMaxSizeInBytes) 254 | { 255 | return 0; 256 | } 257 | 258 | inline void TypeBinaryFast::Edge::Initialize(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data, Vector* Di, Vector* Dj) 259 | { 260 | // V00 V01 = A B = A A + 0.5 * ( 0 0 + 0 P-Q + 0 P+Q ) 261 | // V10 V11 C D D D Q-P Q-P 0 P-Q P+Q 0 262 | // where P=B-A, Q=C-D 263 | Di->m_data += data.m_V[1][1] - data.m_V[0][0]; 264 | REAL P = data.m_V[0][1] - data.m_V[0][0], Q = data.m_V[1][0] - data.m_V[1][1]; 265 | REAL halfPplusQ = (REAL)0.5 * (P + Q); 266 | REAL halfPminusQ = (REAL)0.5 * (P - Q); 267 | Di->m_data += -halfPminusQ; 268 | Dj->m_data += halfPminusQ; 269 | m_lambdaIsing = halfPplusQ; 270 | m_message.m_data = halfPminusQ + (data.m_V[0][0] - data.m_V[1][1]); 271 | } 272 | 273 | inline TypeBinaryFast::Vector* TypeBinaryFast::Edge::GetMessagePtr() 274 | { 275 | return &m_message; 276 | } 277 | 278 | inline void TypeBinaryFast::Edge::Swap(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj) 279 | { 280 | } 281 | 282 | inline TypeBinaryFast::REAL TypeBinaryFast::Edge::UpdateMessage(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Vector* source, REAL gamma, int dir, void* buf) 283 | { 284 | REAL s = gamma*source->m_data - m_message.m_data; 285 | 286 | if (m_lambdaIsing >= 0) 287 | { 288 | if (s >= m_lambdaIsing) m_message.m_data = m_lambdaIsing; 289 | else if (s <= -m_lambdaIsing) m_message.m_data = -m_lambdaIsing; 290 | else m_message.m_data = s; 291 | } 292 | else 293 | { 294 | if (s >= -m_lambdaIsing) m_message.m_data = m_lambdaIsing; 295 | else if (s <= m_lambdaIsing) m_message.m_data = -m_lambdaIsing; 296 | else m_message.m_data = -s; 297 | } 298 | 299 | return 0; 300 | } 301 | 302 | inline void TypeBinaryFast::Edge::AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir) 303 | { 304 | dest->m_data += (ksource == 0) ? m_lambdaIsing : -m_lambdaIsing; 305 | } 306 | 307 | ////////////////////////////////////////////////////////////////////////////////// 308 | 309 | #endif 310 | -------------------------------------------------------------------------------- /cv_utils/cv_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "ImageMask.h" 12 | #include "Histogram.h" 13 | //#include "FusionSpaceSolver.h" 14 | 15 | 16 | namespace cv_utils 17 | { 18 | //class Histogram; 19 | //class Histogram; 20 | // class ImageMask; 21 | 22 | /**********Image Operations**********/ 23 | 24 | //complete image with holes 25 | cv::Mat completeImage(const cv::Mat &input_image, const std::vector &input_source_mask, const std::vector &input_target_mask, const int WINDOW_SIZE = 5, const Eigen::Matrix3d &unwarp_transform = Eigen::MatrixXd::Identity(3, 3)); 26 | 27 | //complete image with holes 28 | cv::Mat completeImage(const cv::Mat &input_image, const ImageMask &input_source_mask, const ImageMask &input_target_mask, const int WINDOW_SIZE = 5, const Eigen::Matrix3d &unwarp_transform = Eigen::MatrixXd::Identity(3, 3)); 29 | 30 | //complete image with holes using fusion space approace 31 | cv::Mat completeImageUsingFusionSpace(const cv::Mat &image, const ImageMask &source_mask, const ImageMask &target_mask, const int WINDOW_SIZE); 32 | 33 | //fast computation box integration 34 | std::vector calcBoxIntegrationMask(const std::vector &values, const int IMAGE_WIDTH, const int IMAGE_HEIGHT); 35 | double calcBoxIntegration(const std::vector &mask, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const int x_1, const int y_1, const int x_2, const int y_2); 36 | 37 | //calculate means and vars for all windows 38 | void calcWindowMeansAndVars(const std::vector &values, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const int WINDOW_SIZE, std::vector &means, std::vector &vars); 39 | void calcWindowMeansAndVars(const std::vector > &values, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const int WINDOW_SIZE, std::vector > &means, std::vector > &vars); 40 | 41 | //guided image filtering 42 | void guidedFilter(const cv::Mat &guidance_image, const cv::Mat &input_image, cv::Mat &output_image, const double radius, const double epsilon); 43 | 44 | 45 | 46 | /**********Common Operations**********/ 47 | 48 | //find corresponding pixel on another image 49 | inline int convertPixel(const int pixel, const int WIDTH, const int HEIGHT, const int NEW_WIDTH, const int NEW_HEIGHT) 50 | { 51 | int new_pixel_x = std::min(static_cast(round(1.0 * (pixel % WIDTH) * NEW_WIDTH / WIDTH)), NEW_WIDTH - 1); 52 | int new_pixel_y = std::min(static_cast(round(1.0 * (pixel / WIDTH) * NEW_HEIGHT / HEIGHT)), NEW_HEIGHT - 1); 53 | return new_pixel_y * NEW_WIDTH + new_pixel_x; 54 | } 55 | 56 | //find neighbors of a pixel on image 57 | std::vector findNeighbors(const int pixel, const int WIDTH, const int HEIGHT, const bool USE_PANORAMA = false, const int NEIGHBOR_SYSTEM = 8); 58 | 59 | //find neighbors for all pixels 60 | std::vector > findNeighborsForAllPixels(const int WIDTH, const int HEIGHT, const int NEIGHBOR_SYSTEM = 8); 61 | 62 | //find pixels in a neighboring window 63 | std::vector findWindowPixels(const int pixel, const int WIDTH, const int HEIGHT, const int WINDOW_SIZE, const bool USE_PANORAMA = false); 64 | 65 | inline double calcColorDiff(const cv::Mat &image, const int &pixel_1, const int &pixel_2) 66 | { 67 | if (image.channels() == 1) 68 | return abs(1.0 * image.at(pixel_1 / image.cols, pixel_1 % image.cols) - image.at(pixel_2 / image.cols, pixel_2 % image.cols)); 69 | else { 70 | cv::Vec3b color_1 = image.at(pixel_1 / image.cols, pixel_1 % image.cols); 71 | cv::Vec3b color_2 = image.at(pixel_2 / image.cols, pixel_2 % image.cols); 72 | double difference = 0; 73 | for (int c = 0; c < 3; c++) 74 | difference += pow(1.0 * color_1[c] - color_2[c], 2); 75 | return sqrt(difference); 76 | } 77 | } 78 | 79 | template inline T getMin(const std::vector &values) 80 | { 81 | T min_value = std::numeric_limits::max(); 82 | for (typename std::vector::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) 83 | if (*value_it < min_value) 84 | min_value = *value_it; 85 | return min_value; 86 | } 87 | 88 | template inline T getMax(const std::vector &values) 89 | { 90 | T max_value = std::numeric_limits::lowest(); 91 | for (typename std::vector::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) 92 | if (*value_it > max_value) 93 | max_value = *value_it; 94 | return max_value; 95 | } 96 | 97 | template inline std::vector randomSampleValues(const std::vector &values, const int NUM_SAMPLES) 98 | { 99 | assert(values.size() >= NUM_SAMPLES); 100 | std::vector sampled_values; 101 | std::vector used_mask(values.size(), false); 102 | while (sampled_values.size() < NUM_SAMPLES) { 103 | int value_index = rand() % values.size(); 104 | if (used_mask[value_index] == true) 105 | continue; 106 | sampled_values.push_back(values[value_index]); 107 | used_mask[value_index] = true; 108 | } 109 | return sampled_values; 110 | } 111 | 112 | template inline std::vector getVec(const T &value_1, const T &value_2) 113 | { 114 | std::vector values(2); 115 | values[0] = value_1; 116 | values[1] = value_2; 117 | return values; 118 | } 119 | 120 | template inline std::vector getVec(const T &value_1, const T &value_2, const T &value_3) 121 | { 122 | std::vector values(3); 123 | values[0] = value_1; 124 | values[1] = value_2; 125 | values[3] = value_3; 126 | return values; 127 | } 128 | 129 | 130 | /**********Statistics Calculation**********/ 131 | 132 | //generate a random probablity 133 | inline double randomProbability() 134 | { 135 | std::random_device rd; 136 | std::mt19937 gen(rd()); 137 | std::uniform_real_distribution<> dis(0, 1); 138 | return dis(gen); 139 | } 140 | 141 | //calculate the number of bits with specified bit value 142 | inline int calcNumBits(const int value, const int denoted_bit_value) 143 | { 144 | int num_bits = 0; 145 | int current_value = value; 146 | while (current_value > 0) { 147 | int bit_value = current_value % 2; 148 | num_bits += bit_value == denoted_bit_value ? 1 : 0; 149 | current_value /= 2; 150 | } 151 | return num_bits; 152 | } 153 | 154 | //calculate the mean and svar of a set of values 155 | std::vector calcMeanAndSVar(const std::vector &values); 156 | //calculate the mean and svar of a set of values with more than one dimension 157 | void calcMeanAndSVar(const std::vector > &values, std::vector &mean, std::vector > &var); 158 | 159 | //find all possible combinations of selecting num_elements elements from candidates 160 | std::vector > findAllCombinations(const std::vector &candidates, const int num_elements); 161 | 162 | //calculate the number of distinct values 163 | int calcNumDistinctValues(const std::vector &values); 164 | 165 | 166 | /**********Geometry Calculation**********/ 167 | 168 | //fit a plane based on points. 169 | std::vector fitPlane(const std::vector &points); 170 | 171 | //estimate camera parameters 172 | void estimateCameraParameters(const std::vector &point_cloud, const int image_width, const int image_height, double &focal_length); 173 | void estimateCameraParameters(const std::vector &point_cloud, const int image_width, const int image_height, std::vector &camera_parameters, const bool USE_PANORAMA = false); 174 | 175 | //calculate surface normals for given point cloud based on local windows 176 | std::vector calcNormals(const std::vector &point_cloud, const int image_width, const int image_height, const int K = 30); 177 | 178 | //calculate surface normal at pixel for given point cloud based on local windows 179 | std::vector calcNormals(const std::vector &point_cloud, const int pixel, const int image_width, const int image_height, const int K = 30); 180 | 181 | //calculate surface curvatures for given point cloud based on local windows 182 | std::vector calcCurvatures(const std::vector &point_cloud, const int image_width, const int image_height, const int K = 30); 183 | 184 | //calculate 2D geodesic distance between two pixels 185 | double calcGeodesicDistance(const std::vector > &distance_map, const int width, const int height, const int start_pixel, const int end_pixel, const double distance_2D_weight); 186 | 187 | //calculate 2D geodesic distance from a start pixel to all end pixels 188 | std::vector calcGeodesicDistances(const std::vector > &distance_map, const int width, const int height, const int start_pixel, const std::vector end_pixels, const double distance_2D_weight); 189 | 190 | 191 | //calculate the dot product of two vectors 192 | inline double calcDotProduct(const std::vector &vec_1, const std::vector &vec_2) 193 | { 194 | assert(vec_1.size() == vec_2.size()); 195 | double dot_product = 0; 196 | for (int i = 0; i < vec_1.size(); i++) 197 | dot_product += vec_1[i] * vec_2[i]; 198 | return dot_product; 199 | } 200 | 201 | //calculate the cross product of two vectors 202 | inline std::vector calcCrossProduct(const std::vector &vec_1, const std::vector &vec_2) 203 | { 204 | assert(vec_1.size() == vec_2.size() && vec_1.size() == 3); 205 | std::vector cross_product(3); 206 | cross_product[0] = vec_1[1] * vec_2[2] - vec_1[2] * vec_2[1]; 207 | cross_product[1] = vec_1[2] * vec_2[0] - vec_1[0] * vec_2[2]; 208 | cross_product[2] = vec_1[0] * vec_2[1] - vec_1[1] * vec_2[0]; 209 | return cross_product; 210 | } 211 | 212 | //calculate the L2 norm of a vector 213 | inline double calcNorm(const std::vector &vec) 214 | { 215 | double sum = 0; 216 | for (int c = 0; c < vec.size(); c++) 217 | sum += pow(vec[c], 2); 218 | return sqrt(sum); 219 | } 220 | 221 | //calculate the distance from a point to a plane 222 | inline double calcPointPlaneDistance(const std::vector &point, const std::vector &plane) 223 | { 224 | double distance = plane[3]; 225 | for (int c = 0; c < 3; c++) 226 | distance -= plane[c] * point[c]; 227 | return distance; 228 | } 229 | 230 | //calculate the euclidean distance between two vectors 231 | inline double calcDistance(const std::vector &vec_1, const std::vector &vec_2) 232 | { 233 | assert(vec_1.size() == vec_2.size()); 234 | double distance = 0; 235 | for (int c = 0; c < vec_1.size(); c++) 236 | distance += pow(vec_1[c] - vec_2[c], 2); 237 | return sqrt(distance); 238 | } 239 | 240 | //calculate the angle between two vectors 241 | inline double calcAngle(const std::vector &vec_1, const std::vector &vec_2) 242 | { 243 | assert(vec_1.size() == vec_2.size()); 244 | double cos_value = 0; 245 | for (int c = 0; c < vec_1.size(); c++) 246 | cos_value += vec_1[c] * vec_2[c]; 247 | return acos(std::max(std::min(cos_value, 1.0), -1.0)); 248 | } 249 | 250 | //fit a 2D line 251 | std::vector fitLine2D(const std::vector &points); 252 | 253 | /**********Point Cloud Operations**********/ 254 | 255 | inline std::vector getPoint(const std::vector &point_cloud, const int pixel) 256 | { 257 | return std::vector(point_cloud.begin() + pixel * 3, point_cloud.begin() + (pixel + 1) * 3); 258 | } 259 | 260 | inline std::vector getPoints(const std::vector &point_cloud, const std::vector &pixels) 261 | { 262 | std::vector points; 263 | for (std::vector::const_iterator pixel_it = pixels.begin(); pixel_it != pixels.end(); pixel_it++) 264 | points.insert(points.end(), point_cloud.begin() + *pixel_it * 3, point_cloud.begin() + (*pixel_it + 1) * 3); 265 | return points; 266 | } 267 | 268 | inline bool checkPointValidity(const std::vector &point) 269 | { 270 | assert(point.size() == 3); 271 | if (calcNorm(std::vector(point.begin(), point.begin() + 3)) < 0.000001) 272 | return false; 273 | else 274 | return true; 275 | } 276 | 277 | inline ImageMask getInvalidPointMask(const std::vector &point_cloud, const int WIDTH, const int HEIGHT) 278 | { 279 | std::vector invalid_mask(WIDTH * HEIGHT, false); 280 | for (int pixel = 0; pixel < WIDTH * HEIGHT; pixel++) 281 | invalid_mask[pixel] = !checkPointValidity(getPoint(point_cloud, pixel)); 282 | return ImageMask(invalid_mask, WIDTH, HEIGHT); 283 | } 284 | 285 | bool writePointCloud(const std::string &filename, const std::vector &point_cloud, const int IMAGE_WIDTH, const int IMAGE_HEIGHT); 286 | bool readPointCloud(const std::string &filename, std::vector &point_cloud); 287 | 288 | /**********Matrix Calculation**********/ 289 | std::vector > calcInverse(const std::vector > &matrix); 290 | } 291 | 292 | #endif 293 | -------------------------------------------------------------------------------- /TRW_S/typeBinary.h: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | typeBinary.h 3 | 4 | Energy function with binary labels: 5 | E(x) = \sum_i D_i(x_i) + \sum_ij V_ij(x_i,x_j) 6 | where x_i \in {0,1}. 7 | 8 | Example usage: 9 | 10 | Minimize function E(x,y) = Dx(x) + Dy(y) + V(x,y) where 11 | x,y \in {0,1}, 12 | Dx(0) = 0, Dx(1) = 1, 13 | Dy(0) = 2, Dy(1) = 3, 14 | V(0,0) = 4, V(0,1) = 5, 15 | V(1,0) = 6, V(1,1) = 7, 16 | [.] is 1 if it's argument is true, and 0 otherwise. 17 | 18 | 19 | 20 | #include 21 | #include "MRFEnergy.h" 22 | 23 | void testBinary() 24 | { 25 | MRFEnergy* mrf; 26 | MRFEnergy::NodeId* nodes; 27 | MRFEnergy::Options options; 28 | TypeBinary::REAL energy, lowerBound; 29 | 30 | const int nodeNum = 2; // number of nodes 31 | int x, y; 32 | 33 | mrf = new MRFEnergy(TypeBinary::GlobalSize(K)); 34 | nodes = new MRFEnergy::NodeId[nodeNum]; 35 | 36 | // construct energy 37 | nodes[0] = mrf->AddNode(TypeBinary::LocalSize(), TypeBinary::NodeData(0, 1)); 38 | nodes[1] = mrf->AddNode(TypeBinary::LocalSize(), TypeBinary::NodeData(2, 3)); 39 | mrf->AddEdge(nodes[0], nodes[1], TypeBinary::EdgeData(4, 5, 6, 7)); 40 | 41 | // Function below is optional - it may help if, for example, nodes are added in a random order 42 | // mrf->SetAutomaticOrdering(); 43 | 44 | /////////////////////// TRW-S algorithm ////////////////////// 45 | options.m_iterMax = 30; // maximum number of iterations 46 | mrf->Minimize_TRW_S(options, lowerBound, energy); 47 | 48 | // read solution 49 | x = mrf->GetSolution(nodes[0]); 50 | y = mrf->GetSolution(nodes[1]); 51 | 52 | printf("Solution: %d %d\n", x, y); 53 | 54 | //////////////////////// BP algorithm //////////////////////// 55 | mrf->ZeroMessages(); // in general not necessary - it may be faster to start 56 | // with messages computed in previous iterations 57 | 58 | options.m_iterMax = 30; // maximum number of iterations 59 | mrf->Minimize_BP(options, energy); 60 | 61 | // read solution 62 | x = mrf->GetSolution(nodes[0]); 63 | y = mrf->GetSolution(nodes[1]); 64 | 65 | printf("Solution: %d %d\n", x, y); 66 | 67 | // done 68 | delete nodes; 69 | delete mrf; 70 | } 71 | 72 | *******************************************************************/ 73 | 74 | 75 | 76 | 77 | 78 | 79 | #ifndef __TYPEBINARY_H__ 80 | #define __TYPEBINARY_H__ 81 | 82 | #include 83 | #include 84 | 85 | 86 | template class MRFEnergy; 87 | 88 | 89 | class TypeBinary 90 | { 91 | private: 92 | struct Vector; // node parameters and messages 93 | struct Edge; // stores edge information and either forward or backward message 94 | 95 | public: 96 | // types declarations 97 | typedef int Label; 98 | typedef double REAL; 99 | struct GlobalSize; // global information about number of labels 100 | struct LocalSize; // local information about number of labels (stored at each node) 101 | struct NodeData; // argument to MRFEnergy::AddNode() 102 | struct EdgeData; // argument to MRFEnergy::AddEdge() 103 | 104 | 105 | struct GlobalSize // always 2 labels - no need to store it 106 | { 107 | }; 108 | 109 | struct LocalSize // always 2 labels - no need to store it 110 | { 111 | }; 112 | 113 | struct NodeData 114 | { 115 | NodeData(REAL D0, REAL D1); 116 | 117 | private: 118 | friend struct Vector; 119 | friend struct Edge; 120 | REAL m_data[2]; 121 | }; 122 | 123 | struct EdgeData 124 | { 125 | EdgeData(REAL V00, REAL V01, REAL V10, REAL V11); 126 | 127 | private: 128 | friend struct Vector; 129 | friend struct Edge; 130 | REAL m_V[2][2]; 131 | }; 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | ////////////////////////////////////////////////////////////////////////////////// 140 | ////////////////////////// Visible only to MRFEnergy ///////////////////////////// 141 | ////////////////////////////////////////////////////////////////////////////////// 142 | 143 | private: 144 | friend class MRFEnergy; 145 | 146 | struct Vector 147 | { 148 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize K); // returns -1 if invalid K's 149 | void Initialize(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user adds a node 150 | void Add(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user calls MRFEnergy::AddNodeData() 151 | 152 | void SetZero(GlobalSize Kglobal, LocalSize K); // set this[k] = 0 153 | void Copy(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = V[k] 154 | void Add(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = this[k] + V[k] 155 | REAL GetValue(GlobalSize Kglobal, LocalSize K, Label k); // return this[k] 156 | REAL ComputeMin(GlobalSize Kglobal, LocalSize K, Label& kMin); // return min_k { this[k] }, set kMin 157 | REAL ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K); // same as previous, but additionally set this[k] -= vMin (and kMin is not returned) 158 | 159 | static int GetArraySize(GlobalSize Kglobal, LocalSize K); 160 | REAL GetArrayValue(GlobalSize Kglobal, LocalSize K, int k); // note: k is an integer in [0..GetArraySize()-1]. 161 | // For Potts functions GetArrayValue() and GetValue() are the same, 162 | // but they are different for, say, 2-dimensional labels. 163 | void SetArrayValue(GlobalSize Kglobal, LocalSize K, int k, REAL x); 164 | 165 | private: 166 | friend struct Edge; 167 | REAL m_data[2]; 168 | }; 169 | 170 | struct Edge 171 | { 172 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data); // returns -1 if invalid data 173 | static int GetBufSizeInBytes(int vectorMaxSizeInBytes); // returns size of buffer need for UpdateMessage() 174 | void Initialize(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data, Vector* Di, Vector* Dj); // called once when user adds an edge 175 | Vector* GetMessagePtr(); 176 | void Swap(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj); // if the client calls this function, then the meaning of 'dir' 177 | // in distance transform functions is swapped 178 | 179 | // When UpdateMessage() is called, edge contains message from dest to source. 180 | // The function must replace it with the message from source to dest. 181 | // The update rule is given below assuming that source corresponds to tail (i) and dest corresponds 182 | // to head (j) (which is the case if dir==0). 183 | // 184 | // 1. Compute Di[ki] = gamma*source[ki] - message[ki]. (Note: message = message from j to i). 185 | // 2. Compute distance transform: set 186 | // message[kj] = min_{ki} (Di[ki] + V(ki,kj)). (Note: message = message from i to j). 187 | // 3. Compute vMin = min_{kj} m_message[kj]. 188 | // 4. Set m_message[kj] -= vMin. 189 | // 5. Return vMin. 190 | // 191 | // If dir==1 then source corresponds to j, sink corresponds to i. Then the update rule is 192 | // 193 | // 1. Compute Dj[kj] = gamma*source[kj] - message[kj]. (Note: message = message from i to j). 194 | // 2. Compute distance transform: set 195 | // message[ki] = min_{kj} (Dj[kj] + V(ki,kj)). (Note: message = message from j to i). 196 | // 3. Compute vMin = min_{ki} m_message[ki]. 197 | // 4. Set m_message[ki] -= vMin. 198 | // 5. Return vMin. 199 | // 200 | // If Edge::Swap has been called odd number of times, then the meaning of dir is swapped. 201 | // 202 | // Vector 'source' must not be modified. Function may use 'buf' as a temporary storage. 203 | REAL UpdateMessage(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Vector* source, REAL gamma, int dir, void* buf); 204 | 205 | // If dir==0, then sets dest[kj] += V(ksource,kj). 206 | // If dir==1, then sets dest[ki] += V(ki,ksource). 207 | // If Swap() has been called odd number of times, then the meaning of dir is swapped. 208 | void AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir); 209 | 210 | private: 211 | // edge information 212 | REAL m_lambdaIsing; 213 | 214 | // message 215 | Vector m_message; 216 | }; 217 | }; 218 | 219 | 220 | 221 | 222 | ////////////////////////////////////////////////////////////////////////////////// 223 | /////////////////////////////// Implementation /////////////////////////////////// 224 | ////////////////////////////////////////////////////////////////////////////////// 225 | 226 | 227 | 228 | ///////////////////// NodeData and EdgeData /////////////////////// 229 | 230 | inline TypeBinary::NodeData::NodeData(REAL D0, REAL D1) 231 | { 232 | m_data[0] = D0; 233 | m_data[1] = D1; 234 | } 235 | 236 | inline TypeBinary::EdgeData::EdgeData(REAL V00, REAL V01, REAL V10, REAL V11) 237 | { 238 | m_V[0][0] = V00; 239 | m_V[0][1] = V01; 240 | m_V[1][0] = V10; 241 | m_V[1][1] = V11; 242 | } 243 | 244 | ///////////////////// Vector /////////////////////// 245 | 246 | inline int TypeBinary::Vector::GetSizeInBytes(GlobalSize Kglobal, LocalSize K) 247 | { 248 | return sizeof(Vector); 249 | } 250 | inline void TypeBinary::Vector::Initialize(GlobalSize Kglobal, LocalSize K, NodeData data) 251 | { 252 | m_data[0] = data.m_data[0]; 253 | m_data[1] = data.m_data[1]; 254 | } 255 | 256 | inline void TypeBinary::Vector::Add(GlobalSize Kglobal, LocalSize K, NodeData data) 257 | { 258 | m_data[0] += data.m_data[0]; 259 | m_data[1] += data.m_data[1]; 260 | } 261 | 262 | inline void TypeBinary::Vector::SetZero(GlobalSize Kglobal, LocalSize K) 263 | { 264 | m_data[0] = 0; 265 | m_data[1] = 0; 266 | } 267 | 268 | inline void TypeBinary::Vector::Copy(GlobalSize Kglobal, LocalSize K, Vector* V) 269 | { 270 | m_data[0] = V->m_data[0]; 271 | m_data[1] = V->m_data[1]; 272 | } 273 | 274 | inline void TypeBinary::Vector::Add(GlobalSize Kglobal, LocalSize K, Vector* V) 275 | { 276 | m_data[0] += V->m_data[0]; 277 | m_data[1] += V->m_data[1]; 278 | } 279 | 280 | inline TypeBinary::REAL TypeBinary::Vector::GetValue(GlobalSize Kglobal, LocalSize K, Label k) 281 | { 282 | assert(k>=0 && k<2); 283 | return m_data[k]; 284 | } 285 | 286 | inline TypeBinary::REAL TypeBinary::Vector::ComputeMin(GlobalSize Kglobal, LocalSize K, Label& kMin) 287 | { 288 | kMin = (m_data[0] <= m_data[1]) ? 0 : 1; 289 | return m_data[kMin]; 290 | } 291 | 292 | inline TypeBinary::REAL TypeBinary::Vector::ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K) 293 | { 294 | REAL vMin; 295 | 296 | if (m_data[0] <= m_data[1]) 297 | { 298 | vMin = m_data[0]; 299 | m_data[0] = 0; 300 | m_data[1] -= vMin; 301 | } 302 | else 303 | { 304 | vMin = m_data[1]; 305 | m_data[1] = 0; 306 | m_data[0] -= vMin; 307 | } 308 | 309 | return vMin; 310 | } 311 | 312 | inline int TypeBinary::Vector::GetArraySize(GlobalSize Kglobal, LocalSize K) 313 | { 314 | return 2; 315 | } 316 | 317 | inline TypeBinary::REAL TypeBinary::Vector::GetArrayValue(GlobalSize Kglobal, LocalSize K, int k) 318 | { 319 | assert(k>=0 && k<2); 320 | return m_data[k]; 321 | } 322 | 323 | inline void TypeBinary::Vector::SetArrayValue(GlobalSize Kglobal, LocalSize K, int k, REAL x) 324 | { 325 | assert(k>=0 && k<2); 326 | m_data[k] = x; 327 | } 328 | 329 | ///////////////////// EdgeDataAndMessage implementation ///////////////////////// 330 | 331 | inline int TypeBinary::Edge::GetSizeInBytes(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data) 332 | { 333 | return sizeof(Edge); 334 | } 335 | 336 | inline int TypeBinary::Edge::GetBufSizeInBytes(int vectorMaxSizeInBytes) 337 | { 338 | return 0; 339 | } 340 | 341 | inline void TypeBinary::Edge::Initialize(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data, Vector* Di, Vector* Dj) 342 | { 343 | // V00 V01 = A B = A A + 0.5 * ( 0 0 + 0 P-Q + 0 P+Q ) 344 | // V10 V11 C D D D Q-P Q-P 0 P-Q P+Q 0 345 | // where P=B-A, Q=C-D 346 | Di->m_data[0] += data.m_V[0][0]; 347 | Di->m_data[1] += data.m_V[1][1]; 348 | REAL P = data.m_V[0][1] - data.m_V[0][0], Q = data.m_V[1][0] - data.m_V[1][1]; 349 | REAL halfPplusQ = (REAL)0.5 * (P + Q); 350 | REAL halfPminusQ = (REAL)0.5 * (P - Q); 351 | Di->m_data[1] += -halfPminusQ; 352 | Dj->m_data[1] += halfPminusQ; 353 | m_lambdaIsing = halfPplusQ; 354 | m_message.m_data[0] = 0; 355 | m_message.m_data[1] = halfPminusQ + (data.m_V[0][0] - data.m_V[1][1]); 356 | } 357 | 358 | inline TypeBinary::Vector* TypeBinary::Edge::GetMessagePtr() 359 | { 360 | return &m_message; 361 | } 362 | 363 | inline void TypeBinary::Edge::Swap(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj) 364 | { 365 | } 366 | 367 | inline TypeBinary::REAL TypeBinary::Edge::UpdateMessage(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Vector* source, REAL gamma, int dir, void* buf) 368 | { 369 | REAL data[2], vMin; 370 | 371 | data[0] = gamma*source->m_data[0] - m_message.m_data[0]; 372 | data[1] = gamma*source->m_data[1] - m_message.m_data[1]; 373 | m_message.m_data[0] = (data[0] < data[1] + m_lambdaIsing) ? data[0] : data[1] + m_lambdaIsing; 374 | m_message.m_data[1] = (data[1] < data[0] + m_lambdaIsing) ? data[1] : data[0] + m_lambdaIsing; 375 | 376 | vMin = (m_message.m_data[0] < m_message.m_data[1]) ? m_message.m_data[0] : m_message.m_data[1]; 377 | m_message.m_data[0] -= vMin; 378 | m_message.m_data[1] -= vMin; 379 | return vMin; 380 | } 381 | 382 | 383 | 384 | 385 | inline void TypeBinary::Edge::AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir) 386 | { 387 | dest->m_data[1-ksource] += m_lambdaIsing; 388 | } 389 | 390 | ////////////////////////////////////////////////////////////////////////////////// 391 | 392 | #endif 393 | -------------------------------------------------------------------------------- /TRW_S/typePotts.h: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | typePotts.h 3 | 4 | Energy function with Potts interactions: 5 | E(x) = \sum_i D_i(x_i) + \sum_ij V_ij(x_i,x_j) 6 | where x_i \in {0, 1, ..., K-1}, 7 | V_ij(ki, kj) = 0 if ki==kj, and lambda_ij otherwise. 8 | lambda_ij must be non-negative. 9 | 10 | Example usage: 11 | 12 | Minimize function E(x,y) = Dx(x) + Dy(y) + lambda*[x != y] where 13 | x,y \in {0,1,2}, 14 | Dx(0) = 0, Dx(1) = 1, Dx(2) = 2, 15 | Dy(0) = 3, Dy(1) = 4, Dy(2) = 5, 16 | lambda = 6, 17 | [.] is 1 if it's argument is true, and 0 otherwise. 18 | 19 | 20 | 21 | #include 22 | #include "MRFEnergy.h" 23 | 24 | void testPotts() 25 | { 26 | MRFEnergy* mrf; 27 | MRFEnergy::NodeId* nodes; 28 | MRFEnergy::Options options; 29 | TypePotts::REAL energy, lowerBound; 30 | 31 | const int nodeNum = 2; // number of nodes 32 | const int K = 3; // number of labels 33 | TypePotts::REAL D[K]; 34 | int x, y; 35 | 36 | mrf = new MRFEnergy(TypePotts::GlobalSize(K)); 37 | nodes = new MRFEnergy::NodeId[nodeNum]; 38 | 39 | // construct energy 40 | D[0] = 0; D[1] = 1; D[2] = 2; 41 | nodes[0] = mrf->AddNode(TypePotts::LocalSize(), TypePotts::NodeData(D)); 42 | D[0] = 3; D[1] = 4; D[2] = 5; 43 | nodes[1] = mrf->AddNode(TypePotts::LocalSize(), TypePotts::NodeData(D)); 44 | mrf->AddEdge(nodes[0], nodes[1], TypePotts::EdgeData(6)); 45 | 46 | // Function below is optional - it may help if, for example, nodes are added in a random order 47 | // mrf->SetAutomaticOrdering(); 48 | 49 | /////////////////////// TRW-S algorithm ////////////////////// 50 | options.m_iterMax = 30; // maximum number of iterations 51 | mrf->Minimize_TRW_S(options, lowerBound, energy); 52 | 53 | // read solution 54 | x = mrf->GetSolution(nodes[0]); 55 | y = mrf->GetSolution(nodes[1]); 56 | 57 | printf("Solution: %d %d\n", x, y); 58 | 59 | //////////////////////// BP algorithm //////////////////////// 60 | mrf->ZeroMessages(); // in general not necessary - it may be faster to start 61 | // with messages computed in previous iterations 62 | 63 | options.m_iterMax = 30; // maximum number of iterations 64 | mrf->Minimize_BP(options, energy); 65 | 66 | // read solution 67 | x = mrf->GetSolution(nodes[0]); 68 | y = mrf->GetSolution(nodes[1]); 69 | 70 | printf("Solution: %d %d\n", x, y); 71 | 72 | // done 73 | delete nodes; 74 | delete mrf; 75 | } 76 | 77 | *******************************************************************/ 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | #ifndef __TYPEPOTTS_H__ 97 | #define __TYPEPOTTS_H__ 98 | 99 | #include 100 | #include 101 | 102 | 103 | template class MRFEnergy; 104 | 105 | 106 | class TypePotts 107 | { 108 | private: 109 | struct Vector; // node parameters and messages 110 | struct Edge; // stores edge information and either forward or backward message 111 | 112 | public: 113 | // types declarations 114 | typedef int Label; 115 | typedef double REAL; 116 | struct GlobalSize; // global information about number of labels 117 | struct LocalSize; // local information about number of labels (stored at each node) 118 | struct NodeData; // argument to MRFEnergy::AddNode() 119 | struct EdgeData; // argument to MRFEnergy::AddEdge() 120 | 121 | 122 | struct GlobalSize 123 | { 124 | GlobalSize(int K); 125 | 126 | private: 127 | friend struct Vector; 128 | friend struct Edge; 129 | int m_K; // number of labels 130 | }; 131 | 132 | struct LocalSize // number of labels is stored at MRFEnergy::m_Kglobal 133 | { 134 | }; 135 | 136 | struct NodeData 137 | { 138 | NodeData(REAL* data); // data = pointer to array of size MRFEnergy::m_Kglobal 139 | 140 | private: 141 | friend struct Vector; 142 | friend struct Edge; 143 | REAL* m_data; 144 | }; 145 | 146 | struct EdgeData 147 | { 148 | EdgeData(REAL lambdaPotts); 149 | 150 | private: 151 | friend struct Vector; 152 | friend struct Edge; 153 | REAL m_lambdaPotts; 154 | }; 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | ////////////////////////////////////////////////////////////////////////////////// 163 | ////////////////////////// Visible only to MRFEnergy ///////////////////////////// 164 | ////////////////////////////////////////////////////////////////////////////////// 165 | 166 | private: 167 | friend class MRFEnergy; 168 | 169 | struct Vector 170 | { 171 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize K); // returns -1 if invalid K's 172 | void Initialize(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user adds a node 173 | void Add(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user calls MRFEnergy::AddNodeData() 174 | 175 | void SetZero(GlobalSize Kglobal, LocalSize K); // set this[k] = 0 176 | void Copy(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = V[k] 177 | void Add(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = this[k] + V[k] 178 | REAL GetValue(GlobalSize Kglobal, LocalSize K, Label k); // return this[k] 179 | REAL ComputeMin(GlobalSize Kglobal, LocalSize K, Label& kMin); // return vMin = min_k { this[k] }, set kMin 180 | REAL ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K); // same as previous, but additionally set this[k] -= vMin (and kMin is not returned) 181 | 182 | static int GetArraySize(GlobalSize Kglobal, LocalSize K); 183 | REAL GetArrayValue(GlobalSize Kglobal, LocalSize K, int k); // note: k is an integer in [0..GetArraySize()-1]. 184 | // For Potts functions GetArrayValue() and GetValue() are the same, 185 | // but they are different for, say, 2-dimensional labels. 186 | void SetArrayValue(GlobalSize Kglobal, LocalSize K, int k, REAL x); 187 | 188 | private: 189 | friend struct Edge; 190 | REAL m_data[1]; // actual size is MRFEnergy::m_Kglobal 191 | }; 192 | 193 | struct Edge 194 | { 195 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data); // returns -1 if invalid data 196 | static int GetBufSizeInBytes(int vectorMaxSizeInBytes); // returns size of buffer need for UpdateMessage() 197 | void Initialize(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data, Vector* Di, Vector* Dj); // called once when user adds an edge 198 | Vector* GetMessagePtr(); 199 | void Swap(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj); // if the client calls this function, then the meaning of 'dir' 200 | // in distance transform functions is swapped 201 | 202 | // When UpdateMessage() is called, edge contains message from dest to source. 203 | // The function must replace it with the message from source to dest. 204 | // The update rule is given below assuming that source corresponds to tail (i) and dest corresponds 205 | // to head (j) (which is the case if dir==0). 206 | // 207 | // 1. Compute Di[ki] = gamma*source[ki] - message[ki]. (Note: message = message from j to i). 208 | // 2. Compute distance transform: set 209 | // message[kj] = min_{ki} (Di[ki] + V(ki,kj)). (Note: message = message from i to j). 210 | // 3. Compute vMin = min_{kj} m_message[kj]. 211 | // 4. Set m_message[kj] -= vMin. 212 | // 5. Return vMin. 213 | // 214 | // If dir==1 then source corresponds to j, sink corresponds to i. Then the update rule is 215 | // 216 | // 1. Compute Dj[kj] = gamma*source[kj] - message[kj]. (Note: message = message from i to j). 217 | // 2. Compute distance transform: set 218 | // message[ki] = min_{kj} (Dj[kj] + V(ki,kj)). (Note: message = message from j to i). 219 | // 3. Compute vMin = min_{ki} m_message[ki]. 220 | // 4. Set m_message[ki] -= vMin. 221 | // 5. Return vMin. 222 | // 223 | // If Edge::Swap has been called odd number of times, then the meaning of dir is swapped. 224 | // 225 | // Vector 'source' must not be modified. Function may use 'buf' as a temporary storage. 226 | REAL UpdateMessage(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Vector* source, REAL gamma, int dir, void* buf); 227 | 228 | // If dir==0, then sets dest[kj] += V(ksource,kj). 229 | // If dir==1, then sets dest[ki] += V(ki,ksource). 230 | // If Swap() has been called odd number of times, then the meaning of dir is swapped. 231 | void AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir); 232 | 233 | private: 234 | // edge information 235 | REAL m_lambdaPotts; 236 | 237 | // message 238 | Vector m_message; 239 | }; 240 | }; 241 | 242 | 243 | 244 | 245 | ////////////////////////////////////////////////////////////////////////////////// 246 | /////////////////////////////// Implementation /////////////////////////////////// 247 | ////////////////////////////////////////////////////////////////////////////////// 248 | 249 | 250 | inline TypePotts::GlobalSize::GlobalSize(int K) 251 | { 252 | m_K = K; 253 | } 254 | 255 | ///////////////////// NodeData and EdgeData /////////////////////// 256 | 257 | inline TypePotts::NodeData::NodeData(REAL* data) 258 | { 259 | m_data = data; 260 | } 261 | 262 | inline TypePotts::EdgeData::EdgeData(REAL lambdaPotts) 263 | { 264 | m_lambdaPotts = lambdaPotts; 265 | } 266 | 267 | ///////////////////// Vector /////////////////////// 268 | 269 | inline int TypePotts::Vector::GetSizeInBytes(GlobalSize Kglobal, LocalSize K) 270 | { 271 | if (Kglobal.m_K < 1) 272 | { 273 | return -1; 274 | } 275 | return Kglobal.m_K*sizeof(REAL); 276 | } 277 | inline void TypePotts::Vector::Initialize(GlobalSize Kglobal, LocalSize K, NodeData data) 278 | { 279 | memcpy(m_data, data.m_data, Kglobal.m_K*sizeof(REAL)); 280 | } 281 | 282 | inline void TypePotts::Vector::Add(GlobalSize Kglobal, LocalSize K, NodeData data) 283 | { 284 | for (int k=0; km_data, Kglobal.m_K*sizeof(REAL)); 298 | } 299 | 300 | inline void TypePotts::Vector::Add(GlobalSize Kglobal, LocalSize K, Vector* V) 301 | { 302 | for (int k=0; km_data[k]; 305 | } 306 | } 307 | 308 | inline TypePotts::REAL TypePotts::Vector::GetValue(GlobalSize Kglobal, LocalSize K, Label k) 309 | { 310 | assert(k>=0 && k m_data[k]) 321 | { 322 | vMin = m_data[k]; 323 | kMin = k; 324 | } 325 | } 326 | 327 | return vMin; 328 | } 329 | 330 | inline TypePotts::REAL TypePotts::Vector::ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K) 331 | { 332 | REAL vMin = m_data[0]; 333 | for (int k=1; k m_data[k]) 336 | { 337 | vMin = m_data[k]; 338 | } 339 | } 340 | for (int k=0; k=0 && k=0 && km_data[0] - m_message.m_data[0]; 402 | vMin = m_message.m_data[0]; 403 | 404 | for (k=1; km_data[k] - m_message.m_data[k]; 407 | if (vMin > m_message.m_data[k]) 408 | { 409 | vMin = m_message.m_data[k]; 410 | } 411 | } 412 | 413 | for (k=0; k m_lambdaPotts) 417 | { 418 | m_message.m_data[k] = m_lambdaPotts; 419 | } 420 | } 421 | 422 | return vMin; 423 | } 424 | 425 | inline void TypePotts::Edge::AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir) 426 | { 427 | assert(ksource>=0 && ksourcem_data[k] += m_lambdaPotts; 434 | } 435 | for (k++; km_data[k] += m_lambdaPotts; 438 | } 439 | } 440 | 441 | ////////////////////////////////////////////////////////////////////////////////// 442 | 443 | #endif 444 | -------------------------------------------------------------------------------- /TRW_S/typeTruncatedLinear.h: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | typeTruncatedLinear.h 3 | 4 | Energy function with truncated linear interactions: 5 | E(x) = \sum_i D_i(x_i) + \sum_ij V_ij(x_i,x_j) 6 | where x_i \in {0, 1, ..., K-1}, 7 | V_ij(ki, kj) = min { alpha_ij*|ki-kj|, lambda_ij }. 8 | alpha_ij and lambda_ij must be non-negative. 9 | 10 | Example usage: 11 | 12 | Minimize function E(x,y) = Dx(x) + Dy(y) + min { alpha*|x - y| , lambda } where 13 | x,y \in {0,1,2}, 14 | Dx(0) = 0, Dx(1) = 1, Dx(2) = 2, 15 | Dy(0) = 3, Dy(1) = 4, Dy(2) = 5, 16 | alpha = 6, 17 | lambda = 7 18 | 19 | 20 | 21 | 22 | #include 23 | #include "MRFEnergy.h" 24 | 25 | void testTruncatedLinear() 26 | { 27 | MRFEnergy* mrf; 28 | MRFEnergy::NodeId* nodes; 29 | MRFEnergy::Options options; 30 | TypeTruncatedLinear::REAL energy, lowerBound; 31 | 32 | const int nodeNum = 2; // number of nodes 33 | const int K = 3; // number of labels 34 | TypeTruncatedLinear::REAL D[K]; 35 | int x, y; 36 | 37 | mrf = new MRFEnergy(TypeTruncatedLinear::GlobalSize(K)); 38 | nodes = new MRFEnergy::NodeId[nodeNum]; 39 | 40 | // construct energy 41 | D[0] = 0; D[1] = 1; D[2] = 2; 42 | nodes[0] = mrf->AddNode(TypeTruncatedLinear::LocalSize(), TypeTruncatedLinear::NodeData(D)); 43 | D[0] = 3; D[1] = 4; D[2] = 5; 44 | nodes[1] = mrf->AddNode(TypeTruncatedLinear::LocalSize(), TypeTruncatedLinear::NodeData(D)); 45 | mrf->AddEdge(nodes[0], nodes[1], TypeTruncatedLinear::EdgeData(6, 7)); 46 | 47 | // Function below is optional - it may help if, for example, nodes are added in a random order 48 | // mrf->SetAutomaticOrdering(); 49 | 50 | /////////////////////// TRW-S algorithm ////////////////////// 51 | options.m_iterMax = 30; // maximum number of iterations 52 | mrf->Minimize_TRW_S(options, lowerBound, energy); 53 | 54 | // read solution 55 | x = mrf->GetSolution(nodes[0]); 56 | y = mrf->GetSolution(nodes[1]); 57 | 58 | printf("Solution: %d %d\n", x, y); 59 | 60 | //////////////////////// BP algorithm //////////////////////// 61 | mrf->ZeroMessages(); // in general not necessary - it may be faster to start 62 | // with messages computed in previous iterations 63 | 64 | options.m_iterMax = 30; // maximum number of iterations 65 | mrf->Minimize_BP(options, energy); 66 | 67 | // read solution 68 | x = mrf->GetSolution(nodes[0]); 69 | y = mrf->GetSolution(nodes[1]); 70 | 71 | printf("Solution: %d %d\n", x, y); 72 | 73 | // done 74 | delete nodes; 75 | delete mrf; 76 | } 77 | 78 | *******************************************************************/ 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | #ifndef __TYPETRUNCATEDLINEAR_H__ 98 | #define __TYPETRUNCATEDLINEAR_H__ 99 | 100 | #include 101 | #include 102 | 103 | 104 | template class MRFEnergy; 105 | 106 | 107 | class TypeTruncatedLinear 108 | { 109 | private: 110 | struct Vector; // node parameters and messages 111 | struct Edge; // stores edge information and either forward or backward message 112 | 113 | public: 114 | // types declarations 115 | typedef int Label; 116 | typedef double REAL; 117 | struct GlobalSize; // global information about number of labels 118 | struct LocalSize; // local information about number of labels (stored at each node) 119 | struct NodeData; // argument to MRFEnergy::AddNode() 120 | struct EdgeData; // argument to MRFEnergy::AddEdge() 121 | 122 | 123 | struct GlobalSize 124 | { 125 | GlobalSize(int K); 126 | 127 | private: 128 | friend struct Vector; 129 | friend struct Edge; 130 | int m_K; // number of labels 131 | }; 132 | 133 | struct LocalSize // number of labels is stored at MRFEnergy::m_Kglobal 134 | { 135 | }; 136 | 137 | struct NodeData 138 | { 139 | NodeData(REAL* data); // data = pointer to array of size MRFEnergy::m_Kglobal 140 | 141 | private: 142 | friend struct Vector; 143 | friend struct Edge; 144 | REAL* m_data; 145 | }; 146 | 147 | struct EdgeData 148 | { 149 | EdgeData(REAL alpha, REAL lambda); 150 | 151 | private: 152 | friend struct Vector; 153 | friend struct Edge; 154 | REAL m_alpha; 155 | REAL m_lambda; 156 | }; 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | ////////////////////////////////////////////////////////////////////////////////// 165 | ////////////////////////// Visible only to MRFEnergy ///////////////////////////// 166 | ////////////////////////////////////////////////////////////////////////////////// 167 | 168 | private: 169 | friend class MRFEnergy; 170 | 171 | struct Vector 172 | { 173 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize K); // returns -1 if invalid K's 174 | void Initialize(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user adds a node 175 | void Add(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user calls MRFEnergy::AddNodeData() 176 | 177 | void SetZero(GlobalSize Kglobal, LocalSize K); // set this[k] = 0 178 | void Copy(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = V[k] 179 | void Add(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = this[k] + V[k] 180 | REAL GetValue(GlobalSize Kglobal, LocalSize K, Label k); // return this[k] 181 | REAL ComputeMin(GlobalSize Kglobal, LocalSize K, Label& kMin); // return vMin = min_k { this[k] }, set kMin 182 | REAL ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K); // same as previous, but additionally set this[k] -= vMin (and kMin is not returned) 183 | 184 | static int GetArraySize(GlobalSize Kglobal, LocalSize K); 185 | REAL GetArrayValue(GlobalSize Kglobal, LocalSize K, int k); // note: k is an integer in [0..GetArraySize()-1]. 186 | // For Potts functions GetArrayValue() and GetValue() are the same, 187 | // but they are different for, say, 2-dimensional labels. 188 | void SetArrayValue(GlobalSize Kglobal, LocalSize K, int k, REAL x); 189 | 190 | private: 191 | friend struct Edge; 192 | REAL m_data[1]; // actual size is MRFEnergy::m_Kglobal 193 | }; 194 | 195 | struct Edge 196 | { 197 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data); // returns -1 if invalid data 198 | static int GetBufSizeInBytes(int vectorMaxSizeInBytes); // returns size of buffer need for UpdateMessage() 199 | void Initialize(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data, Vector* Di, Vector* Dj); // called once when user adds an edge 200 | Vector* GetMessagePtr(); 201 | void Swap(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj); // if the client calls this function, then the meaning of 'dir' 202 | // in distance transform functions is swapped 203 | 204 | // When UpdateMessage() is called, edge contains message from dest to source. 205 | // The function must replace it with the message from source to dest. 206 | // The update rule is given below assuming that source corresponds to tail (i) and dest corresponds 207 | // to head (j) (which is the case if dir==0). 208 | // 209 | // 1. Compute Di[ki] = gamma*source[ki] - message[ki]. (Note: message = message from j to i). 210 | // 2. Compute distance transform: set 211 | // message[kj] = min_{ki} (Di[ki] + V(ki,kj)). (Note: message = message from i to j). 212 | // 3. Compute vMin = min_{kj} m_message[kj]. 213 | // 4. Set m_message[kj] -= vMin. 214 | // 5. Return vMin. 215 | // 216 | // If dir==1 then source corresponds to j, sink corresponds to i. Then the update rule is 217 | // 218 | // 1. Compute Dj[kj] = gamma*source[kj] - message[kj]. (Note: message = message from i to j). 219 | // 2. Compute distance transform: set 220 | // message[ki] = min_{kj} (Dj[kj] + V(ki,kj)). (Note: message = message from j to i). 221 | // 3. Compute vMin = min_{ki} m_message[ki]. 222 | // 4. Set m_message[ki] -= vMin. 223 | // 5. Return vMin. 224 | // 225 | // If Edge::Swap has been called odd number of times, then the meaning of dir is swapped. 226 | // 227 | // Vector 'source' must not be modified. Function may use 'buf' as a temporary storage. 228 | REAL UpdateMessage(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Vector* source, REAL gamma, int dir, void* buf); 229 | 230 | // If dir==0, then sets dest[kj] += V(ksource,kj). 231 | // If dir==1, then sets dest[ki] += V(ki,ksource). 232 | // If Swap() has been called odd number of times, then the meaning of dir is swapped. 233 | void AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir); 234 | 235 | private: 236 | // edge information 237 | REAL m_alpha; 238 | REAL m_lambda; 239 | 240 | // message 241 | Vector m_message; 242 | }; 243 | }; 244 | 245 | 246 | 247 | 248 | ////////////////////////////////////////////////////////////////////////////////// 249 | /////////////////////////////// Implementation /////////////////////////////////// 250 | ////////////////////////////////////////////////////////////////////////////////// 251 | 252 | 253 | inline TypeTruncatedLinear::GlobalSize::GlobalSize(int K) 254 | { 255 | m_K = K; 256 | } 257 | 258 | ///////////////////// NodeData and EdgeData /////////////////////// 259 | 260 | inline TypeTruncatedLinear::NodeData::NodeData(REAL* data) 261 | { 262 | m_data = data; 263 | } 264 | 265 | inline TypeTruncatedLinear::EdgeData::EdgeData(REAL alpha, REAL lambda) 266 | { 267 | m_alpha = alpha; 268 | m_lambda = lambda; 269 | } 270 | 271 | ///////////////////// Vector /////////////////////// 272 | 273 | inline int TypeTruncatedLinear::Vector::GetSizeInBytes(GlobalSize Kglobal, LocalSize K) 274 | { 275 | if (Kglobal.m_K < 1) 276 | { 277 | return -1; 278 | } 279 | return Kglobal.m_K*sizeof(REAL); 280 | } 281 | inline void TypeTruncatedLinear::Vector::Initialize(GlobalSize Kglobal, LocalSize K, NodeData data) 282 | { 283 | memcpy(m_data, data.m_data, Kglobal.m_K*sizeof(REAL)); 284 | } 285 | 286 | inline void TypeTruncatedLinear::Vector::Add(GlobalSize Kglobal, LocalSize K, NodeData data) 287 | { 288 | for (int k=0; km_data, Kglobal.m_K*sizeof(REAL)); 302 | } 303 | 304 | inline void TypeTruncatedLinear::Vector::Add(GlobalSize Kglobal, LocalSize K, Vector* V) 305 | { 306 | for (int k=0; km_data[k]; 309 | } 310 | } 311 | 312 | inline TypeTruncatedLinear::REAL TypeTruncatedLinear::Vector::GetValue(GlobalSize Kglobal, LocalSize K, Label k) 313 | { 314 | assert(k>=0 && k m_data[k]) 325 | { 326 | vMin = m_data[k]; 327 | kMin = k; 328 | } 329 | } 330 | 331 | return vMin; 332 | } 333 | 334 | inline TypeTruncatedLinear::REAL TypeTruncatedLinear::Vector::ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K) 335 | { 336 | REAL vMin = m_data[0]; 337 | for (int k=1; k m_data[k]) 340 | { 341 | vMin = m_data[k]; 342 | } 343 | } 344 | for (int k=0; k=0 && k=0 && km_data[0] - m_message.m_data[0]; 407 | vMin = m_message.m_data[0]; 408 | 409 | for (k=1; km_data[k] - m_message.m_data[k]; 412 | if (m_message.m_data[k] > m_message.m_data[k-1] + m_alpha) 413 | { 414 | m_message.m_data[k] = m_message.m_data[k-1] + m_alpha; 415 | } 416 | else if (vMin > m_message.m_data[k]) 417 | { 418 | vMin = m_message.m_data[k]; 419 | } 420 | } 421 | 422 | k--; 423 | m_message.m_data[k] -= vMin; 424 | if (m_message.m_data[k] > m_lambda) 425 | { 426 | m_message.m_data[k] = m_lambda; 427 | } 428 | 429 | for (k--; k>=0; k--) 430 | { 431 | m_message.m_data[k] -= vMin; 432 | if (m_message.m_data[k] > m_message.m_data[k+1] + m_alpha) 433 | { 434 | m_message.m_data[k] = m_message.m_data[k+1] + m_alpha; 435 | } 436 | if (m_message.m_data[k] > m_lambda) 437 | { 438 | m_message.m_data[k] = m_lambda; 439 | } 440 | } 441 | 442 | return vMin; 443 | } 444 | 445 | inline void TypeTruncatedLinear::Edge::AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir) 446 | { 447 | assert(ksource>=0 && ksourcem_data[k] += (ksource-k)*m_alpha < m_lambda ? (ksource-k)*m_alpha : m_lambda; 454 | } 455 | for (k++; km_data[k] += m_alpha*(k-ksource) < m_lambda ? m_alpha*(k-ksource) : m_lambda; 458 | } 459 | } 460 | 461 | ////////////////////////////////////////////////////////////////////////////////// 462 | 463 | #endif 464 | -------------------------------------------------------------------------------- /cv_utils/ImageOperations.cpp: -------------------------------------------------------------------------------- 1 | #include "cv_utils.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace cv; 8 | 9 | namespace cv_utils 10 | { 11 | 12 | template Mat drawValuesOnImage(const vector &values, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const Func &func) 13 | { 14 | Mat image(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC1); 15 | for (int y = 0; y < IMAGE_HEIGHT; y++) { 16 | for (int x = 0; x < IMAGE_WIDTH; x++) { 17 | int color = round(func(values[y * IMAGE_WIDTH + x])); 18 | image.at(y, x) = max(min(color, 255), 0); 19 | } 20 | } 21 | return image; 22 | } 23 | 24 | vector calcBoxIntegrationMask(const vector &values, const int IMAGE_WIDTH, const int IMAGE_HEIGHT) 25 | { 26 | vector mask = values; 27 | for (int y = 0; y < IMAGE_HEIGHT; y++) 28 | for (int x = 1; x < IMAGE_WIDTH; x++) 29 | mask[y * IMAGE_WIDTH + x] += mask[y * IMAGE_WIDTH + (x - 1)]; 30 | for (int x = 0; x < IMAGE_WIDTH; x++) 31 | for (int y = 1; y < IMAGE_HEIGHT; y++) 32 | mask[y * IMAGE_WIDTH + x] += mask[(y - 1) * IMAGE_WIDTH + x]; 33 | return mask; 34 | } 35 | 36 | double calcBoxIntegration(const vector &mask, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const int x_1, const int y_1, const int x_2, const int y_2) 37 | { 38 | int min_x = min(x_1, x_2) - 1; 39 | int min_y = min(y_1, y_2) - 1; 40 | int max_x = min(max(x_1, x_2), IMAGE_WIDTH - 1); 41 | int max_y = min(max(y_1, y_2), IMAGE_HEIGHT - 1); 42 | double value_1 = (min_x >= 0 && min_y >= 0) ? mask[min_y * IMAGE_WIDTH + min_x] : 0; 43 | double value_2 = min_x >= 0 ? mask[max_y * IMAGE_WIDTH + min_x] : 0; 44 | double value_3 = min_y >= 0 ? mask[min_y * IMAGE_WIDTH + max_x] : 0; 45 | double value_4 = mask[max_y * IMAGE_WIDTH + max_x]; 46 | return (value_1 + value_4) - (value_2 + value_3); 47 | } 48 | 49 | void calcWindowMeansAndVars(const std::vector &values, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const int WINDOW_SIZE, vector &means, vector &vars) 50 | { 51 | vector sum_mask = calcBoxIntegrationMask(values, IMAGE_WIDTH, IMAGE_HEIGHT); 52 | vector values2(IMAGE_WIDTH * IMAGE_HEIGHT); 53 | transform(values.begin(), values.end(), values2.begin(), [](const double &x) { return pow(x, 2); }); 54 | vector sum2_mask = calcBoxIntegrationMask(values2, IMAGE_WIDTH, IMAGE_HEIGHT); 55 | means.assign(IMAGE_WIDTH * IMAGE_HEIGHT, 0); 56 | vars.assign(IMAGE_WIDTH * IMAGE_HEIGHT, 0); 57 | for (int pixel = 0; pixel < IMAGE_WIDTH * IMAGE_HEIGHT; pixel++) { 58 | int x_1 = pixel % IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2; 59 | int y_1 = pixel / IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2; 60 | int x_2 = pixel % IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2; 61 | int y_2 = pixel / IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2; 62 | int area = (min(pixel % IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2, IMAGE_WIDTH - 1) - max(pixel % IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2, 0) + 1) * (min(pixel / IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2, IMAGE_HEIGHT - 1) - max(pixel / IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2, 0) + 1); 63 | double mean = calcBoxIntegration(sum_mask, IMAGE_WIDTH, IMAGE_HEIGHT, x_1, y_1, x_2, y_2) / area; 64 | double var = calcBoxIntegration(sum2_mask, IMAGE_WIDTH, IMAGE_HEIGHT, x_1, y_1, x_2, y_2) / area - pow(mean, 2); 65 | means[pixel] = mean; 66 | vars[pixel] = var; 67 | } 68 | } 69 | 70 | void calcWindowMeansAndVars(const std::vector > &values, const int IMAGE_WIDTH, const int IMAGE_HEIGHT, const int WINDOW_SIZE, vector > &means, vector > &vars) 71 | { 72 | const int NUM_CHANNELS = values.size(); 73 | vector > sum_masks(NUM_CHANNELS); 74 | for (int c = 0; c < NUM_CHANNELS; c++) 75 | sum_masks[c] = calcBoxIntegrationMask(values[c], IMAGE_WIDTH, IMAGE_HEIGHT); 76 | vector > values2(NUM_CHANNELS * NUM_CHANNELS, vector(IMAGE_WIDTH * IMAGE_HEIGHT)); 77 | for (int c_1 = 0; c_1 < NUM_CHANNELS; c_1++) 78 | for (int c_2 = 0; c_2 < NUM_CHANNELS; c_2++) 79 | transform(values[c_1].begin(), values[c_1].end(), values[c_2].begin(), values2[c_1 * NUM_CHANNELS + c_2].begin(), [](const double &x, const double &y) { return x * y; }); 80 | vector > sum2_masks(NUM_CHANNELS * NUM_CHANNELS); 81 | for (int c_1 = 0; c_1 < NUM_CHANNELS; c_1++) 82 | for (int c_2 = 0; c_2 < NUM_CHANNELS; c_2++) 83 | sum2_masks[c_1 * NUM_CHANNELS + c_2] = calcBoxIntegrationMask(values2[c_1 * NUM_CHANNELS + c_2], IMAGE_WIDTH, IMAGE_HEIGHT); 84 | 85 | means.assign(NUM_CHANNELS, vector(IMAGE_WIDTH * IMAGE_HEIGHT)); 86 | vars.assign(NUM_CHANNELS * NUM_CHANNELS, vector(IMAGE_WIDTH * IMAGE_HEIGHT)); 87 | for (int pixel = 0; pixel < IMAGE_WIDTH * IMAGE_HEIGHT; pixel++) { 88 | int x_1 = pixel % IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2; 89 | int y_1 = pixel / IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2; 90 | int x_2 = pixel % IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2; 91 | int y_2 = pixel / IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2; 92 | int area = (min(pixel % IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2, IMAGE_WIDTH - 1) - max(pixel % IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2, 0) + 1) * (min(pixel / IMAGE_WIDTH + (WINDOW_SIZE - 1) / 2, IMAGE_HEIGHT - 1) - max(pixel / IMAGE_WIDTH - (WINDOW_SIZE - 1) / 2, 0) + 1); 93 | vector mean(NUM_CHANNELS); 94 | for (int c = 0; c < NUM_CHANNELS; c++) 95 | mean[c] = calcBoxIntegration(sum_masks[c], IMAGE_WIDTH, IMAGE_HEIGHT, x_1, y_1, x_2, y_2) / area; 96 | vector var(NUM_CHANNELS * NUM_CHANNELS); 97 | for (int c_1 = 0; c_1 < NUM_CHANNELS; c_1++) 98 | for (int c_2 = 0; c_2 < NUM_CHANNELS; c_2++) 99 | var[c_1 * NUM_CHANNELS + c_2] = calcBoxIntegration(sum2_masks[c_1 * NUM_CHANNELS + c_2], IMAGE_WIDTH, IMAGE_HEIGHT, x_1, y_1, x_2, y_2) / area - mean[c_1] * mean[c_2]; 100 | for (int c = 0; c < NUM_CHANNELS; c++) 101 | means[c][pixel] = mean[c]; 102 | for (int c_1 = 0; c_1 < NUM_CHANNELS; c_1++) 103 | for (int c_2 = 0; c_2 < NUM_CHANNELS; c_2++) 104 | vars[c_1 * NUM_CHANNELS + c_2][pixel] = var[c_1 * NUM_CHANNELS + c_2]; 105 | } 106 | } 107 | 108 | void guidedFilter(const cv::Mat &guidance_image, const cv::Mat &input_image, cv::Mat &output_image, const double radius, const double epsilon) 109 | { 110 | const int IMAGE_WIDTH = guidance_image.cols; 111 | const int IMAGE_HEIGHT = guidance_image.rows; 112 | const int NUM_PIXELS = IMAGE_WIDTH * IMAGE_HEIGHT; 113 | if (guidance_image.channels() == 1 && input_image.channels() == 1) { 114 | vector guidance_image_values(NUM_PIXELS); 115 | vector input_image_values(NUM_PIXELS); 116 | vector guidance_image_input_image_values(NUM_PIXELS); 117 | for (int y = 0; y < IMAGE_HEIGHT; y++) { 118 | for (int x = 0; x < IMAGE_WIDTH; x++) { 119 | int pixel = y * IMAGE_WIDTH + x; 120 | guidance_image_values[pixel] = 1.0 * guidance_image.at(y, x) / 256; 121 | input_image_values[pixel] = 1.0 * input_image.at(y, x) / 256; 122 | guidance_image_input_image_values[pixel] = (1.0 * guidance_image.at(y, x) / 256) * (1.0 * input_image.at(y, x) / 256); 123 | } 124 | } 125 | vector guidance_image_means; 126 | vector guidance_image_vars; 127 | calcWindowMeansAndVars(guidance_image_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, guidance_image_means, guidance_image_vars); 128 | vector input_image_means; 129 | vector dummy_vars; 130 | calcWindowMeansAndVars(input_image_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, input_image_means, dummy_vars); 131 | vector guidance_image_input_image_means; 132 | calcWindowMeansAndVars(guidance_image_input_image_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, guidance_image_input_image_means, dummy_vars); 133 | 134 | vector a_values(NUM_PIXELS); 135 | vector b_values(NUM_PIXELS); 136 | for (int pixel = 0; pixel < IMAGE_WIDTH * IMAGE_HEIGHT; pixel++) { 137 | a_values[pixel] = (guidance_image_input_image_means[pixel] - guidance_image_means[pixel] * input_image_means[pixel]) / (guidance_image_vars[pixel] + epsilon); 138 | b_values[pixel] = input_image_means[pixel] - a_values[pixel] * guidance_image_means[pixel]; 139 | } 140 | 141 | vector a_means; 142 | vector b_means; 143 | calcWindowMeansAndVars(a_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, a_means, dummy_vars); 144 | calcWindowMeansAndVars(b_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, b_means, dummy_vars); 145 | 146 | output_image = Mat(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC1); 147 | for (int y = 0; y < IMAGE_HEIGHT; y++) { 148 | for (int x = 0; x < IMAGE_WIDTH; x++) { 149 | int pixel = y * IMAGE_WIDTH + x; 150 | output_image.at(y, x) = max(min((a_means[pixel] * input_image_values[pixel] + b_means[pixel]) * 256, 255.0), 0.0); 151 | } 152 | } 153 | } else if (guidance_image.channels() == 3 && input_image.channels() == 3) { 154 | vector > guidance_image_values(3, vector(NUM_PIXELS)); 155 | vector > input_image_values(3, vector(NUM_PIXELS)); 156 | vector > guidance_image_input_image_values(3, vector(NUM_PIXELS)); 157 | for (int y = 0; y < IMAGE_HEIGHT; y++) { 158 | for (int x = 0; x < IMAGE_WIDTH; x++) { 159 | int pixel = y * IMAGE_WIDTH + x; 160 | Vec3b guidance_image_color = guidance_image.at(y, x); 161 | Vec3b input_image_color = input_image.at(y, x); 162 | for (int c = 0; c < 3; c++) { 163 | guidance_image_values[c][pixel] = 1.0 * guidance_image_color[c] / 256; 164 | input_image_values[c][pixel] = 1.0 * input_image_color[c] / 256; 165 | guidance_image_input_image_values[c][pixel] = (1.0 * guidance_image_color[c] / 256) * (1.0 * input_image_color[c] / 256); 166 | } 167 | } 168 | } 169 | vector > guidance_image_means(3); 170 | vector > guidance_image_vars(3); 171 | vector > input_image_means(3); 172 | vector > guidance_image_input_image_means(3); 173 | for (int c = 0; c < 3; c++) { 174 | vector dummy_vars; 175 | calcWindowMeansAndVars(guidance_image_values[c], IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, guidance_image_means[c], guidance_image_vars[c]); 176 | calcWindowMeansAndVars(input_image_values[c], IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, input_image_means[c], dummy_vars); 177 | calcWindowMeansAndVars(guidance_image_input_image_values[c], IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, guidance_image_input_image_means[c], dummy_vars); 178 | } 179 | 180 | vector a_values(NUM_PIXELS); 181 | vector > b_values(3, vector(NUM_PIXELS)); 182 | for (int pixel = 0; pixel < IMAGE_WIDTH * IMAGE_HEIGHT; pixel++) { 183 | double guidance_image_input_image_covariance = 0; 184 | double guidance_image_var = 0; 185 | for (int c = 0; c < 3; c++) { 186 | guidance_image_input_image_covariance += guidance_image_input_image_means[c][pixel] - guidance_image_means[c][pixel] * input_image_means[c][pixel]; 187 | guidance_image_var += guidance_image_vars[c][pixel]; 188 | } 189 | a_values[pixel] = guidance_image_input_image_covariance / (guidance_image_var + epsilon); 190 | for (int c = 0; c < 3; c++) 191 | b_values[c][pixel] = input_image_means[c][pixel] - a_values[pixel] * guidance_image_means[c][pixel]; 192 | } 193 | 194 | vector a_means; 195 | vector dummy_vars; 196 | calcWindowMeansAndVars(a_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, a_means, dummy_vars); 197 | vector > b_means(3); 198 | for (int c = 0; c < 3; c++) { 199 | calcWindowMeansAndVars(b_values[c], IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, b_means[c], dummy_vars); 200 | } 201 | 202 | output_image = Mat(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC3); 203 | for (int y = 0; y < IMAGE_HEIGHT; y++) { 204 | for (int x = 0; x < IMAGE_WIDTH; x++) { 205 | int pixel = y * IMAGE_WIDTH + x; 206 | Vec3b color; 207 | for (int c = 0; c < 3; c++) 208 | color[c] = max(min((a_means[pixel] * input_image_values[c][pixel] + b_means[c][pixel]) * 256, 255.0), 0.0); 209 | output_image.at(y, x) = color; 210 | } 211 | } 212 | } else if (guidance_image.channels() == 3 && input_image.channels() == 1) { 213 | vector > guidance_image_values(3, vector(NUM_PIXELS)); 214 | vector input_image_values(NUM_PIXELS); 215 | vector > guidance_image_input_image_values(3, vector(NUM_PIXELS)); 216 | for (int y = 0; y < IMAGE_HEIGHT; y++) { 217 | for (int x = 0; x < IMAGE_WIDTH; x++) { 218 | int pixel = y * IMAGE_WIDTH + x; 219 | Vec3b guidance_image_color = guidance_image.at(y, x); 220 | uchar input_image_color = input_image.at(y, x); 221 | input_image_values[pixel] = 1.0 * input_image_color / 256; 222 | for (int c = 0; c < 3; c++) { 223 | guidance_image_values[c][pixel] = 1.0 * guidance_image_color[c] / 256; 224 | guidance_image_input_image_values[c][pixel] = (1.0 * guidance_image_color[c] / 256) * (1.0 * input_image_color / 256); 225 | } 226 | } 227 | } 228 | vector > guidance_image_means; 229 | vector > guidance_image_vars; 230 | calcWindowMeansAndVars(guidance_image_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, guidance_image_means, guidance_image_vars); 231 | vector dummy_vars; 232 | vector input_image_means; 233 | calcWindowMeansAndVars(input_image_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, input_image_means, dummy_vars); 234 | vector > guidance_image_input_image_means(3); 235 | for (int c = 0; c < 3; c++) { 236 | calcWindowMeansAndVars(guidance_image_input_image_values[c], IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, guidance_image_input_image_means[c], dummy_vars); 237 | } 238 | 239 | vector > a_values(3, vector(NUM_PIXELS, 0)); 240 | vector b_values(NUM_PIXELS, 0); 241 | for (int pixel = 0; pixel < IMAGE_WIDTH * IMAGE_HEIGHT; pixel++) { 242 | vector guidance_image_input_image_covariance(3); 243 | vector > guidance_image_var(3, vector(3)); 244 | for (int c = 0; c < 3; c++) 245 | guidance_image_input_image_covariance[c] = guidance_image_input_image_means[c][pixel] - guidance_image_means[c][pixel] * input_image_means[pixel]; 246 | for (int c_1 = 0; c_1 < 3; c_1++) 247 | for (int c_2 = 0; c_2 < 3; c_2++) 248 | guidance_image_var[c_1][c_2] = guidance_image_vars[c_1 * 3 + c_2][pixel] + epsilon * (c_1 == c_2); 249 | 250 | vector > guidance_image_var_inverse = calcInverse(guidance_image_var); 251 | vector a_value(3, 0); 252 | for (int c_1 = 0; c_1 < 3; c_1++) 253 | for (int c_2 = 0; c_2 < 3; c_2++) 254 | a_value[c_1] += guidance_image_var_inverse[c_1][c_2] * guidance_image_input_image_covariance[c_2]; 255 | for (int c = 0; c < 3; c++) 256 | a_values[c][pixel] = a_value[c]; 257 | 258 | double b = input_image_means[pixel]; 259 | for (int c = 0; c < 3; c++) 260 | b -= a_value[c] * guidance_image_means[c][pixel]; 261 | b_values[pixel] = b; 262 | } 263 | 264 | vector > a_means(3); 265 | for (int c = 0; c < 3; c++) 266 | calcWindowMeansAndVars(a_values[c], IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, a_means[c], dummy_vars); 267 | vector b_means; 268 | calcWindowMeansAndVars(b_values, IMAGE_WIDTH, IMAGE_HEIGHT, radius * 2 + 1, b_means, dummy_vars); 269 | 270 | output_image = Mat(IMAGE_HEIGHT, IMAGE_WIDTH, CV_8UC1); 271 | for (int y = 0; y < IMAGE_HEIGHT; y++) { 272 | for (int x = 0; x < IMAGE_WIDTH; x++) { 273 | int pixel = y * IMAGE_WIDTH + x; 274 | double color = b_means[pixel]; 275 | for (int c = 0; c < 3; c++) 276 | color += a_means[c][pixel] * guidance_image_values[c][pixel]; 277 | output_image.at(y, x) = max(min(color * 256, 255.0), 0.0); 278 | } 279 | } 280 | } 281 | } 282 | } 283 | 284 | 285 | -------------------------------------------------------------------------------- /TRW_S/typeTruncatedLinear2D.h: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | typeTruncatedLinear2D.h 3 | 4 | Energy function with 2-dimensional truncated linear interactions: 5 | E(x) = \sum_i D_i(x_i) + \sum_ij V_ij(x_i,x_j) 6 | where x_i \in {0, 1, ..., KX-1} x {0, 1, ..., KY-1} 7 | (i.e. x_i = (x_i(1), x_i(2))). 8 | V_ij(ki, kj) = min { alpha1_ij*|ki(1)-kj(2)| + alpha2_ij*|ki(2)-kj(2)|, lambda_ij }. 9 | alpha1_ij, alpha2_ij and lambda_ij must be non-negative. 10 | 11 | Example usage: 12 | 13 | Minimize function E(x,y) = Dx(x) + Dy(y) + min { alpha1*|x(1) - y(1)| + alpha2*|x(2) - y(2)|, lambda } 14 | where 15 | x,y \in {0,1} x {0,1,2} 16 | Dx(0,0) = 0, Dx(0,1) = 1, Dx(0,2) = 2, 17 | Dx(1,0) = 3, Dx(1,1) = 4, Dx(1,2) = 5, 18 | Dy(y) = 0 for all y, 19 | alpha1 = 6, 20 | alpha2 = 7, 21 | lambda = 8 22 | 23 | 24 | 25 | 26 | #include 27 | #include "MRFEnergy.h" 28 | 29 | void testTruncatedLinear2D() 30 | { 31 | MRFEnergy* mrf; 32 | MRFEnergy::NodeId* nodes; 33 | MRFEnergy::Options options; 34 | TypeTruncatedLinear2D::REAL energy, lowerBound; 35 | 36 | const int nodeNum = 2; // number of nodes 37 | const int KX = 2; // label 38 | const int KY = 3; // dimensions 39 | const int K = KX*KY; // number of labels 40 | TypeTruncatedLinear2D::REAL D[K]; 41 | TypeTruncatedLinear2D::Label x, y; 42 | 43 | mrf = new MRFEnergy(TypeTruncatedLinear2D::GlobalSize(KX, KY)); 44 | nodes = new MRFEnergy::NodeId[nodeNum]; 45 | 46 | // construct energy 47 | D[0] = 0; D[1] = 1; D[2] = 2; 48 | D[3] = 3; D[4] = 4; D[5] = 5; 49 | nodes[0] = mrf->AddNode(TypeTruncatedLinear2D::LocalSize(), TypeTruncatedLinear2D::NodeData(D)); 50 | D[0] = 0; D[1] = 0; D[2] = 0; 51 | D[3] = 0; D[4] = 0; D[5] = 0; 52 | nodes[1] = mrf->AddNode(TypeTruncatedLinear2D::LocalSize(), TypeTruncatedLinear2D::NodeData(D)); 53 | mrf->AddEdge(nodes[0], nodes[1], TypeTruncatedLinear2D::EdgeData(6, 7, 8)); 54 | 55 | // Function below is optional - it may help if, for example, nodes are added in a random order 56 | // mrf->SetAutomaticOrdering(); 57 | 58 | /////////////////////// TRW-S algorithm ////////////////////// 59 | options.m_iterMax = 30; // maximum number of iterations 60 | mrf->Minimize_TRW_S(options, lowerBound, energy); 61 | 62 | // read solution 63 | x = mrf->GetSolution(nodes[0]); 64 | y = mrf->GetSolution(nodes[1]); 65 | 66 | printf("Solution: %d %d\n", x, y); 67 | 68 | //////////////////////// BP algorithm //////////////////////// 69 | mrf->ZeroMessages(); // in general not necessary - it may be faster to start 70 | // with messages computed in previous iterations 71 | 72 | options.m_iterMax = 30; // maximum number of iterations 73 | mrf->Minimize_BP(options, energy); 74 | 75 | // read solution 76 | x = mrf->GetSolution(nodes[0]); 77 | y = mrf->GetSolution(nodes[1]); 78 | 79 | printf("Solution: (%d, %d) (%d, %d)\n", x.m_kx, x.m_ky, y.m_kx, y.m_ky); 80 | 81 | // done 82 | delete nodes; 83 | delete mrf; 84 | } 85 | 86 | *******************************************************************/ 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | #ifndef __TYPETRUNCATEDLINEAR2D_H__ 106 | #define __TYPETRUNCATEDLINEAR2D_H__ 107 | 108 | #include 109 | #include 110 | 111 | 112 | template class MRFEnergy; 113 | 114 | 115 | class TypeTruncatedLinear2D 116 | { 117 | private: 118 | struct Vector; // node parameters and messages 119 | struct Edge; // stores edge information and either forward or backward message 120 | 121 | public: 122 | // types declarations 123 | struct Label 124 | { 125 | int m_kx, m_ky; 126 | }; 127 | typedef double REAL; 128 | struct GlobalSize; // global information about number of labels 129 | struct LocalSize; // local information about number of labels (stored at each node) 130 | struct NodeData; // argument to MRFEnergy::AddNode() 131 | struct EdgeData; // argument to MRFEnergy::AddEdge() 132 | 133 | 134 | struct GlobalSize 135 | { 136 | GlobalSize(int KX, int KY); 137 | 138 | private: 139 | friend struct Vector; 140 | friend struct Edge; 141 | int m_KX, m_KY; // label dimensions 142 | int m_K; // number of labels 143 | }; 144 | 145 | struct LocalSize // number of labels is stored at MRFEnergy::m_Kglobal 146 | { 147 | }; 148 | 149 | struct NodeData 150 | { 151 | NodeData(REAL* data); // data = pointer to array of size MRFEnergy::m_Kglobal 152 | 153 | private: 154 | friend struct Vector; 155 | friend struct Edge; 156 | REAL* m_data; 157 | }; 158 | 159 | struct EdgeData 160 | { 161 | EdgeData(REAL alphaX, REAL alphaY, REAL lambda); 162 | 163 | private: 164 | friend struct Vector; 165 | friend struct Edge; 166 | REAL m_alphaX, m_alphaY; 167 | REAL m_lambda; 168 | }; 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | ////////////////////////////////////////////////////////////////////////////////// 177 | ////////////////////////// Visible only to MRFEnergy ///////////////////////////// 178 | ////////////////////////////////////////////////////////////////////////////////// 179 | 180 | private: 181 | friend class MRFEnergy; 182 | 183 | struct Vector 184 | { 185 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize K); // returns -1 if invalid K's 186 | void Initialize(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user adds a node 187 | void Add(GlobalSize Kglobal, LocalSize K, NodeData data); // called once when user calls MRFEnergy::AddNodeData() 188 | 189 | void SetZero(GlobalSize Kglobal, LocalSize K); // set this[k] = 0 190 | void Copy(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = V[k] 191 | void Add(GlobalSize Kglobal, LocalSize K, Vector* V); // set this[k] = this[k] + V[k] 192 | REAL GetValue(GlobalSize Kglobal, LocalSize K, Label k); // return this[k] 193 | REAL ComputeMin(GlobalSize Kglobal, LocalSize K, Label& kMin); // return vMin = min_k { this[k] }, set kMin 194 | REAL ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K); // same as previous, but additionally set this[k] -= vMin (and kMin is not returned) 195 | 196 | static int GetArraySize(GlobalSize Kglobal, LocalSize K); 197 | REAL GetArrayValue(GlobalSize Kglobal, LocalSize K, int k); // note: k is an integer in [0..GetArraySize()-1]. 198 | // For Potts functions GetArrayValue() and GetValue() are the same, 199 | // but they are different for, say, 2-dimensional labels. 200 | void SetArrayValue(GlobalSize Kglobal, LocalSize K, int k, REAL x); 201 | 202 | private: 203 | friend struct Edge; 204 | REAL m_data[1]; // actual size is MRFEnergy::m_Kglobal 205 | }; 206 | 207 | struct Edge 208 | { 209 | static int GetSizeInBytes(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data); // returns -1 if invalid data 210 | static int GetBufSizeInBytes(int vectorMaxSizeInBytes); // returns size of buffer need for UpdateMessage() 211 | void Initialize(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj, EdgeData data, Vector* Di, Vector* Dj); // called once when user adds an edge 212 | Vector* GetMessagePtr(); 213 | void Swap(GlobalSize Kglobal, LocalSize Ki, LocalSize Kj); // if the client calls this function, then the meaning of 'dir' 214 | // in distance transform functions is swapped 215 | 216 | // When UpdateMessage() is called, edge contains message from dest to source. 217 | // The function must replace it with the message from source to dest. 218 | // The update rule is given below assuming that source corresponds to tail (i) and dest corresponds 219 | // to head (j) (which is the case if dir==0). 220 | // 221 | // 1. Compute Di[ki] = gamma*source[ki] - message[ki]. (Note: message = message from j to i). 222 | // 2. Compute distance transform: set 223 | // message[kj] = min_{ki} (Di[ki] + V(ki,kj)). (Note: message = message from i to j). 224 | // 3. Compute vMin = min_{kj} m_message[kj]. 225 | // 4. Set m_message[kj] -= vMin. 226 | // 5. Return vMin. 227 | // 228 | // If dir==1 then source corresponds to j, sink corresponds to i. Then the update rule is 229 | // 230 | // 1. Compute Dj[kj] = gamma*source[kj] - message[kj]. (Note: message = message from i to j). 231 | // 2. Compute distance transform: set 232 | // message[ki] = min_{kj} (Dj[kj] + V(ki,kj)). (Note: message = message from j to i). 233 | // 3. Compute vMin = min_{ki} m_message[ki]. 234 | // 4. Set m_message[ki] -= vMin. 235 | // 5. Return vMin. 236 | // 237 | // If Edge::Swap has been called odd number of times, then the meaning of dir is swapped. 238 | // 239 | // Vector 'source' must not be modified. Function may use 'buf' as a temporary storage. 240 | REAL UpdateMessage(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Vector* source, REAL gamma, int dir, void* buf); 241 | 242 | // If dir==0, then sets dest[kj] += V(ksource,kj). 243 | // If dir==1, then sets dest[ki] += V(ki,ksource). 244 | // If Swap() has been called odd number of times, then the meaning of dir is swapped. 245 | void AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir); 246 | 247 | private: 248 | // edge information 249 | REAL m_alphaX, m_alphaY; 250 | REAL m_lambda; 251 | 252 | // message 253 | Vector m_message; 254 | }; 255 | }; 256 | 257 | 258 | 259 | 260 | ////////////////////////////////////////////////////////////////////////////////// 261 | /////////////////////////////// Implementation /////////////////////////////////// 262 | ////////////////////////////////////////////////////////////////////////////////// 263 | 264 | 265 | inline TypeTruncatedLinear2D::GlobalSize::GlobalSize(int KX, int KY) 266 | { 267 | m_KX = KX; 268 | m_KY = KY; 269 | m_K = KX*KY; 270 | } 271 | 272 | ///////////////////// NodeData and EdgeData /////////////////////// 273 | 274 | inline TypeTruncatedLinear2D::NodeData::NodeData(REAL* data) 275 | { 276 | m_data = data; 277 | } 278 | 279 | inline TypeTruncatedLinear2D::EdgeData::EdgeData(REAL alphaX, REAL alphaY, REAL lambda) 280 | { 281 | m_alphaX = alphaX; 282 | m_alphaY = alphaY; 283 | m_lambda = lambda; 284 | } 285 | 286 | ///////////////////// Vector /////////////////////// 287 | 288 | inline int TypeTruncatedLinear2D::Vector::GetSizeInBytes(GlobalSize Kglobal, LocalSize K) 289 | { 290 | if (Kglobal.m_KX < 1 || Kglobal.m_KY < 2) 291 | { 292 | return -1; 293 | } 294 | return Kglobal.m_K*sizeof(REAL); 295 | } 296 | inline void TypeTruncatedLinear2D::Vector::Initialize(GlobalSize Kglobal, LocalSize K, NodeData data) 297 | { 298 | memcpy(m_data, data.m_data, Kglobal.m_K*sizeof(REAL)); 299 | } 300 | 301 | inline void TypeTruncatedLinear2D::Vector::Add(GlobalSize Kglobal, LocalSize K, NodeData data) 302 | { 303 | for (int k=0; km_data, Kglobal.m_K*sizeof(REAL)); 317 | } 318 | 319 | inline void TypeTruncatedLinear2D::Vector::Add(GlobalSize Kglobal, LocalSize K, Vector* V) 320 | { 321 | for (int k=0; km_data[k]; 324 | } 325 | } 326 | 327 | inline TypeTruncatedLinear2D::REAL TypeTruncatedLinear2D::Vector::GetValue(GlobalSize Kglobal, LocalSize K, Label k) 328 | { 329 | assert(k.m_kx>=0 && k.m_kx=0 && k.m_ky m_data[k]) 340 | { 341 | vMin = m_data[k]; 342 | kMin = k; 343 | } 344 | } 345 | 346 | _kMin.m_ky = kMin / Kglobal.m_KX; 347 | _kMin.m_kx = kMin - _kMin.m_ky * Kglobal.m_KX; 348 | 349 | return vMin; 350 | } 351 | 352 | inline TypeTruncatedLinear2D::REAL TypeTruncatedLinear2D::Vector::ComputeAndSubtractMin(GlobalSize Kglobal, LocalSize K) 353 | { 354 | REAL vMin = m_data[0]; 355 | for (int k=1; k m_data[k]) 358 | { 359 | vMin = m_data[k]; 360 | } 361 | } 362 | for (int k=0; k=0 && k=0 && km_data[0] - m_message.m_data[0]; 428 | vMin = m_message.m_data[0]; 429 | 430 | sourcePtr = source->m_data; 431 | destPtr = m_message.m_data; 432 | for (k.m_ky=0; k.m_ky 0 && destPtr[0] > destPtr[-1] + m_alphaX) 437 | { 438 | destPtr[0] = destPtr[-1] + m_alphaX; 439 | } 440 | if (k.m_ky > 0 && destPtr[0] > destPtr[-Kglobal.m_KX] + m_alphaY) 441 | { 442 | destPtr[0] = destPtr[-Kglobal.m_KX] + m_alphaY; 443 | } 444 | else if (vMin > destPtr[0]) 445 | { 446 | vMin = destPtr[0]; 447 | } 448 | } 449 | 450 | destPtr--; 451 | for (k.m_ky=Kglobal.m_KY-1; k.m_ky>=0; k.m_ky--) 452 | for (k.m_kx=Kglobal.m_KX-1; k.m_kx>=0; k.m_kx--, destPtr--) 453 | { 454 | destPtr[0] -= vMin; 455 | if (k.m_kx < Kglobal.m_KX-1 && destPtr[0] > destPtr[1] + m_alphaX) 456 | { 457 | destPtr[0] = destPtr[1] + m_alphaX; 458 | } 459 | if (k.m_ky < Kglobal.m_KY-1 && destPtr[0] > destPtr[Kglobal.m_KX] + m_alphaY) 460 | { 461 | destPtr[0] = destPtr[Kglobal.m_KX] + m_alphaY; 462 | } 463 | if (destPtr[0] > m_lambda) 464 | { 465 | destPtr[0] = m_lambda; 466 | } 467 | } 468 | 469 | return vMin; 470 | } 471 | 472 | inline void TypeTruncatedLinear2D::Edge::AddColumn(GlobalSize Kglobal, LocalSize Ksource, LocalSize Kdest, Label ksource, Vector* dest, int dir) 473 | { 474 | assert(ksource.m_kx>=0 && ksource.m_kx=0 && ksource.m_kym_data; 480 | for (k.m_ky=0; k.m_ky ksource.m_kx) ? k.m_kx - ksource.m_kx : ksource.m_kx - k.m_kx) 484 | + m_alphaY*((k.m_ky > ksource.m_ky) ? k.m_ky - ksource.m_ky : ksource.m_ky - k.m_ky); 485 | destPtr[0] += (cost < m_lambda) ? cost : m_lambda; 486 | } 487 | } 488 | 489 | ////////////////////////////////////////////////////////////////////////////////// 490 | 491 | #endif 492 | --------------------------------------------------------------------------------