├── .DS_Store ├── boxes ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png ├── 06.png ├── 07.png ├── 08.png ├── 09.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.png ├── 15.png ├── 16.png ├── 17.png ├── 18.png ├── 19.png ├── 20.png ├── 21.png ├── 22.png ├── 23.png ├── 24.png ├── 25.png ├── 26.png ├── 27.png ├── 28.png ├── 29.png └── 30.png ├── cotton ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png ├── 06.png ├── 07.png ├── 08.png ├── 09.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.png ├── 15.png ├── 16.png ├── 17.png ├── 18.png ├── 19.png ├── 20.png ├── 21.png ├── 22.png ├── 23.png ├── 24.png ├── 25.png ├── 26.png ├── 27.png ├── 28.png ├── 29.png ├── 30.png └── .DS_Store ├── include ├── .DS_Store ├── LinkedBlockList.h ├── block.h ├── energy.h ├── graph.h └── GCoptimization.h ├── result └── after alignment.png ├── CMakeLists.txt ├── README.md └── GCO_README.TXT /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/.DS_Store -------------------------------------------------------------------------------- /boxes/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/01.png -------------------------------------------------------------------------------- /boxes/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/02.png -------------------------------------------------------------------------------- /boxes/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/03.png -------------------------------------------------------------------------------- /boxes/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/04.png -------------------------------------------------------------------------------- /boxes/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/05.png -------------------------------------------------------------------------------- /boxes/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/06.png -------------------------------------------------------------------------------- /boxes/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/07.png -------------------------------------------------------------------------------- /boxes/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/08.png -------------------------------------------------------------------------------- /boxes/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/09.png -------------------------------------------------------------------------------- /boxes/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/10.png -------------------------------------------------------------------------------- /boxes/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/11.png -------------------------------------------------------------------------------- /boxes/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/12.png -------------------------------------------------------------------------------- /boxes/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/13.png -------------------------------------------------------------------------------- /boxes/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/14.png -------------------------------------------------------------------------------- /boxes/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/15.png -------------------------------------------------------------------------------- /boxes/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/16.png -------------------------------------------------------------------------------- /boxes/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/17.png -------------------------------------------------------------------------------- /boxes/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/18.png -------------------------------------------------------------------------------- /boxes/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/19.png -------------------------------------------------------------------------------- /boxes/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/20.png -------------------------------------------------------------------------------- /boxes/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/21.png -------------------------------------------------------------------------------- /boxes/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/22.png -------------------------------------------------------------------------------- /boxes/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/23.png -------------------------------------------------------------------------------- /boxes/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/24.png -------------------------------------------------------------------------------- /boxes/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/25.png -------------------------------------------------------------------------------- /boxes/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/26.png -------------------------------------------------------------------------------- /boxes/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/27.png -------------------------------------------------------------------------------- /boxes/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/28.png -------------------------------------------------------------------------------- /boxes/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/29.png -------------------------------------------------------------------------------- /boxes/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/boxes/30.png -------------------------------------------------------------------------------- /cotton/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/01.png -------------------------------------------------------------------------------- /cotton/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/02.png -------------------------------------------------------------------------------- /cotton/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/03.png -------------------------------------------------------------------------------- /cotton/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/04.png -------------------------------------------------------------------------------- /cotton/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/05.png -------------------------------------------------------------------------------- /cotton/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/06.png -------------------------------------------------------------------------------- /cotton/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/07.png -------------------------------------------------------------------------------- /cotton/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/08.png -------------------------------------------------------------------------------- /cotton/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/09.png -------------------------------------------------------------------------------- /cotton/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/10.png -------------------------------------------------------------------------------- /cotton/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/11.png -------------------------------------------------------------------------------- /cotton/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/12.png -------------------------------------------------------------------------------- /cotton/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/13.png -------------------------------------------------------------------------------- /cotton/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/14.png -------------------------------------------------------------------------------- /cotton/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/15.png -------------------------------------------------------------------------------- /cotton/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/16.png -------------------------------------------------------------------------------- /cotton/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/17.png -------------------------------------------------------------------------------- /cotton/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/18.png -------------------------------------------------------------------------------- /cotton/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/19.png -------------------------------------------------------------------------------- /cotton/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/20.png -------------------------------------------------------------------------------- /cotton/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/21.png -------------------------------------------------------------------------------- /cotton/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/22.png -------------------------------------------------------------------------------- /cotton/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/23.png -------------------------------------------------------------------------------- /cotton/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/24.png -------------------------------------------------------------------------------- /cotton/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/25.png -------------------------------------------------------------------------------- /cotton/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/26.png -------------------------------------------------------------------------------- /cotton/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/27.png -------------------------------------------------------------------------------- /cotton/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/28.png -------------------------------------------------------------------------------- /cotton/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/29.png -------------------------------------------------------------------------------- /cotton/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/30.png -------------------------------------------------------------------------------- /cotton/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/cotton/.DS_Store -------------------------------------------------------------------------------- /include/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/include/.DS_Store -------------------------------------------------------------------------------- /result/after alignment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahn9807/Depth-from-focus/HEAD/result/after alignment.png -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.17) 2 | 3 | project(DepthFromFocus) 4 | set(PROJECT_VERSIOIN_MAJOR 0) 5 | set(PROJECT_VERSION_MINOR 1) 6 | set (CMAKE_CXX_STANDARD 11) 7 | 8 | include_directories(/usr/local/Cellar/opencv/4.5.0/include/opencv4) 9 | link_directories(/usr/local/Cellar/opencv/4.5.0/lib/) 10 | 11 | set(EXT_LIBS opencv_core opencv_highgui opencv_imgproc opencv_calib3d opencv_features2d opencv_ximgproc opencv_imgcodecs) 12 | 13 | set( CMAKE_INSTALL_PREFIX ../ ) 14 | 15 | add_executable( 16 | DepthFromFocus 17 | 18 | # Header Files 19 | include/block.h 20 | include/energy.h 21 | include/GCoptimization.h 22 | include/graph.h 23 | include/LinkedBlockList.h 24 | 25 | # Source Files 26 | src/main.cpp 27 | src/example.cpp 28 | src/GCoptimization.cpp 29 | src/graph.cpp 30 | src/LinkedBlockList.cpp 31 | src/maxflow.cpp 32 | ) 33 | 34 | target_link_libraries(DepthFromFocus ${EXT_LIBS}) 35 | 36 | 37 | -------------------------------------------------------------------------------- /include/LinkedBlockList.h: -------------------------------------------------------------------------------- 1 | /* Singly Linked List of Blocks */ 2 | // This data structure should be used only for the GCoptimization class implementation 3 | // because it lucks some important general functions for general list, like remove_item() 4 | // The head block may be not full 5 | // For regular 2D grids, it's better to set GCLL_BLOCK_SIZE to 2 6 | // For other graphs, it should be set to the average expected number of neighbors 7 | // Data in linked list for the neighborhood system is allocated in blocks of size GCLL_BLOCK_SIZE 8 | 9 | #ifndef __LINKEDBLOCKLIST_H__ 10 | #define __LINKEDBLOCKLIST_H__ 11 | 12 | #define GCLL_BLOCK_SIZE 4 13 | // GCLL_BLOCKSIZE should "fit" into the type BlockType. That is 14 | // if GCLL_BLOCKSIZE is larger than 255 but smaller than largest short integer 15 | // then BlockType should be set to short 16 | typedef char BlockType; 17 | 18 | //The type of data stored in the linked list 19 | typedef void * ListType; 20 | 21 | class LinkedBlockList{ 22 | 23 | public: 24 | void addFront(ListType item); 25 | inline bool isEmpty(){if (m_head == 0) return(true); else return(false);}; 26 | inline LinkedBlockList(){m_head = 0; m_head_block_size = GCLL_BLOCK_SIZE;}; 27 | ~LinkedBlockList(); 28 | 29 | // Next three functins are for the linked list traversal 30 | inline void setCursorFront(){m_cursor = m_head; m_cursor_ind = 0;}; 31 | ListType next(); 32 | bool hasNext(); 33 | 34 | private: 35 | typedef struct LLBlockStruct{ 36 | ListType m_item[GCLL_BLOCK_SIZE]; 37 | struct LLBlockStruct *m_next; 38 | } LLBlock; 39 | 40 | LLBlock *m_head; 41 | // Remembers the number of elements in the head block, since it may not be full 42 | BlockType m_head_block_size; 43 | // For block traversal, points to current element in the current block 44 | BlockType m_cursor_ind; 45 | // For block traversal, points to current block in the linked list 46 | LLBlock *m_cursor; 47 | }; 48 | 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Depth From focus 2 | ## Summary 3 | Depth from focus/defocus is the problem of estimating the 3D surface of a scene from a set of two or more images of that scene. The images are obtained by changing the camera parameters (typically the focal setting or the image plane axial position), and taken from the same point of view [1]. In this project, I construct all in focus image by selecting and placing focused pixel at each focus/defocused images. 4 | ## Build Instruction 5 | ### Requirements 6 | 1. opencv c++ library https://opencv.org/ 7 | 2. cmake https://cmake.org/ 8 | 9 | ### Setup Instructions 10 | You have to sepcify opencv libary location to CMakeLists.txt. If you see CMakeLists.txt, you can find include_directories and link_directories for linking the library files to your own workstation. In my case, opencv version is 4.5.0 and installed location is located at the /usr/lcoal/Cellar/opencv/4.5.0/. But this path is varying from your own workstation, so you have to set properly for building this project. 11 | 12 | ``` 13 | include_directories(/usr/local/Cellar/opencv/4.5.0/include/opencv4) 14 | link_directories(/usr/local/Cellar/opencv/4.5.0/lib/) 15 | ``` 16 | 17 | After setting library location, you have to make and generate project for your platform. 18 | 19 | ## Image Alignment 20 | Cause focusing a image requires movement of focal lens at the physical camera with positioning error of human, initial defocused images are mismatched each other. So, we have to set alignement of given images. So How? It is simple. First we calculate homograhy matrix of consecutive images. Let $h_x$ is homogray matrix of image number x and x + 1. Then, we can calculate homography matrix of first image and x'th image by mutiplying all the homography matrix of $h_1$, $h_2$,... $h_{x-1}$. Finally, you can get aligned images. 21 | 22 | For aligning images, you have to consider using various kinds of align methods. In this project, I use feature based method. You can find the way I use at the reference [2]. 23 | 24 | |before alignment|after alignment| 25 | |:---:|:---| 26 | |![ba](https://raw.githubusercontent.com/ahn9807/Depth-from-focus/master/result/before%20alignment.png) | ![aa](https://raw.githubusercontent.com/ahn9807/Depth-from-focus/master/result/after%20alignment.png) | 27 | 28 | You can find the difference of image 1 and image 30 in above table. You can find that after the refinement the differences of image is reduced. 29 | 30 | ## Initial Depth Map (Cost Volume) 31 | ### Calculating Depth map 32 | We can calculate depth map by derivative of images. Using “blurryness metric”, some of them simple and straightforward using just basic grayscale pixel intensity statistics, others more advanced and feature-based, evaluating the Local Binary Patterns of an image [3]. If the variance falls below a pre-defined threshold, then the image is considered blurry; otherwise, the image is not blurry. You can use various kind of covolution kernel for calculating color difference of each piexel (gray-scaled). The most simplestic way is first derivative (known as sobel filter). But it is not specific enough for calculating focus of images. So we use laplacian of each images for calculating more nosiy but more accurate focus measure. There are lots of variantions of laplacian kernel. Here is examples. 33 | |Name of kernel|Equation| 34 | |:---:|:---:| 35 | |Laplacian|$\frac{\partial^2 f}{\partial x^2} + \frac{\partial^2 f}{\partial y^2}$| 36 | |Modified Laplacian|$(\frac{\partial^2 f}{\partial x^2})^2 + (\frac{\partial^2 f}{\partial y^2})^2$| 37 | |Sum Of ML|$\sum_{near\ by\ pixels} (\frac{\partial^2 f}{\partial x^2})^2 + (\frac{\partial^2 f}{\partial y^2})^2$| 38 | 39 | In this project, I use Laplacian as a focus Measure Method. 40 | 41 | |Depth map of image 1|Depth map of image 30| 42 | |:---:|:---| 43 | |![dm1](https://raw.githubusercontent.com/ahn9807/Depth-from-focus/master/result/cost%20volume%201.png) | ![dm2](https://raw.githubusercontent.com/ahn9807/Depth-from-focus/master/result/cost%20volume%2030.png) | 44 | 45 | ### Calculating Cost Volume 46 | Now calculating depth map of each images and assemble them. Then we can make cost volume. Cost volume is a terminology for "Celected data set of diaparity map" in computer vision [4]. By selecting the label of image at the highest value in the each cost volume pixels, we can get the initial depth map. But, this naive approach for calculating initial depth map has lots of noise at the depth map. So we have to reduce this noise by using graph cut and weighted median filter. 47 | 48 | ## Depth Refine ment 49 | ### Graph Cut 50 | In graph theory, a cut is a partition of the vertices of a graph into two disjoint subsets [5]. I use Multi-label optimization for partitioning the image label at the cost volume. I use gco library at waterloo university [6]. 51 | ### Weighted Median Filter 52 | Weighted Median (WM) filters have the robustness and edge preserving capability of the classical median filter [7]. Median filter is somple. Just takes the median of neighbor pixels and self. The only differences of weight median filter and median filter is that weighted median filter uses weighted kernel. Is is known that at the general cases, you can find more neat image by using weighted median filter than median filter [8]. 53 | 54 | |Initial depth map|Using graph cut and weighted meidan filter| 55 | |:---:|:---| 56 | |![idm](https://raw.githubusercontent.com/ahn9807/Depth-from-focus/master/result/initial%20depth%20map.png) | ![refined image](https://raw.githubusercontent.com/ahn9807/Depth-from-focus/master/result/after%20refinement.png) | 57 | 58 | ## All in Focus 59 | Finally, by selecting the pixel at the i'th decoused image at the depth map, we can construct final all in focus image. 60 | 61 | ![result](https://raw.githubusercontent.com/ahn9807/Depth-from-focus/master/result/result.png) 62 | 63 | ## References 64 | 1. https://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/FAVARO1/dfdtutorial.html 65 | 2. https://www.learnopencv.com/image-alignment-feature-based-using-opencv-c-python/ 66 | 3. https://www.pyimagesearch.com/2015/09/07/blur-detection-with-opencv/ 67 | 4. http://blog.naver.com/PostView.nhn?blogId=dnjswns2280&logNo=222073493738&parentCategoryNo=&categoryNo=10&viewDate=&isShowPopularPosts=false&from=postView 68 | 5. https://en.wikipedia.org/wiki/Cut_(graph_theory) 69 | 6. https://vision.cs.uwaterloo.ca/code/ 70 | 7. https://ieeexplore.ieee.org/document/486465 71 | 8. https://dsp.stackexchange.com/questions/22412/what-is-the-advantage-of-weighted-median-filter-over-median-filter 72 | -------------------------------------------------------------------------------- /include/block.h: -------------------------------------------------------------------------------- 1 | /* block.h */ 2 | /* 3 | Template classes Block and DBlock 4 | Implement adding and deleting items of the same type in blocks. 5 | 6 | If there there are many items then using Block or DBlock 7 | is more efficient than using 'new' and 'delete' both in terms 8 | of memory and time since 9 | (1) On some systems there is some minimum amount of memory 10 | that 'new' can allocate (e.g., 64), so if items are 11 | small that a lot of memory is wasted. 12 | (2) 'new' and 'delete' are designed for items of varying size. 13 | If all items has the same size, then an algorithm for 14 | adding and deleting can be made more efficient. 15 | (3) All Block and DBlock functions are inline, so there are 16 | no extra function calls. 17 | 18 | Differences between Block and DBlock: 19 | (1) DBlock allows both adding and deleting items, 20 | whereas Block allows only adding items. 21 | (2) Block has an additional operation of scanning 22 | items added so far (in the order in which they were added). 23 | (3) Block allows to allocate several consecutive 24 | items at a time, whereas DBlock can add only a single item. 25 | 26 | Note that no constructors or destructors are called for items. 27 | 28 | Example usage for items of type 'MyType': 29 | 30 | /////////////////////////////////////////////////// 31 | #include "block.h" 32 | #define BLOCK_SIZE 1024 33 | typedef struct { int a, b; } MyType; 34 | MyType *ptr, *array[10000]; 35 | 36 | ... 37 | 38 | Block *block = new Block(BLOCK_SIZE); 39 | 40 | // adding items 41 | for (int i=0; i New(); 44 | ptr -> a = ptr -> b = rand(); 45 | } 46 | 47 | // reading items 48 | for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext()) 49 | { 50 | printf("%d %d\n", ptr->a, ptr->b); 51 | } 52 | 53 | delete block; 54 | 55 | ... 56 | 57 | DBlock *dblock = new DBlock(BLOCK_SIZE); 58 | 59 | // adding items 60 | for (int i=0; i New(); 63 | } 64 | 65 | // deleting items 66 | for (int i=0; i Delete(array[i]); 69 | } 70 | 71 | // adding items 72 | for (int i=0; i New(); 75 | } 76 | 77 | delete dblock; 78 | 79 | /////////////////////////////////////////////////// 80 | 81 | Note that DBlock deletes items by marking them as 82 | empty (i.e., by adding them to the list of free items), 83 | so that this memory could be used for subsequently 84 | added items. Thus, at each moment the memory allocated 85 | is determined by the maximum number of items allocated 86 | simultaneously at earlier moments. All memory is 87 | deallocated only when the destructor is called. 88 | */ 89 | 90 | #ifndef __BLOCK_H__ 91 | #define __BLOCK_H__ 92 | 93 | #include 94 | 95 | /***********************************************************************/ 96 | /***********************************************************************/ 97 | /***********************************************************************/ 98 | 99 | template class Block 100 | { 101 | public: 102 | /* Constructor. Arguments are the block size and 103 | (optionally) the pointer to the function which 104 | will be called if allocation failed; the message 105 | passed to this function is "Not enough memory!" */ 106 | Block(int size, void (*err_function)(const char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; } 107 | 108 | /* Destructor. Deallocates all items added so far */ 109 | ~Block() { while (first) { block *next = first -> next; delete first; first = next; } } 110 | 111 | /* Allocates 'num' consecutive items; returns pointer 112 | to the first item. 'num' cannot be greater than the 113 | block size since items must fit in one block */ 114 | Type *New(int num = 1) 115 | { 116 | Type *t; 117 | 118 | if (!last || last->current + num > last->last) 119 | { 120 | if (last && last->next) last = last -> next; 121 | else 122 | { 123 | block *next = (block *) new char [sizeof(block) + (block_size-1)*sizeof(Type)]; 124 | if (!next) { if (error_function) (*error_function)("Not enough memory!"); exit(1); } 125 | if (last) last -> next = next; 126 | else first = next; 127 | last = next; 128 | last -> current = & ( last -> data[0] ); 129 | last -> last = last -> current + block_size; 130 | last -> next = NULL; 131 | } 132 | } 133 | 134 | t = last -> current; 135 | last -> current += num; 136 | return t; 137 | } 138 | 139 | /* Returns the first item (or NULL, if no items were added) */ 140 | Type *ScanFirst() 141 | { 142 | for (scan_current_block=first; scan_current_block; scan_current_block = scan_current_block->next) 143 | { 144 | scan_current_data = & ( scan_current_block -> data[0] ); 145 | if (scan_current_data < scan_current_block -> current) return scan_current_data ++; 146 | } 147 | return NULL; 148 | } 149 | 150 | /* Returns the next item (or NULL, if all items have been read) 151 | Can be called only if previous ScanFirst() or ScanNext() 152 | call returned not NULL. */ 153 | Type *ScanNext() 154 | { 155 | while (scan_current_data >= scan_current_block -> current) 156 | { 157 | scan_current_block = scan_current_block -> next; 158 | if (!scan_current_block) return NULL; 159 | scan_current_data = & ( scan_current_block -> data[0] ); 160 | } 161 | return scan_current_data ++; 162 | } 163 | 164 | /* Marks all elements as empty */ 165 | void Reset() 166 | { 167 | block *b; 168 | if (!first) return; 169 | for (b=first; ; b=b->next) 170 | { 171 | b -> current = & ( b -> data[0] ); 172 | if (b == last) break; 173 | } 174 | last = first; 175 | } 176 | 177 | /***********************************************************************/ 178 | 179 | private: 180 | 181 | typedef struct block_st 182 | { 183 | Type *current, *last; 184 | struct block_st *next; 185 | Type data[1]; 186 | } block; 187 | 188 | int block_size; 189 | block *first; 190 | block *last; 191 | 192 | block *scan_current_block; 193 | Type *scan_current_data; 194 | 195 | void (*error_function)(const char *); 196 | }; 197 | 198 | /***********************************************************************/ 199 | /***********************************************************************/ 200 | /***********************************************************************/ 201 | 202 | template class DBlock 203 | { 204 | public: 205 | /* Constructor. Arguments are the block size and 206 | (optionally) the pointer to the function which 207 | will be called if allocation failed; the message 208 | passed to this function is "Not enough memory!" */ 209 | DBlock(int size, void (*err_function)(const char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; } 210 | 211 | /* Destructor. Deallocates all items added so far */ 212 | ~DBlock() { while (first) { block *next = first -> next; delete first; first = next; } } 213 | 214 | /* Allocates one item */ 215 | Type *New() 216 | { 217 | block_item *item; 218 | 219 | if (!first_free) 220 | { 221 | block *next = first; 222 | first = (block *) new char [sizeof(block) + (block_size-1)*sizeof(block_item)]; 223 | if (!first) { if (error_function) (*error_function)("Not enough memory!"); exit(1); } 224 | first_free = & (first -> data[0] ); 225 | for (item=first_free; item next_free = item + 1; 227 | item -> next_free = NULL; 228 | first -> next = next; 229 | } 230 | 231 | item = first_free; 232 | first_free = item -> next_free; 233 | return (Type *) item; 234 | } 235 | 236 | /* Deletes an item allocated previously */ 237 | void Delete(Type *t) 238 | { 239 | ((block_item *) t) -> next_free = first_free; 240 | first_free = (block_item *) t; 241 | } 242 | 243 | /***********************************************************************/ 244 | 245 | private: 246 | 247 | typedef union block_item_st 248 | { 249 | Type t; 250 | block_item_st *next_free; 251 | } block_item; 252 | 253 | typedef struct block_st 254 | { 255 | struct block_st *next; 256 | block_item data[1]; 257 | } block; 258 | 259 | int block_size; 260 | block *first; 261 | block_item *first_free; 262 | 263 | void (*error_function)(const char *); 264 | }; 265 | 266 | 267 | #endif 268 | 269 | -------------------------------------------------------------------------------- /include/energy.h: -------------------------------------------------------------------------------- 1 | /* energy.h */ 2 | /* Vladimir Kolmogorov (vnk@cs.cornell.edu), 2003. */ 3 | 4 | /* 5 | This software implements an energy minimization technique described in 6 | 7 | What Energy Functions can be Minimized via Graph Cuts? 8 | Vladimir Kolmogorov and Ramin Zabih. 9 | To appear in IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI). 10 | Earlier version appeared in European Conference on Computer Vision (ECCV), May 2002. 11 | 12 | More specifically, it computes the global minimum of a function E of binary 13 | variables x_1, ..., x_n which can be written as a sum of terms involving 14 | at most three variables at a time: 15 | 16 | E(x_1, ..., x_n) = \sum_{i} E^{i} (x_i) 17 | + \sum_{i,j} E^{i,j} (x_i, x_j) 18 | + \sum_{i,j,k} E^{i,j,k}(x_i, x_j, x_k) 19 | 20 | The method works only if each term is "regular". Definitions of regularity 21 | for terms E^{i}, E^{i,j}, E^{i,j,k} are given below as comments to functions 22 | add_term1(), add_term2(), add_term3(). 23 | 24 | This software can be used only for research purposes. IF YOU USE THIS SOFTWARE, 25 | YOU SHOULD CITE THE AFOREMENTIONED PAPER IN ANY RESULTING PUBLICATION. 26 | 27 | In order to use it, you will also need a MAXFLOW software which can be 28 | obtained from http://www.cs.cornell.edu/People/vnk/software.html 29 | 30 | 31 | Example usage 32 | (Minimizes the following function of 3 binary variables: 33 | E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z|): 34 | 35 | /////////////////////////////////////////////////// 36 | 37 | #include 38 | #include "energy.h" 39 | 40 | void main() 41 | { 42 | // Minimize the following function of 3 binary variables: 43 | // E(x, y, z) = x - 2*y + 3*(1-z) - 4*x*y + 5*|y-z| 44 | 45 | Energy::Var varx, vary, varz; 46 | Energy *e = new Energy(); 47 | 48 | varx = e -> add_variable(); 49 | vary = e -> add_variable(); 50 | varz = e -> add_variable(); 51 | 52 | e -> add_term1(varx, 0, 1); // add term x 53 | e -> add_term1(vary, 0, -2); // add term -2*y 54 | e -> add_term1(varz, 3, 0); // add term 3*(1-z) 55 | 56 | e -> add_term2(x, y, 0, 0, 0, -4); // add term -4*x*y 57 | e -> add_term2(y, z, 0, 5, 5, 0); // add term 5*|y-z| 58 | 59 | Energy::TotalValue Emin = e -> minimize(); 60 | 61 | printf("Minimum = %d\n", Emin); 62 | printf("Optimal solution:\n"); 63 | printf("x = %d\n", e->get_var(varx)); 64 | printf("y = %d\n", e->get_var(vary)); 65 | printf("z = %d\n", e->get_var(varz)); 66 | 67 | delete e; 68 | } 69 | 70 | /////////////////////////////////////////////////// 71 | */ 72 | 73 | #ifndef __ENERGY_H__ 74 | #define __ENERGY_H__ 75 | 76 | #include 77 | #include "graph.h" 78 | 79 | template class Energy: public Graph 80 | { 81 | typedef Graph GraphT; 82 | public: 83 | typedef typename GraphT::node_id Var; 84 | 85 | /* Types of energy values. 86 | Value is a type of a value in a single term 87 | TotalValue is a type of a value of the total energy. 88 | By default Value = short, TotalValue = int. 89 | To change it, change the corresponding types in graph.h */ 90 | typedef captype Value; 91 | typedef flowtype TotalValue; 92 | 93 | /* interface functions */ 94 | 95 | /* Constructor. Optional argument is the pointer to the 96 | function which will be called if an error occurs; 97 | an error message is passed to this function. If this 98 | argument is omitted, exit(1) will be called. */ 99 | Energy(int var_num_max, int edge_num_max, void (*err_function)(const char *) = NULL); 100 | 101 | /* Destructor */ 102 | ~Energy(); 103 | 104 | /* Adds a new binary variable */ 105 | Var add_variable(int num=1); 106 | 107 | /* Adds a constant E to the energy function */ 108 | void add_constant(Value E); 109 | 110 | /* Adds a new term E(x) of one binary variable 111 | to the energy function, where 112 | E(0) = E0, E(1) = E1 113 | E0 and E1 can be arbitrary */ 114 | void add_term1(Var x, 115 | Value E0, Value E1); 116 | 117 | /* Adds a new term E(x,y) of two binary variables 118 | to the energy function, where 119 | E(0,0) = E00, E(0,1) = E01 120 | E(1,0) = E10, E(1,1) = E11 121 | The term must be regular, i.e. E00 + E11 <= E01 + E10 */ 122 | void add_term2(Var x, Var y, 123 | Value E00, Value E01, 124 | Value E10, Value E11); 125 | 126 | /* Adds a new term E(x,y,z) of three binary variables 127 | to the energy function, where 128 | E(0,0,0) = E000, E(0,0,1) = E001 129 | E(0,1,0) = E010, E(0,1,1) = E011 130 | E(1,0,0) = E100, E(1,0,1) = E101 131 | E(1,1,0) = E110, E(1,1,1) = E111 132 | The term must be regular. It means that if one 133 | of the variables is fixed (for example, y=1), then 134 | the resulting function of two variables must be regular. 135 | Since there are 6 ways to fix one variable 136 | (3 variables times 2 binary values - 0 and 1), 137 | this is equivalent to 6 inequalities */ 138 | void add_term3(Var x, Var y, Var z, 139 | Value E000, Value E001, 140 | Value E010, Value E011, 141 | Value E100, Value E101, 142 | Value E110, Value E111); 143 | 144 | /* After the energy function has been constructed, 145 | call this function to minimize it. 146 | Returns the minimum of the function */ 147 | TotalValue minimize(); 148 | 149 | /* After 'minimize' has been called, this function 150 | can be used to determine the value of variable 'x' 151 | in the optimal solution. 152 | Returns either 0 or 1 */ 153 | int get_var(Var x); 154 | 155 | /***********************************************************************/ 156 | /***********************************************************************/ 157 | /***********************************************************************/ 158 | 159 | private: 160 | /* internal variables and functions */ 161 | 162 | TotalValue Econst; 163 | void (*error_function)(const char *); /* this function is called if a error occurs, 164 | with a corresponding error message 165 | (or exit(1) is called if it's NULL) */ 166 | }; 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | /***********************************************************************/ 183 | /************************ Implementation ******************************/ 184 | /***********************************************************************/ 185 | 186 | template 187 | inline Energy::Energy(int var_num_max, int edge_num_max, void (*err_function)(const char *)) : Graph(var_num_max, edge_num_max, err_function) 188 | { 189 | Econst = 0; 190 | error_function = err_function; 191 | } 192 | 193 | template 194 | inline Energy::~Energy() {} 195 | 196 | template 197 | inline typename Energy::Var Energy::add_variable(int num) 198 | { return GraphT::add_node(num); } 199 | 200 | template 201 | inline void Energy::add_constant(Value A) { Econst += A; } 202 | 203 | template 204 | inline void Energy::add_term1(Var x, 205 | Value A, Value B) 206 | { 207 | this->add_tweights(x, B, A); 208 | } 209 | 210 | template 211 | inline void Energy::add_term2(Var x, Var y, 212 | Value A, Value B, 213 | Value C, Value D) 214 | { 215 | /* 216 | E = A A + 0 B-A 217 | D D C-D 0 218 | Add edges for the first term 219 | */ 220 | this->add_tweights(x, D, A); 221 | B -= A; C -= D; 222 | 223 | /* now need to represent 224 | 0 B 225 | C 0 226 | */ 227 | 228 | assert(B + C >= 0); /* check regularity */ 229 | if (B < 0) 230 | { 231 | /* Write it as 232 | B B + -B 0 + 0 0 233 | 0 0 -B 0 B+C 0 234 | */ 235 | this->add_tweights(x, 0, B); /* first term */ 236 | this->add_tweights(y, 0, -B); /* second term */ 237 | this->add_edge(x, y, 0, B+C); /* third term */ 238 | } 239 | else if (C < 0) 240 | { 241 | /* Write it as 242 | -C -C + C 0 + 0 B+C 243 | 0 0 C 0 0 0 244 | */ 245 | this->add_tweights(x, 0, -C); /* first term */ 246 | this->add_tweights(y, 0, C); /* second term */ 247 | this->add_edge(x, y, B+C, 0); /* third term */ 248 | } 249 | else /* B >= 0, C >= 0 */ 250 | { 251 | this->add_edge(x, y, B, C); 252 | } 253 | } 254 | 255 | template 256 | inline void Energy::add_term3(Var x, Var y, Var z, 257 | Value E000, Value E001, 258 | Value E010, Value E011, 259 | Value E100, Value E101, 260 | Value E110, Value E111) 261 | { 262 | register Value pi = (E000 + E011 + E101 + E110) - (E100 + E010 + E001 + E111); 263 | register Value delta; 264 | register Var u; 265 | 266 | if (pi >= 0) 267 | { 268 | Econst += E111 - (E011 + E101 + E110); 269 | 270 | add_tweights(x, E101, E001); 271 | add_tweights(y, E110, E100); 272 | add_tweights(z, E011, E010); 273 | 274 | delta = (E010 + E001) - (E000 + E011); /* -pi(E[x=0]) */ 275 | assert(delta >= 0); /* check regularity */ 276 | add_edge(y, z, delta, 0); 277 | 278 | delta = (E100 + E001) - (E000 + E101); /* -pi(E[y=0]) */ 279 | assert(delta >= 0); /* check regularity */ 280 | add_edge(z, x, delta, 0); 281 | 282 | delta = (E100 + E010) - (E000 + E110); /* -pi(E[z=0]) */ 283 | assert(delta >= 0); /* check regularity */ 284 | add_edge(x, y, delta, 0); 285 | 286 | if (pi > 0) 287 | { 288 | u = add_variable(); 289 | add_edge(x, u, pi, 0); 290 | add_edge(y, u, pi, 0); 291 | add_edge(z, u, pi, 0); 292 | add_tweights(u, 0, pi); 293 | } 294 | } 295 | else 296 | { 297 | Econst += E000 - (E100 + E010 + E001); 298 | 299 | add_tweights(x, E110, E010); 300 | add_tweights(y, E011, E001); 301 | add_tweights(z, E101, E100); 302 | 303 | delta = (E110 + E101) - (E100 + E111); /* -pi(E[x=1]) */ 304 | assert(delta >= 0); /* check regularity */ 305 | add_edge(z, y, delta, 0); 306 | 307 | delta = (E110 + E011) - (E010 + E111); /* -pi(E[y=1]) */ 308 | assert(delta >= 0); /* check regularity */ 309 | add_edge(x, z, delta, 0); 310 | 311 | delta = (E101 + E011) - (E001 + E111); /* -pi(E[z=1]) */ 312 | assert(delta >= 0); /* check regularity */ 313 | add_edge(y, x, delta, 0); 314 | 315 | u = add_variable(); 316 | add_edge(u, x, -pi, 0); 317 | add_edge(u, y, -pi, 0); 318 | add_edge(u, z, -pi, 0); 319 | this->add_tweights(u, -pi, 0); 320 | } 321 | } 322 | 323 | template 324 | inline typename Energy::TotalValue Energy::minimize() { 325 | return Econst + GraphT::maxflow(); } 326 | 327 | template 328 | inline int Energy::get_var(Var x) { return (int) this->what_segment(x); } 329 | 330 | #endif 331 | -------------------------------------------------------------------------------- /include/graph.h: -------------------------------------------------------------------------------- 1 | /* graph.h */ 2 | /* 3 | This software library implements the maxflow algorithm 4 | described in 5 | 6 | "An Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy Minimization in Vision." 7 | Yuri Boykov and Vladimir Kolmogorov. 8 | In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), 9 | September 2004 10 | 11 | This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov 12 | at Siemens Corporate Research. To make it available for public use, 13 | it was later reimplemented by Vladimir Kolmogorov based on open publications. 14 | 15 | If you use this software for research purposes, you should cite 16 | the aforementioned paper in any resulting publication. 17 | 18 | ---------------------------------------------------------------------- 19 | 20 | REUSING TREES: 21 | 22 | Starting with version 3.0, there is a also an option of reusing search 23 | trees from one maxflow computation to the next, as described in 24 | 25 | "Efficiently Solving Dynamic Markov Random Fields Using Graph Cuts." 26 | Pushmeet Kohli and Philip H.S. Torr 27 | International Conference on Computer Vision (ICCV), 2005 28 | 29 | If you use this option, you should cite 30 | the aforementioned paper in any resulting publication. 31 | */ 32 | 33 | 34 | 35 | /* 36 | For description, license, example usage see README.TXT. 37 | */ 38 | 39 | #ifndef __GRAPH_H__ 40 | #define __GRAPH_H__ 41 | 42 | #include 43 | #include "block.h" 44 | 45 | #include 46 | // NOTE: in UNIX you need to use -DNDEBUG preprocessor option to supress assert's!!! 47 | 48 | 49 | 50 | // captype: type of edge capacities (excluding t-links) 51 | // tcaptype: type of t-links (edges between nodes and terminals) 52 | // flowtype: type of total flow 53 | // 54 | // Current instantiations are in instances.inc 55 | template class Graph 56 | { 57 | public: 58 | typedef enum 59 | { 60 | SOURCE = 0, 61 | SINK = 1 62 | } termtype; // terminals 63 | typedef int node_id; 64 | 65 | ///////////////////////////////////////////////////////////////////////// 66 | // BASIC INTERFACE FUNCTIONS // 67 | // (should be enough for most applications) // 68 | ///////////////////////////////////////////////////////////////////////// 69 | 70 | // Constructor. 71 | // The first argument gives an estimate of the maximum number of nodes that can be added 72 | // to the graph, and the second argument is an estimate of the maximum number of edges. 73 | // The last (optional) argument is the pointer to the function which will be called 74 | // if an error occurs; an error message is passed to this function. 75 | // If this argument is omitted, exit(1) will be called. 76 | // 77 | // IMPORTANT: It is possible to add more nodes to the graph than node_num_max 78 | // (and node_num_max can be zero). However, if the count is exceeded, then 79 | // the internal memory is reallocated (increased by 50%) which is expensive. 80 | // Also, temporarily the amount of allocated memory would be more than twice than needed. 81 | // Similarly for edges. 82 | // If you wish to avoid this overhead, you can download version 2.2, where nodes and edges are stored in blocks. 83 | Graph(int node_num_max, int edge_num_max, void (*err_function)(const char *) = NULL); 84 | 85 | // Destructor 86 | ~Graph(); 87 | 88 | // Adds node(s) to the graph. By default, one node is added (num=1); then first call returns 0, second call returns 1, and so on. 89 | // If num>1, then several nodes are added, and node_id of the first one is returned. 90 | // IMPORTANT: see note about the constructor 91 | node_id add_node(int num = 1); 92 | 93 | // Adds a bidirectional edge between 'i' and 'j' with the weights 'cap' and 'rev_cap'. 94 | // IMPORTANT: see note about the constructor 95 | void add_edge(node_id i, node_id j, captype cap, captype rev_cap); 96 | 97 | // Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights. 98 | // Can be called multiple times for each node. 99 | // Weights can be negative. 100 | // NOTE: the number of such edges is not counted in edge_num_max. 101 | // No internal memory is allocated by this call. 102 | void add_tweights(node_id i, tcaptype cap_source, tcaptype cap_sink); 103 | 104 | 105 | // Computes the maxflow. Can be called several times. 106 | // FOR DESCRIPTION OF reuse_trees, SEE mark_node(). 107 | // FOR DESCRIPTION OF changed_list, SEE remove_from_changed_list(). 108 | flowtype maxflow(bool reuse_trees = false, Block* changed_list = NULL); 109 | 110 | // After the maxflow is computed, this function returns to which 111 | // segment the node 'i' belongs (Graph::SOURCE or Graph::SINK). 112 | // 113 | // Occasionally there may be several minimum cuts. If a node can be assigned 114 | // to both the source and the sink, then default_segm is returned. 115 | termtype what_segment(node_id i, termtype default_segm = SOURCE); 116 | 117 | 118 | 119 | ////////////////////////////////////////////// 120 | // ADVANCED INTERFACE FUNCTIONS // 121 | // (provide access to the graph) // 122 | ////////////////////////////////////////////// 123 | 124 | private: 125 | struct node; 126 | struct arc; 127 | 128 | public: 129 | 130 | //////////////////////////// 131 | // 1. Reallocating graph. // 132 | //////////////////////////// 133 | 134 | // Removes all nodes and edges. 135 | // After that functions add_node() and add_edge() must be called again. 136 | // 137 | // Advantage compared to deleting Graph and allocating it again: 138 | // no calls to delete/new (which could be quite slow). 139 | // 140 | // If the graph structure stays the same, then an alternative 141 | // is to go through all nodes/edges and set new residual capacities 142 | // (see functions below). 143 | void reset(); 144 | 145 | //////////////////////////////////////////////////////////////////////////////// 146 | // 2. Functions for getting pointers to arcs and for reading graph structure. // 147 | // NOTE: adding new arcs may invalidate these pointers (if reallocation // 148 | // happens). So it's best not to add arcs while reading graph structure. // 149 | //////////////////////////////////////////////////////////////////////////////// 150 | 151 | // The following two functions return arcs in the same order that they 152 | // were added to the graph. NOTE: for each call add_edge(i,j,cap,cap_rev) 153 | // the first arc returned will be i->j, and the second j->i. 154 | // If there are no more arcs, then the function can still be called, but 155 | // the returned arc_id is undetermined. 156 | typedef arc* arc_id; 157 | arc_id get_first_arc(); 158 | arc_id get_next_arc(arc_id a); 159 | 160 | // other functions for reading graph structure 161 | int get_node_num() { return node_num; } 162 | int get_arc_num() { return (int)(arc_last - arcs); } 163 | void get_arc_ends(arc_id a, node_id& i, node_id& j); // returns i,j to that a = i->j 164 | 165 | /////////////////////////////////////////////////// 166 | // 3. Functions for reading residual capacities. // 167 | /////////////////////////////////////////////////// 168 | 169 | // returns residual capacity of SOURCE->i minus residual capacity of i->SINK 170 | tcaptype get_trcap(node_id i); 171 | // returns residual capacity of arc a 172 | captype get_rcap(arc* a); 173 | 174 | ///////////////////////////////////////////////////////////////// 175 | // 4. Functions for setting residual capacities. // 176 | // NOTE: If these functions are used, the value of the flow // 177 | // returned by maxflow() will not be valid! // 178 | ///////////////////////////////////////////////////////////////// 179 | 180 | void set_trcap(node_id i, tcaptype trcap); 181 | void set_rcap(arc* a, captype rcap); 182 | 183 | //////////////////////////////////////////////////////////////////// 184 | // 5. Functions related to reusing trees & list of changed nodes. // 185 | //////////////////////////////////////////////////////////////////// 186 | 187 | // If flag reuse_trees is true while calling maxflow(), then search trees 188 | // are reused from previous maxflow computation. 189 | // In this case before calling maxflow() the user must 190 | // specify which parts of the graph have changed by calling mark_node(): 191 | // add_tweights(i),set_trcap(i) => call mark_node(i) 192 | // add_edge(i,j),set_rcap(a) => call mark_node(i); mark_node(j) 193 | // 194 | // This option makes sense only if a small part of the graph is changed. 195 | // The initialization procedure goes only through marked nodes then. 196 | // 197 | // mark_node(i) can either be called before or after graph modification. 198 | // Can be called more than once per node, but calls after the first one 199 | // do not have any effect. 200 | // 201 | // NOTE: 202 | // - This option cannot be used in the first call to maxflow(). 203 | // - It is not necessary to call mark_node() if the change is ``not essential'', 204 | // i.e. sign(trcap) is preserved for a node and zero/nonzero status is preserved for an arc. 205 | // - To check that you marked all necessary nodes, you can call maxflow(false) after calling maxflow(true). 206 | // If everything is correct, the two calls must return the same value of flow. (Useful for debugging). 207 | void mark_node(node_id i); 208 | 209 | // If changed_list is not NULL while calling maxflow(), then the algorithm 210 | // keeps a list of nodes which could potentially have changed their segmentation label. 211 | // Nodes which are not in the list are guaranteed to keep their old segmentation label (SOURCE or SINK). 212 | // Example usage: 213 | // 214 | // typedef Graph G; 215 | // G* g = new Graph(nodeNum, edgeNum); 216 | // Block* changed_list = new Block(128); 217 | // 218 | // ... // add nodes and edges 219 | // 220 | // g->maxflow(); // first call should be without arguments 221 | // for (int iter=0; iter<10; iter++) 222 | // { 223 | // ... // change graph, call mark_node() accordingly 224 | // 225 | // g->maxflow(true, changed_list); 226 | // G::node_id* ptr; 227 | // for (ptr=changed_list->ScanFirst(); ptr; ptr=changed_list->ScanNext()) 228 | // { 229 | // G::node_id i = *ptr; assert(i>=0 && iremove_from_changed_list(i); 231 | // // do something with node i... 232 | // if (g->what_segment(i) == G::SOURCE) { ... } 233 | // } 234 | // changed_list->Reset(); 235 | // } 236 | // delete changed_list; 237 | // 238 | // NOTE: 239 | // - If changed_list option is used, then reuse_trees must be used as well. 240 | // - In the example above, the user may omit calls g->remove_from_changed_list(i) and changed_list->Reset() in a given iteration. 241 | // Then during the next call to maxflow(true, &changed_list) new nodes will be added to changed_list. 242 | // - If the next call to maxflow() does not use option reuse_trees, then calling remove_from_changed_list() 243 | // is not necessary. ("changed_list->Reset()" or "delete changed_list" should still be called, though). 244 | void remove_from_changed_list(node_id i) 245 | { 246 | assert(i>=0 && i* g0); 251 | 252 | 253 | 254 | 255 | ///////////////////////////////////////////////////////////////////////// 256 | ///////////////////////////////////////////////////////////////////////// 257 | ///////////////////////////////////////////////////////////////////////// 258 | 259 | private: 260 | // internal variables and functions 261 | 262 | struct node 263 | { 264 | arc *first; // first outcoming arc 265 | 266 | arc *parent; // node's parent 267 | node *next; // pointer to the next active node 268 | // (or to itself if it is the last node in the list) 269 | int TS; // timestamp showing when DIST was computed 270 | int DIST; // distance to the terminal 271 | int is_sink : 1; // flag showing whether the node is in the source or in the sink tree (if parent!=NULL) 272 | int is_marked : 1; // set by mark_node() 273 | int is_in_changed_list : 1; // set by maxflow if 274 | 275 | tcaptype tr_cap; // if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node 276 | // otherwise -tr_cap is residual capacity of the arc node->SINK 277 | 278 | }; 279 | 280 | struct arc 281 | { 282 | node *head; // node the arc points to 283 | arc *next; // next arc with the same originating node 284 | arc *sister; // reverse arc 285 | 286 | captype r_cap; // residual capacity 287 | }; 288 | 289 | struct nodeptr 290 | { 291 | node *ptr; 292 | nodeptr *next; 293 | }; 294 | static const int NODEPTR_BLOCK_SIZE = 128; 295 | 296 | node *nodes, *node_last, *node_max; // node_last = nodes+node_num, node_max = nodes+node_num_max; 297 | arc *arcs, *arc_last, *arc_max; // arc_last = arcs+2*edge_num, arc_max = arcs+2*edge_num_max; 298 | 299 | int node_num; 300 | 301 | DBlock *nodeptr_block; 302 | 303 | void (*error_function)(const char *); // this function is called if a error occurs, 304 | // with a corresponding error message 305 | // (or exit(1) is called if it's NULL) 306 | 307 | flowtype flow; // total flow 308 | 309 | // reusing trees & list of changed pixels 310 | int maxflow_iteration; // counter 311 | Block *changed_list; 312 | 313 | ///////////////////////////////////////////////////////////////////////// 314 | 315 | node *queue_first[2], *queue_last[2]; // list of active nodes 316 | nodeptr *orphan_first, *orphan_last; // list of pointers to orphans 317 | int TIME; // monotonically increasing global counter 318 | 319 | ///////////////////////////////////////////////////////////////////////// 320 | 321 | void reallocate_nodes(int num); // num is the number of new nodes 322 | void reallocate_arcs(); 323 | 324 | // functions for processing active list 325 | void set_active(node *i); 326 | node *next_active(); 327 | 328 | // functions for processing orphans list 329 | void set_orphan_front(node* i); // add to the beginning of the list 330 | void set_orphan_rear(node* i); // add to the end of the list 331 | 332 | void add_to_changed_list(node* i); 333 | 334 | void maxflow_init(); // called if reuse_trees == false 335 | void maxflow_reuse_trees_init(); // called if reuse_trees == true 336 | void augment(arc *middle_arc); 337 | void process_source_orphan(node *i); 338 | void process_sink_orphan(node *i); 339 | 340 | void test_consistency(node* current_node=NULL); // debug function 341 | }; 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | /////////////////////////////////////// 354 | // Implementation - inline functions // 355 | /////////////////////////////////////// 356 | 357 | 358 | 359 | template 360 | inline typename Graph::node_id Graph::add_node(int num) 361 | { 362 | assert(num > 0); 363 | 364 | if (node_last + num > node_max) reallocate_nodes(num); 365 | 366 | if (num == 1) 367 | { 368 | node_last -> first = NULL; 369 | node_last -> tr_cap = 0; 370 | node_last -> is_marked = 0; 371 | node_last -> is_in_changed_list = 0; 372 | 373 | node_last ++; 374 | return node_num ++; 375 | } 376 | else 377 | { 378 | memset(node_last, 0, num*sizeof(node)); 379 | 380 | node_id i = node_num; 381 | node_num += num; 382 | node_last += num; 383 | return i; 384 | } 385 | } 386 | 387 | template 388 | inline void Graph::add_tweights(node_id i, tcaptype cap_source, tcaptype cap_sink) 389 | { 390 | assert(i >= 0 && i < node_num); 391 | 392 | tcaptype delta = nodes[i].tr_cap; 393 | if (delta > 0) cap_source += delta; 394 | else cap_sink -= delta; 395 | flow += (cap_source < cap_sink) ? cap_source : cap_sink; 396 | nodes[i].tr_cap = cap_source - cap_sink; 397 | } 398 | 399 | template 400 | inline void Graph::add_edge(node_id _i, node_id _j, captype cap, captype rev_cap) 401 | { 402 | assert(_i >= 0 && _i < node_num); 403 | assert(_j >= 0 && _j < node_num); 404 | assert(_i != _j); 405 | assert(cap >= 0); 406 | assert(rev_cap >= 0); 407 | 408 | if (arc_last == arc_max) reallocate_arcs(); 409 | 410 | arc *a = arc_last ++; 411 | arc *a_rev = arc_last ++; 412 | 413 | node* i = nodes + _i; 414 | node* j = nodes + _j; 415 | 416 | a -> sister = a_rev; 417 | a_rev -> sister = a; 418 | a -> next = i -> first; 419 | i -> first = a; 420 | a_rev -> next = j -> first; 421 | j -> first = a_rev; 422 | a -> head = j; 423 | a_rev -> head = i; 424 | a -> r_cap = cap; 425 | a_rev -> r_cap = rev_cap; 426 | } 427 | 428 | template 429 | inline typename Graph::arc* Graph::get_first_arc() 430 | { 431 | return arcs; 432 | } 433 | 434 | template 435 | inline typename Graph::arc* Graph::get_next_arc(arc* a) 436 | { 437 | return a + 1; 438 | } 439 | 440 | template 441 | inline void Graph::get_arc_ends(arc* a, node_id& i, node_id& j) 442 | { 443 | assert(a >= arcs && a < arc_last); 444 | i = (node_id) (a->sister->head - nodes); 445 | j = (node_id) (a->head - nodes); 446 | } 447 | 448 | template 449 | inline tcaptype Graph::get_trcap(node_id i) 450 | { 451 | assert(i>=0 && i 456 | inline captype Graph::get_rcap(arc* a) 457 | { 458 | assert(a >= arcs && a < arc_last); 459 | return a->r_cap; 460 | } 461 | 462 | template 463 | inline void Graph::set_trcap(node_id i, tcaptype trcap) 464 | { 465 | assert(i>=0 && i 470 | inline void Graph::set_rcap(arc* a, captype rcap) 471 | { 472 | assert(a >= arcs && a < arc_last); 473 | a->r_cap = rcap; 474 | } 475 | 476 | 477 | template 478 | inline typename Graph::termtype Graph::what_segment(node_id i, termtype default_segm) 479 | { 480 | if (nodes[i].parent) 481 | { 482 | return (nodes[i].is_sink) ? SINK : SOURCE; 483 | } 484 | else 485 | { 486 | return default_segm; 487 | } 488 | } 489 | 490 | template 491 | inline void Graph::mark_node(node_id _i) 492 | { 493 | node* i = nodes + _i; 494 | if (!i->next) 495 | { 496 | /* it's not in the list yet */ 497 | if (queue_last[1]) queue_last[1] -> next = i; 498 | else queue_first[1] = i; 499 | queue_last[1] = i; 500 | i -> next = i; 501 | } 502 | i->is_marked = 1; 503 | } 504 | 505 | 506 | #endif 507 | -------------------------------------------------------------------------------- /GCO_README.TXT: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # # 3 | # GCoptimization - software for energy minimization with graph cuts # 4 | # Version 3.0 # 5 | # http://www.csd.uwo.ca/faculty/olga/software.html # 6 | # # 7 | # Copyright 2007-2010 Olga Veksler # 8 | # Andrew Delong # 9 | # # 10 | ############################################################################## 11 | 12 | C++ requires at least Visual C++ 2005 (VC8) or GCC 4.03. Supports 32 or 64-bit. 13 | See matlab/README.TXT for bundled MATLAB wrapper and its documentation. 14 | 15 | IMPORTANT: 16 | To use this software, YOU MUST CITE the following in any resulting publication: 17 | 18 | [1] Efficient Approximate Energy Minimization via Graph Cuts. 19 | Y. Boykov, O. Veksler, R.Zabih. IEEE TPAMI, 20(12):1222-1239, Nov 2001. 20 | 21 | [2] What Energy Functions can be Minimized via Graph Cuts? 22 | V. Kolmogorov, R.Zabih. IEEE TPAMI, 26(2):147-159, Feb 2004. 23 | 24 | [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms for 25 | Energy Minimization in Vision. Y. Boykov, V. Kolmogorov. 26 | IEEE TPAMI, 26(9):1124-1137, Sep 2004. 27 | 28 | Furthermore, if you use the label cost feature (setLabelCost), you should cite 29 | 30 | [4] Fast Approximate Energy Minimization with Label Costs. 31 | A. Delong, A. Osokin, H. N. Isack, Y. Boykov. In CVPR, June 2010. 32 | 33 | This software can be used only for research purposes. For commercial purposes, 34 | be aware that there is a US patent on the main algorithm itself: 35 | 36 | R. Zabih, Y. Boykov, O. Veksler, 37 | "System and method for fast approximate energy minimization via graph cuts", 38 | United Stated Patent 6,744,923, June 1, 2004 39 | 40 | Together with this library implemented by O. Veksler, we provide, with the 41 | permission of the V. Kolmogorov and Y. Boykov, the following two libraries: 42 | 43 | 1) energy.h 44 | Developed by V. Kolmogorov, this implements the binary energy minimization 45 | technique described in [2] above. We use this to implement the binary 46 | energy minimization step for the alpha-expansion and swap algorithms. 47 | The graph construction provided by "energy.h" is more efficient than 48 | the original graph construction for alpha-expansion described in [1]. 49 | 50 | Again, this software can be used only for research purposes. IF YOU USE 51 | THIS SOFTWARE (energy.h), YOU SHOULD CITE THE AFOREMENTIONED PAPER [2] 52 | IN ANY RESULTING PUBLICATION. 53 | 54 | 2) maxflow.cpp, graph.cpp, graph.h, block.h 55 | Developed by Y. Boykov and V. Kolmogorov while at Siemens Corporate Research, 56 | algorithm [3] was later reimplemented by V. Kolmogorov based on open publications 57 | and we use his implementation here with permission. 58 | 59 | If you use either of these libraries for research purposes, you should cite 60 | the aforementioned papers in any resulting publication. 61 | 62 | ################################################################## 63 | 64 | 2. License & disclaimer. 65 | 66 | Copyright 2007-2010 Olga Veksler 67 | Andrew Delong 68 | 69 | This software and its modifications can be used and distributed for 70 | research purposes only. Publications resulting from use of this code 71 | must cite publications according to the rules given above. Only 72 | Olga Veksler has the right to redistribute this code, unless expressed 73 | permission is given otherwise. Commercial use of this code, any of 74 | its parts, or its modifications is not permited. The copyright notices 75 | must not be removed in case of any modifications. This Licence 76 | commences on the date it is electronically or physically delivered 77 | to you and continues in effect unless you fail to comply with any of 78 | the terms of the License and fail to cure such breach within 30 days 79 | of becoming aware of the breach, in which case the Licence automatically 80 | terminates. This Licence is governed by the laws of Canada and all 81 | disputes arising from or relating to this Licence must be brought 82 | in Toronto, Ontario. 83 | 84 | 85 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 86 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 87 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 88 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 89 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 90 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 91 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 92 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 93 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 94 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 95 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 96 | 97 | ################################################################## 98 | 99 | 100 | 3. Energy Minimization 101 | 102 | This software is for minimizing sums of three types of terms: 103 | 104 | E(labeling) = DataCosts(labeling) + SmoothCosts(labeling) + LabelCosts(labeling). 105 | 106 | More specifically, 107 | 108 | DataCosts(l) = sum_p D_p(l_p) where l_p is a potential label for site p, 109 | and D_p is the cost of assigning l_p, 110 | 111 | SmoothCosts(l) = sum_pq V_pq(l_p,l_q) where p and q are two distinct site, and 112 | V_pq is the cost for assigning l_p, l_q, and 113 | 114 | LabelCosts(l) = sum_L' h_L'(l) where L' is some subset of labels L, and h_L' 115 | adds a cost iff at least one label from L' 116 | appears in the labeling l. 117 | 118 | Here we have a finite set of sites (or pixels) P and a finite set of labels L. 119 | A labeling l is assignments of labels in L to pixels in P. The individual pixels 120 | are referred to with small letters p and q, label of pixel p is denoted by l_p, 121 | and the set of all label-pixel assignments is denoted by l, that is 122 | l = {l_p | p in P}. 123 | 124 | The first term in the energy function E(l) is typically called the data term, and 125 | it consists of the sum over all pixels p of the penalty(or cost) D(p,l_p), what 126 | should be the cost of assigning label l_p to pixel p. D(p,l_p) can be arbitrary. 127 | 128 | The second term is a sum over all pairs of neighboring pixels {p,q}. 129 | That is there is a neighborhood relation on the set of pixels (this relationship 130 | is symmetric, that is if p is a neighbor of q then q is a neighbor of p). 131 | Here we assume that the neighbor pairs are unordered. This means that if pixels p and q are 132 | neighbors, then there is either Vpq(l_p,l_q) in the second sum of the energy, 133 | or Vqp(l_q,l_p), but not both. This is not a restriction, since in practice, one can always go 134 | from the ordered energy to the unordered one. This second term is typically called the smoothness 135 | term. 136 | 137 | The third term is a sum over all labels (or, more generally, all subsets of labels) 138 | such that each label can have non-negative penalties associated with its use. 139 | This "label cost" feature is used to encourage labelings that use as fewer unique labels 140 | or, more generally, labels from as few unique subsets as possible. 141 | 142 | The expansion algorithm for energy minimization can be used whenever for any 3 labels a,b,c 143 | V(a,a) + V(b,c) <= V(a,c)+V(b,a). In other words, expansion algorithm can be used if 144 | the binary energy for the expansion algorithm step is regular, using V. Kolmogorov's terminology. 145 | 146 | The swap algorithm for energy minimization can be used whenever for any 2 labels a,b 147 | V(a,a) + V(b,b) <= V(a,b)+V(b,a). In other words, swap algorithm can be used if 148 | the binary energy for the swap algorithm step is regular, using V. Kolmogorov's terminology. 149 | 150 | ################################################################## 151 | 152 | 4. Data Types 153 | 154 | Inside the GCoptimization.h file you can customize the following typedefs: 155 | 156 | typedef SiteID; // index of a site (pixel); default is int32 157 | typedef LabelID; // index of a label; default is int32 158 | typedef EnergyType; // total energy value; default is int64 159 | typedef EnergyTermType; // individual energy term; default is int32 160 | 161 | For efficiency it is best to use integral types when possible; be sure that they are 162 | large enough to avoid integer overflow. By default, the library will warn if energy 163 | terms are dangerously large (larger than GCO_MAX_ENERGYTERM=10000000). Even with float 164 | types it's best to avoid extremely large energy terms, because it introduces rounding 165 | errors, and the behaviour of the algorithm is undefined if Inf or NaN values appear 166 | in the energy terms. 167 | 168 | Keep in mind that float/double may cause expansion/swap to report small increase in energy, 169 | due to arithmetic error during max-flow computation. 170 | 171 | ########################################################################### 172 | 173 | 5. Specifying the energy 174 | 175 | Before optimizing the energy, one has to specify it, that is specify the number of 176 | labels, number of pixels, neighborhood system, the data terms, and the smoothness terms. 177 | There are 2 constructors to use, one in case of the grid graph, and another in case 178 | of a general graph. 179 | In all cases, it is assumed that the sites go between 0...num_sites-1, 180 | and labels go between 0....num_labels-1. 181 | For a grid (4-connected) graph, site at coordinates (x,y) is numbered with x+y*width, where width 182 | is the width of the grid, that is the row-major ordering of arrays is assumed. 183 | ________________________________________________________________________________________________ 184 | 185 | Constructor A. 186 | 187 | GCoptimizationGridGraph(int width, int height,int num_labels); 188 | 189 | Use this constructor only for grid of size width by height. If you use this constructor, 190 | 4 connected grid neigbhorhood structure is assumed, so you don't need to specify neighborhood 191 | structure separately (and indeed cannot do so). 192 | _______________________________________________________________________________________________ 193 | 194 | Constructor B. 195 | 196 | GCoptimizationGeneralGraph(int num_sites,int num_labels); 197 | 198 | 199 | Use this constructor for general graphs. If you use this constructor, you must setup up 200 | neighborhood system using function. You can either specify neighbors individually or all at once. 201 | 202 | i) setNeighbors(SiteID s1, SiteID s2, EnergyTermType weight=1); 203 | Specifies neighbors individually. You must call this function exactly once for any 204 | pair of neighboring sites s1 and s2. That is if you call setNeighbors(s1,s2) then you should not call 205 | setNeighbors(s2,s1). If Vpq(l_p,l_q) = V(l_p,l_q)*w_pq, where V(l_p,l_q) is some function that 206 | depends only on the labels l_p,l_q, then specify w_pq by using: setNeighbors(p,q,w_pq). 207 | 208 | ii) To pass in all neighbor information at once, use function: 209 | 210 | void setAllNeighbors(SiteID *numNeighbors,SiteID **neighborsIndexes,EnergyTermType **neighborsWeights); 211 | Here: 212 | (a) numNeighbors is an array of size num_sites, and numNeighbors[i] is the number of neighbors for site i 213 | 214 | (b) neighborIndexes is an array of size num_pixels which stores of pointers. Namely, 215 | neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i 216 | 217 | (c) neighborWeights is an array of size num_sites, and neighborWeighs[i] is a pointer to array 218 | storing the weights between site i and its neighbors in the same order as neighborIndexes[i] 219 | stores the indexes of neighbors. Example: if sites i and j are neighbors, then 220 | for some k and m, neighborsIndexes[i][k] == j and neighborsIndexes[j][m] = i. Then 221 | neighborWeights[i][k] = w_ij and neighborWeights[j][m] = w_ij, where w_ij is the weight 222 | betwen neighbors i and j, that is V_ij = w_ij *V(l_i,l_j) 223 | 224 | 225 | _______________________________________________________________________________________________ 226 | 227 | 228 | 6. Setting the data costs, smooth costs, and label costs. 229 | 230 | The following functions can be called any time before or after expansion. 231 | 232 | 233 | ------------------------Data Costs (unary terms)----------------------- 234 | 235 | (a) void setDataCost(EnergyTermType *dataArray); 236 | dataArray is an array s.t. the data cost for pixel p and label l is stored at 237 | dataArray[pixel*num_labels+l]. If the current neighborhood system is a grid, then 238 | the data term for label l and pixel with coordinates (x,y) is stored at 239 | dataArray[(x+y*width)*num_labels + l]. Thus the size of array dataArray is num_pixels*num_labels. 240 | Can call this function only one time. 241 | 242 | (b) void setDataCost(DataCostFn fn); 243 | DataCostFn is a pointer to a function f(Pixel p, Label l), s.t. the data cost for pixel p to have 244 | label l is given by f(p,l). Can call this function only one time. 245 | 246 | (c) void setDataCost(DataCostFnExtra fn,void *extraData); 247 | DataCostFnExtra is a pointer to a function f(SiteID p, LabelID l,void *extraData), s.t. the data 248 | cost for pixel p to have label l is given by f(p,l,extraData). Can call this function only one time. 249 | 250 | (d) void setDataCost(SiteID s, LabelID l, EnergyTermType e); 251 | sets up D(s,l) = 3; You must call this function for each pixel and each label. 252 | 253 | (e) void setDataCostFunctor(DataCostFunctor* f); 254 | Experienced C++ users can subclass our DataCostFunctor base class to achieve 255 | a similar functionality as (b) or (c) above. By overriding the compute() method 256 | of DataCostFunctor, your compute() method will be called by the GCoptimization 257 | class each time a data penalty must be computed. 258 | 259 | (f) struct SparseDataCost { 260 | SiteID site; 261 | EnergyTermType cost; 262 | }; 263 | void setDataCost(LabelID l, SparseDataCost *costs, SiteID count); 264 | 265 | For some applications, each label is feasible for only a small fraction 266 | of the overall sites. One way to do this is to simply assign high cost to 267 | any infeasible site. A much more efficient way is to specify exactly 268 | which sites are feasible for each label. Do this by calling 269 | setDataCost(label, costs_for_label, num_costs_for_label) once for each 270 | label. The cost array will be copied internally, so your cost array 271 | can be freed. 272 | Note that giveDataEnergy() will add a huge constant for each site 273 | that is assigned an infeasible label in the current labeling. 274 | 275 | 276 | ------------------------Smooth Costs (pairwise terms)----------------------- 277 | 278 | (a) void setSmoothCost(EnergyTermType *V) 279 | 280 | V is an array of smoothness costs, such that V_pq(label1,label2) is stored at V[label1+num_labels*label2] 281 | If graph is a grid, then using this function only if the smooth costs are not spacially varying 282 | that is the smoothness penalty V depends only on labels, but not on sites. If the graph is 283 | not a grid, then you can specify spacially varying coefficients w_pq when you set up the 284 | neighborhood system using setNeighbor(p,q,w_pq) function. In this case, 285 | V_pq(label1,label2) = V[label1+num_labels*label2]*w_pq. This function can be called only one time. 286 | 287 | (b) void setSmoothCost(SmoothCostFn fn); 288 | 289 | fn is pointer to a function f(s1,s2,l1,l2) such that smoothness penalty for neigboring sites 290 | s1 and s2 to have labels, respectively, l1 and l2 is f(s1,s2,l1,l2). This function can be 291 | called only one time. 292 | 293 | (c) void setSmoothCost(SmoothCostFnExtra fn,void *extraData); 294 | 295 | Same as above, but can pass an extra pointer to the data needed for computation 296 | 297 | (d) void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e) 298 | 299 | sets up V(l1,l2) = e. Must call this function for each pair of labels (l1,l2). Notice 300 | that for any l1 and l2, you must call this function on (l1,l2) AND (l2,l1). 301 | V(l1,l2) has to be equal to V(l2,l1) in this case. 302 | 303 | (e) void setSmoothCostVH(EnergyTermType *V, EnergyTermType *vCosts, EnergyTermType *hCosts); 304 | 305 | This function should be used only if the graph is a grid (GCoptimizationGridGraph class). 306 | Array V is the same as above, under (a). 307 | Arrays hCosts and vCosts have the same size as the image (that is width*height), and are used to set 308 | the spatially varying coefficients w_pq. If p = (x,y) and q = (x+1,y), then 309 | w_pq = hCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x+1,y) to have labels 310 | label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*hCosts[x+y*width] 311 | If p = (x,y) and q = (x,y+q), then 312 | w_pq = vCosts[x+y*width], and so the smoothness penalty for pixels (x,y) and (x,y+1) to have labels 313 | label1 and label2, that is V_pq(label1,label2) = V[label1+num_labels*label2]*vCosts[x+y*width] 314 | This function can be only called one time. 315 | 316 | (f) void setSmoothCostFunctor(SmoothCostFunctor* f); 317 | 318 | Experienced C++ users can subclass our SmoothCostFunctor base class to achieve 319 | a similar functionality as (b) or (c) above. By overriding the compute() method 320 | of SmoothCostFunctor, your compute() method will be called by the GCoptimization 321 | class each time a smoothness penalty must be computed. 322 | 323 | 324 | ------------------------Label Costs (global indicator potentials)-------------------- 325 | 326 | (a) void setLabelCost(EnergyTermType cost); 327 | Penalize the appearance of all labels equally. Replaces all current label 328 | costs, if any. 329 | 330 | (b) void setLabelCost(EnergyTermType* costArray); 331 | Set each individual label cost separately. The costArray must have one 332 | entry for each possible label. Replaces all current label costs, if any. 333 | The cost array will be copied intenally, so your array can be freed. 334 | 335 | (c) void setLabelSubsetCost(LabelID* labels, LabelID numLabels, EnergyTermType cost); 336 | Set cost for a specific subset of labels. The cost will be imposed iff the 337 | current labeling contains at least one label from the 'labels' array. 338 | The labels array will be copied internally, so your array can be freed. 339 | 340 | ################################################################## 341 | 342 | 6. Optimizing the energy 343 | 344 | You can optimize the energy and get the resulting labeling using the following functions. Notice that they can 345 | be called as many times as one wishes after the constructor has been called and the data/smoothness terms 346 | (and the neighborhood system, if general graph) has beeen set. The initial labeling is set to consists of 347 | all 0's. Use function setLabel(SiteID pixelP, LabelID labelL), described under heading (x) in this section 348 | to initialize the labeling to anything else (but in the valid range, of course, labels must be between 349 | 0 and num_labels-1) 350 | 351 | a) EnergyType expansion(int max_num_iterations=-1); 352 | Runs the expansion algorithm until convergence (convergence is guaranteed) 353 | or, if max_num_iterations > 0, until a certain number of cycles (iterations). 354 | Returns the energy of the resulting labeling. 355 | 356 | b) bool alpha_expansion(LabelID alpha_label); 357 | Performs expansion on the label specified by alpha_label. 358 | Returns true if the energy was decreased, false otherwise. 359 | 360 | c) EnergyType swap(int max_num_iterations=-1); 361 | Runs the alpha-beta swap algorithm until convergence (convergence is guaranteed) 362 | or, if max_num_iterations > 0, until a certain number of cycles (iterations). 363 | Returns the energy of the resulting labeling. 364 | 365 | d) void alpha_beta_swap(LabelID alpha_label, LabelID beta_label); 366 | Performs swap on a pair of labels, specified by the input parameters alpha_label, beta_label. 367 | 368 | e) EnergyType compute_energy(); 369 | EnergyType giveDataEnergy(); 370 | EnergyType giveSmoothEnergy(); 371 | EnergyType giveLabelEnergy(); 372 | Returns respectively the total, data part, smooth part, and label part of the energy of the current labling. 373 | 374 | f) LabelID whatLabel(SiteID site); 375 | Returns the current label assigned to site. Can be called at any time after the constructor call. 376 | 377 | g) void setLabel(SiteID s, LabelID l); 378 | Sets the label of site s to the the input parameter l. Can be called at any time after 379 | the constructor call. This is useful for initializing the labeling to something specific 380 | before optimization starts. 381 | 382 | h) void setLabelOrder(bool RANDOM_LABEL_ORDER); 383 | By default, the labels for the swap and expansion algorithms are visited in not random order, 384 | but random label visitation might give better results. To set the label order to 385 | be not random, call setLabelOrder(false). To set it to be random, call setLabelOrder(true). Notice, 386 | that by using functions under heading (iii) and (vii) you can completely and exactly specify the desired 387 | order on labels. 388 | 389 | ################################################################## 390 | 391 | 7. Example usage. 392 | 393 | See example.cpp for C++ example, or see matlab\README.TXT for MATLAB example. 394 | 395 | -------------------------------------------------------------------------------- /include/GCoptimization.h: -------------------------------------------------------------------------------- 1 | /* 2 | ############################################################################## 3 | # # 4 | # GCoptimization - software for energy minimization with graph cuts # 5 | # Version 3.0 # 6 | # http://www.csd.uwo.ca/faculty/olga/software.html # 7 | # # 8 | # Copyright 2007-2010 Olga Veksler (olga@csd.uwo.ca) # 9 | # Andrew Delong (andrew.delong@gmail.com) # 10 | # # 11 | ############################################################################## 12 | 13 | C++ requires at least Visual C++ 2005 (VC8) or GCC 4.03. Supports 32 or 64-bit. 14 | See matlab/README.TXT for bundled MATLAB wrapper and its documentation. 15 | 16 | IMPORTANT: 17 | To use this software, YOU MUST CITE the following in any resulting publication: 18 | 19 | [1] Efficient Approximate Energy Minimization via Graph Cuts. 20 | Y. Boykov, O. Veksler, R.Zabih. IEEE TPAMI, 20(12):1222-1239, Nov 2001. 21 | 22 | [2] What Energy Functions can be Minimized via Graph Cuts? 23 | V. Kolmogorov, R.Zabih. IEEE TPAMI, 26(2):147-159, Feb 2004. 24 | 25 | [3] An Experimental Comparison of Min-Cut/Max-Flow Algorithms for 26 | Energy Minimization in Vision. Y. Boykov, V. Kolmogorov. 27 | IEEE TPAMI, 26(9):1124-1137, Sep 2004. 28 | 29 | Furthermore, if you use the label cost feature (setLabelCost), you should cite 30 | 31 | [4] Fast Approximate Energy Minimization with Label Costs. 32 | A. Delong, A. Osokin, H. N. Isack, Y. Boykov. In CVPR, June 2010. 33 | 34 | This software can be used only for research purposes. For commercial purposes, 35 | be aware that there is a US patent on the main algorithm itself: 36 | 37 | R. Zabih, Y. Boykov, O. Veksler, 38 | "System and method for fast approximate energy minimization via graph cuts", 39 | United Stated Patent 6,744,923, June 1, 2004 40 | 41 | Together with this library implemented by O. Veksler, we provide, with the 42 | permission of the V. Kolmogorov and Y. Boykov, the following two libraries: 43 | 44 | 1) energy.h 45 | Developed by V. Kolmogorov, this implements the binary energy minimization 46 | technique described in [2] above. We use this to implement the binary 47 | energy minimization step for the alpha-expansion and swap algorithms. 48 | The graph construction provided by "energy.h" is more efficient than 49 | the original graph construction for alpha-expansion described in [1]. 50 | 51 | Again, this software can be used only for research purposes. IF YOU USE 52 | THIS SOFTWARE (energy.h), YOU SHOULD CITE THE AFOREMENTIONED PAPER [2] 53 | IN ANY RESULTING PUBLICATION. 54 | 55 | 2) maxflow.cpp, graph.cpp, graph.h, block.h 56 | Developed by Y. Boykov and V. Kolmogorov while at Siemens Corporate Research, 57 | algorithm [3] was later reimplemented by V. Kolmogorov based on open publications 58 | and we use his implementation here with permission. 59 | 60 | If you use either of these libraries for research purposes, you should cite 61 | the aforementioned papers in any resulting publication. 62 | 63 | ################################################################## 64 | 65 | License & disclaimer. 66 | 67 | Copyright 2007-2010 Olga Veksler 68 | Andrew Delong 69 | 70 | This software and its modifications can be used and distributed for 71 | research purposes only. Publications resulting from use of this code 72 | must cite publications according to the rules given above. Only 73 | Olga Veksler has the right to redistribute this code, unless expressed 74 | permission is given otherwise. Commercial use of this code, any of 75 | its parts, or its modifications is not permited. The copyright notices 76 | must not be removed in case of any modifications. This Licence 77 | commences on the date it is electronically or physically delivered 78 | to you and continues in effect unless you fail to comply with any of 79 | the terms of the License and fail to cure such breach within 30 days 80 | of becoming aware of the breach, in which case the Licence automatically 81 | terminates. This Licence is governed by the laws of Canada and all 82 | disputes arising from or relating to this Licence must be brought 83 | in Toronto, Ontario. 84 | 85 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 86 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 87 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 88 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 89 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 90 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 91 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 92 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 93 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 94 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 95 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 96 | 97 | ################################################################## 98 | */ 99 | 100 | #ifndef __GCOPTIMIZATION_H__ 101 | #define __GCOPTIMIZATION_H__ 102 | // Due to quiet bugs in function template specialization, it is not 103 | // safe to use earlier MS compilers. 104 | #if defined(_MSC_VER) && _MSC_VER < 1400 105 | #error Requires Visual C++ 2005 (VC8) compiler or later. 106 | #endif 107 | 108 | #include 109 | #include "../include/energy.h" 110 | #include "../src/graph.cpp" 111 | #include "../src/maxflow.cpp" 112 | 113 | ///////////////////////////////////////////////////////////////////// 114 | // Utility functions, classes, and macros 115 | ///////////////////////////////////////////////////////////////////// 116 | 117 | class GCException { 118 | public: 119 | const char* message; 120 | GCException( const char* m ): message(m) { } 121 | void Report(); 122 | }; 123 | 124 | #ifdef _WIN32 125 | typedef __int64 gcoclock_t; 126 | #else 127 | #include 128 | typedef clock_t gcoclock_t; 129 | #endif 130 | extern "C" gcoclock_t gcoclock(); // fairly high-resolution timer... better than clock() when available 131 | extern "C" gcoclock_t GCO_CLOCKS_PER_SEC; // this variable will stay 0 until gcoclock() is called for the first time 132 | 133 | #ifdef _MSC_EXTENSIONS 134 | #define OLGA_INLINE __forceinline 135 | #else 136 | #define OLGA_INLINE inline 137 | #endif 138 | 139 | #ifndef GCO_MAX_ENERGYTERM 140 | #define GCO_MAX_ENERGYTERM 10000000 // maximum safe coefficient to avoid integer overflow 141 | // if a data/smooth/label cost term is larger than this, 142 | // the library will raise an exception 143 | #endif 144 | 145 | #if defined(GCO_ENERGYTYPE) && !defined(GCO_ENERGYTERMTYPE) 146 | #define GCO_ENERGYTERMTYPE GCO_ENERGYTYPE 147 | #endif 148 | #if !defined(GCO_ENERGYTYPE) && defined(GCO_ENERGYTERMTYPE) 149 | #define GCO_ENERGYTYPE GCO_ENERGYTERMTYPE 150 | #endif 151 | 152 | 153 | ///////////////////////////////////////////////////////////////////// 154 | // GCoptimization class 155 | ///////////////////////////////////////////////////////////////////// 156 | class LinkedBlockList; 157 | 158 | class GCoptimization 159 | { 160 | public: 161 | #ifdef GCO_ENERGYTYPE 162 | typedef GCO_ENERGYTYPE EnergyType; 163 | typedef GCO_ENERGYTERMTYPE EnergyTermType; 164 | #else 165 | #ifdef GCO_ENERGYTYPE32 166 | typedef int EnergyType; // 32-bit energy total 167 | #else 168 | typedef long long EnergyType; // 64-bit energy total 169 | #endif 170 | typedef int EnergyTermType; // 32-bit energy terms 171 | #endif 172 | typedef Energy EnergyT; 173 | typedef EnergyT::Var VarID; 174 | typedef int LabelID; // Type for labels 175 | typedef VarID SiteID; // Type for sites 176 | typedef EnergyTermType (*SmoothCostFn)(SiteID s1, SiteID s2, LabelID l1, LabelID l2); 177 | typedef EnergyTermType (*DataCostFn)(SiteID s, LabelID l); 178 | typedef EnergyTermType (*SmoothCostFnExtra)(SiteID s1, SiteID s2, LabelID l1, LabelID l2,void *); 179 | typedef EnergyTermType (*DataCostFnExtra)(SiteID s, LabelID l,void *); 180 | 181 | GCoptimization(SiteID num_sites, LabelID num_labels); 182 | virtual ~GCoptimization(); 183 | 184 | // Peforms expansion algorithm. Runs the number of iterations specified by max_num_iterations 185 | // If no input specified,runs until convergence. Returns total energy of labeling. 186 | EnergyType expansion(int max_num_iterations=-1); 187 | 188 | // Peforms expansion on one label, specified by the input parameter alpha_label 189 | bool alpha_expansion(LabelID alpha_label); 190 | 191 | // Peforms swap algorithm. Runs it the specified number of iterations. If no 192 | // input is specified,runs until convergence 193 | EnergyType swap(int max_num_iterations=-1); 194 | 195 | // Peforms swap on a pair of labels, specified by the input parameters alpha_label, beta_label 196 | void alpha_beta_swap(LabelID alpha_label, LabelID beta_label); 197 | 198 | // Peforms swap on a pair of labels, specified by the input parameters alpha_label, beta_label 199 | // only on the sitess in the specified arrays, alphaSites and betaSitess, and the array sizes 200 | // are, respectively, alpha_size and beta_size 201 | void alpha_beta_swap(LabelID alpha_label, LabelID beta_label, SiteID *alphaSites, 202 | SiteID alpha_size, SiteID *betaSites, SiteID beta_size); 203 | 204 | struct DataCostFunctor; // use this class to pass a functor to setDataCost 205 | struct SmoothCostFunctor; // use this class to pass a functor to setSmoothCost 206 | 207 | // Set cost for all (SiteID,LabelID) pairs. Default data cost is all zeros. 208 | void setDataCost(DataCostFn fn); 209 | void setDataCost(DataCostFnExtra fn, void *extraData); 210 | void setDataCost(EnergyTermType *dataArray); 211 | void setDataCost(SiteID s, LabelID l, EnergyTermType e); 212 | void setDataCostFunctor(DataCostFunctor* f); 213 | struct DataCostFunctor { 214 | virtual EnergyTermType compute(SiteID s, LabelID l) = 0; 215 | }; 216 | // Set cost of assigning 'l' to a specific subset of sites. 217 | // The sites are listed as (SiteID,cost) pairs. 218 | struct SparseDataCost { 219 | SiteID site; 220 | EnergyTermType cost; 221 | }; 222 | void setDataCost(LabelID l, SparseDataCost *costs, SiteID count); 223 | 224 | // Set cost for all (LabelID,LabelID) pairs; the actual smooth cost is then weighted 225 | // at each pair of on neighbors. Defaults to Potts model (0 if l1==l2, 1 otherwise) 226 | void setSmoothCost(SmoothCostFn fn); 227 | void setSmoothCost(SmoothCostFnExtra fn, void *extraData); 228 | void setSmoothCost(LabelID l1, LabelID l2, EnergyTermType e); 229 | void setSmoothCost(EnergyTermType *smoothArray); 230 | void setSmoothCostFunctor(SmoothCostFunctor* f); 231 | struct SmoothCostFunctor { 232 | virtual EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2) = 0; 233 | }; 234 | 235 | // Sets the cost of using label in the solution. 236 | // Set either as uniform cost, or an individual per-label cost. 237 | void setLabelCost(EnergyTermType cost); 238 | void setLabelCost(EnergyTermType* costArray); 239 | void setLabelSubsetCost(LabelID* labels, LabelID numLabels, EnergyTermType cost); 240 | 241 | // Returns current label assigned to input site 242 | LabelID whatLabel(SiteID site); 243 | void whatLabel(SiteID start, SiteID count, LabelID* labeling); 244 | 245 | // This function can be used to change the label of any site at any time 246 | void setLabel(SiteID site, LabelID label); 247 | 248 | // setLabelOrder(false) sets the order to be not random; setLabelOrder(true) 249 | // sets the order to random. By default, the labels are visited in non-random order 250 | // for both the swap and alpha-expansion moves 251 | // Note that srand() must be initialized with an appropriate seed in order for 252 | // random order to take effect! 253 | void setLabelOrder(bool isRandom); 254 | void setLabelOrder(const LabelID* order, LabelID size); 255 | 256 | // Returns total energy for the current labeling 257 | EnergyType compute_energy(); 258 | 259 | // Returns separate Data, Smooth, and Label energy of current labeling 260 | EnergyType giveDataEnergy(); 261 | EnergyType giveSmoothEnergy(); 262 | EnergyType giveLabelEnergy(); 263 | 264 | // Returns number of sites/labels as specified in the constructor 265 | SiteID numSites() const; 266 | LabelID numLabels() const; 267 | 268 | // Prints output to stdout during exansion/swap execution. 269 | // 0 => no output 270 | // 1 => cycle-level output (cycle number, current energy) 271 | // 2 => expansion-/swap-level output (label(s), current energy) 272 | void setVerbosity(int level) { m_verbosity = level; } 273 | 274 | protected: 275 | struct LabelCost { 276 | ~LabelCost() { delete [] labels; } 277 | EnergyTermType cost; 278 | bool active; // flag indicates if this particular labelcost is in effect (i.e. wrt m_labeling) 279 | VarID aux; 280 | LabelCost* next; // global list of LabelSetCost records 281 | LabelID numLabels; 282 | LabelID* labels; 283 | }; 284 | 285 | struct LabelCostIter { 286 | LabelCost* node; 287 | LabelCostIter* next; // local list of LabelSetCost records that contain this label 288 | }; 289 | 290 | LabelID m_num_labels; 291 | SiteID m_num_sites; 292 | LabelID *m_labeling; 293 | SiteID *m_lookupSiteVar; // holds index of variable corresponding to site participating in a move, 294 | // -1 for nonparticipating site 295 | LabelID *m_labelTable; // to figure out label order in which to do expansion/swaps 296 | int m_stepsThisCycle; 297 | int m_stepsThisCycleTotal; 298 | int m_random_label_order; 299 | EnergyTermType* m_datacostIndividual; 300 | EnergyTermType* m_smoothcostIndividual; 301 | EnergyTermType* m_labelingDataCosts; 302 | SiteID* m_labelCounts; 303 | SiteID* m_activeLabelCounts; 304 | LabelCost* m_labelcostsAll; 305 | LabelCostIter** m_labelcostsByLabel; 306 | int m_labelcostCount; 307 | bool m_labelingInfoDirty; 308 | int m_verbosity; 309 | 310 | void* m_datacostFn; 311 | void* m_smoothcostFn; 312 | EnergyType m_beforeExpansionEnergy; 313 | 314 | SiteID *m_numNeighbors; // holds num of neighbors for each site 315 | SiteID m_numNeighborsTotal; // holds total num of neighbor relationships 316 | 317 | EnergyType (GCoptimization::*m_giveSmoothEnergyInternal)(); 318 | SiteID (GCoptimization::*m_queryActiveSitesExpansion)(LabelID, SiteID*); 319 | void (GCoptimization::*m_setupDataCostsExpansion)(SiteID,LabelID,EnergyT*,SiteID*); 320 | void (GCoptimization::*m_setupSmoothCostsExpansion)(SiteID,LabelID,EnergyT*,SiteID*); 321 | void (GCoptimization::*m_setupDataCostsSwap)(SiteID,LabelID,LabelID,EnergyT*,SiteID*); 322 | void (GCoptimization::*m_setupSmoothCostsSwap)(SiteID,LabelID,LabelID,EnergyT*,SiteID*); 323 | void (GCoptimization::*m_applyNewLabeling)(EnergyT*,SiteID*,SiteID,LabelID); 324 | void (GCoptimization::*m_updateLabelingDataCosts)(); 325 | 326 | void (*m_datacostFnDelete)(void* f); 327 | void (*m_smoothcostFnDelete)(void* f); 328 | bool (GCoptimization::*m_solveSpecialCases)(EnergyType&); 329 | 330 | // returns a pointer to the neighbors of a site and the weights 331 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights)=0; 332 | virtual void finalizeNeighbors() = 0; 333 | 334 | struct DataCostFnFromArray { 335 | DataCostFnFromArray(EnergyTermType* theArray, LabelID num_labels) 336 | : m_array(theArray), m_num_labels(num_labels){} 337 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_array[s*m_num_labels+l];} 338 | private: 339 | const EnergyTermType* const m_array; 340 | const LabelID m_num_labels; 341 | }; 342 | 343 | struct DataCostFnFromFunction { 344 | DataCostFnFromFunction(DataCostFn fn): m_fn(fn){} 345 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_fn(s,l);} 346 | private: 347 | const DataCostFn m_fn; 348 | }; 349 | 350 | struct DataCostFnFromFunctionExtra { 351 | DataCostFnFromFunctionExtra(DataCostFnExtra fn,void *extraData): m_fn(fn),m_extraData(extraData){} 352 | OLGA_INLINE EnergyTermType compute(SiteID s, LabelID l){return m_fn(s,l,m_extraData);} 353 | private: 354 | const DataCostFnExtra m_fn; 355 | void *m_extraData; 356 | }; 357 | 358 | struct SmoothCostFnFromArray { 359 | SmoothCostFnFromArray(EnergyTermType* theArray, LabelID num_labels) 360 | : m_array(theArray), m_num_labels(num_labels){} 361 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_array[l1*m_num_labels+l2];} 362 | private: 363 | const EnergyTermType* const m_array; 364 | const LabelID m_num_labels; 365 | }; 366 | 367 | struct SmoothCostFnFromFunction { 368 | SmoothCostFnFromFunction(SmoothCostFn fn) 369 | : m_fn(fn){} 370 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_fn(s1,s2,l1,l2);} 371 | private: 372 | const SmoothCostFn m_fn; 373 | }; 374 | 375 | struct SmoothCostFnFromFunctionExtra { 376 | SmoothCostFnFromFunctionExtra(SmoothCostFnExtra fn,void *extraData) 377 | : m_fn(fn),m_extraData(extraData){} 378 | OLGA_INLINE EnergyTermType compute(SiteID s1, SiteID s2, LabelID l1, LabelID l2){return m_fn(s1,s2,l1,l2,m_extraData);} 379 | private: 380 | const SmoothCostFnExtra m_fn; 381 | void *m_extraData; 382 | }; 383 | 384 | struct SmoothCostFnPotts { 385 | OLGA_INLINE EnergyTermType compute(SiteID, SiteID, LabelID l1, LabelID l2){return l1 != l2 ? (EnergyTermType)1 : (EnergyTermType)0;} 386 | }; 387 | 388 | ///////////////////////////////////////////////////////////////////// 389 | // DataCostFnSparse 390 | // This data cost functor maintains a simple sparse structure 391 | // to quickly find the cost associated with any (site,label) pair. 392 | ///////////////////////////////////////////////////////////////////// 393 | class DataCostFnSparse { 394 | // cLogSitesPerBucket basically controls the compression ratio 395 | // of the sparse structure: 1 => a dense array, num_sites => a single sparse list. 396 | // The amount (cLogSitesPerBucket - cLinearSearchSize) determines the maximum 397 | // number of binary search steps taken for a cost lookup for specific (site,label). 398 | // 399 | static const int cLogSitesPerBucket = 9; 400 | static const int cSitesPerBucket = (1 << cLogSitesPerBucket); 401 | static const size_t cDataCostPtrMask = ~(sizeof(SparseDataCost)-1); 402 | static const ptrdiff_t cLinearSearchSize = 64/sizeof(SparseDataCost); 403 | 404 | struct DataCostBucket { 405 | const SparseDataCost* begin; 406 | const SparseDataCost* end; // one-past-the-last item in the range 407 | const SparseDataCost* predict; // predicts the next cost to be needed 408 | }; 409 | 410 | public: 411 | DataCostFnSparse(SiteID num_sites, LabelID num_labels); 412 | DataCostFnSparse(const DataCostFnSparse& src); 413 | ~DataCostFnSparse(); 414 | 415 | void set(LabelID l, const SparseDataCost* costs, SiteID count); 416 | EnergyTermType compute(SiteID s, LabelID l); 417 | SiteID queryActiveSitesExpansion(LabelID alpha_label, const LabelID* labeling, SiteID* activeSites); 418 | 419 | class iterator { 420 | public: 421 | OLGA_INLINE iterator(): m_ptr(0) { } 422 | OLGA_INLINE iterator& operator++() { m_ptr++; return *this; } 423 | OLGA_INLINE SiteID site() const { return m_ptr->site; } 424 | OLGA_INLINE EnergyTermType cost() const { return m_ptr->cost; } 425 | OLGA_INLINE bool operator==(const iterator& b) const { return m_ptr == b.m_ptr; } 426 | OLGA_INLINE bool operator!=(const iterator& b) const { return m_ptr != b.m_ptr; } 427 | OLGA_INLINE ptrdiff_t operator- (const iterator& b) const { return m_ptr - b.m_ptr; } 428 | private: 429 | OLGA_INLINE iterator(const SparseDataCost* ptr): m_ptr(ptr) { } 430 | const SparseDataCost* m_ptr; 431 | friend class DataCostFnSparse; 432 | }; 433 | 434 | OLGA_INLINE iterator begin(LabelID label) const { return m_buckets[label*m_buckets_per_label].begin; } 435 | OLGA_INLINE iterator end(LabelID label) const { return m_buckets[label*m_buckets_per_label + m_buckets_per_label-1].end; } 436 | 437 | private: 438 | EnergyTermType search(DataCostBucket& b, SiteID s); 439 | const SiteID m_num_sites; 440 | const LabelID m_num_labels; 441 | const int m_buckets_per_label; 442 | mutable DataCostBucket* m_buckets; 443 | }; 444 | 445 | template SiteID queryActiveSitesExpansion(LabelID alpha_label, SiteID* activeSites); 446 | template void setupDataCostsExpansion(SiteID size,LabelID alpha_label,EnergyT *e,SiteID *activeSites); 447 | template void setupDataCostsSwap(SiteID size,LabelID alpha_label,LabelID beta_label,EnergyT *e,SiteID *activeSites); 448 | template void setupSmoothCostsExpansion(SiteID size,LabelID alpha_label,EnergyT *e,SiteID *activeSites); 449 | template void setupSmoothCostsSwap(SiteID size,LabelID alpha_label,LabelID beta_label,EnergyT *e,SiteID *activeSites); 450 | template void applyNewLabeling(EnergyT *e,SiteID *activeSites,SiteID size,LabelID alpha_label); 451 | template void updateLabelingDataCosts(); 452 | template void specializeDataCostFunctor(const UserFunctor f); 453 | template void specializeSmoothCostFunctor(const UserFunctor f); 454 | 455 | EnergyType setupLabelCostsExpansion(SiteID size,LabelID alpha_label,EnergyT *e,SiteID *activeSites); 456 | void updateLabelingInfo(bool updateCounts=true,bool updateActive=true,bool updateCosts=true); 457 | 458 | // Check for overflow and submodularity issues when setting up binary graph cut 459 | void addterm1_checked(EnergyT *e,VarID i,EnergyTermType e0,EnergyTermType e1); 460 | void addterm1_checked(EnergyT *e,VarID i,EnergyTermType e0,EnergyTermType e1,EnergyTermType w); 461 | void addterm2_checked(EnergyT *e,VarID i,VarID j,EnergyTermType e00,EnergyTermType e01,EnergyTermType e10,EnergyTermType e11,EnergyTermType w); 462 | 463 | // Returns Smooth Energy of current labeling 464 | template EnergyType giveSmoothEnergyInternal(); 465 | template static void deleteFunctor(void* f) { delete reinterpret_cast(f); } 466 | 467 | static void handleError(const char *message); 468 | static void checkInterrupt(); 469 | 470 | private: 471 | // Peforms one iteration (one pass over all pairs of labels) of expansion/swap algorithm 472 | EnergyType oneExpansionIteration(); 473 | EnergyType oneSwapIteration(); 474 | void printStatus1(const char* extraMsg=0); 475 | void printStatus1(int cycle, bool isSwap, gcoclock_t ticks0); 476 | void printStatus2(int alpha, int beta, int numVars, gcoclock_t ticks0); 477 | 478 | void permuteLabelTable(); 479 | 480 | template bool solveSpecialCases(EnergyType& energy); 481 | template EnergyType solveGreedy(); 482 | 483 | ///////////////////////////////////////////////////////////////////// 484 | // GreedyIter 485 | // Lets solveGreedy efficiently traverse the datacosts when 486 | // searching for the next greedy move. 487 | ///////////////////////////////////////////////////////////////////// 488 | template 489 | class GreedyIter { 490 | public: 491 | GreedyIter(DataCostT& dc, SiteID numSites) 492 | : m_dc(dc), m_site(0), m_numSites(numSites), m_label(0), m_lbegin(0), m_lend(0) 493 | { } 494 | 495 | OLGA_INLINE void start(const LabelID* labels, LabelID labelCount=1) 496 | { 497 | m_site = labelCount ? 0 : m_numSites; 498 | m_label = m_lbegin = labels; 499 | m_lend = labels + labelCount; 500 | } 501 | OLGA_INLINE SiteID site() const { return m_site; } 502 | OLGA_INLINE SiteID label() const { return *m_label; } 503 | OLGA_INLINE bool done() const { return m_site == m_numSites; } 504 | OLGA_INLINE GreedyIter& operator++() 505 | { 506 | // The inner loop is over labels, not sites, to improve memory locality. 507 | // When dc() is pulling datacosts from an array (the typical format), this can 508 | // improve performance by a factor of 2x, often more like 4x. 509 | if (++m_label >= m_lend) { 510 | m_label = m_lbegin; 511 | ++m_site; 512 | } 513 | return *this; 514 | } 515 | OLGA_INLINE EnergyTermType compute() const { return m_dc.compute(m_site,*m_label); } 516 | OLGA_INLINE SiteID feasibleSites() const { return m_numSites; } 517 | 518 | private: 519 | SiteID m_site; 520 | DataCostT& m_dc; 521 | const SiteID m_numSites; 522 | const LabelID* m_label; 523 | const LabelID* m_lbegin; 524 | const LabelID* m_lend; 525 | }; 526 | }; 527 | 528 | 529 | ////////////////////////////////////////////////////////////////////////////////////////////////// 530 | // Use this derived class for grid graphs 531 | ////////////////////////////////////////////////////////////////////////////////////////////////// 532 | 533 | class GCoptimizationGridGraph: public GCoptimization 534 | { 535 | public: 536 | GCoptimizationGridGraph(SiteID width,SiteID height,LabelID num_labels); 537 | virtual ~GCoptimizationGridGraph(); 538 | 539 | void setSmoothCostVH(EnergyTermType *smoothArray, EnergyTermType *vCosts, EnergyTermType *hCosts); 540 | 541 | protected: 542 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights); 543 | virtual void finalizeNeighbors(); 544 | EnergyTermType m_unityWeights[4]; 545 | int m_weightedGraph; // true if spatially varying w_pq's are present. False otherwise. 546 | 547 | private: 548 | SiteID m_width; 549 | SiteID m_height; 550 | SiteID *m_neighbors; // holds neighbor indexes 551 | EnergyTermType *m_neighborsWeights; // holds neighbor weights 552 | 553 | void setupNeighbData(SiteID startY,SiteID endY,SiteID startX,SiteID endX,SiteID maxInd,SiteID *indexes); 554 | void computeNeighborWeights(EnergyTermType *vCosts,EnergyTermType *hCosts); 555 | }; 556 | 557 | ////////////////////////////////////////////////////////////////////////////////////////////////// 558 | 559 | class GCoptimizationGeneralGraph:public GCoptimization 560 | { 561 | public: 562 | // This is the constructor for non-grid graphs. Neighborhood structure must be specified by 563 | // setNeighbors() function 564 | GCoptimizationGeneralGraph(SiteID num_sites,LabelID num_labels); 565 | virtual ~GCoptimizationGeneralGraph(); 566 | 567 | // Makes site1 and site2 neighbors of each other. Can be called only 1 time for each 568 | // unordered pair of sites. Parameter weight can be used to set spacially varying terms 569 | // If the desired penalty for neighboring sites site1 and site2 is 570 | // V(label1,label2) = weight*SmoothnessPenalty(label1,label2), then 571 | // member function setLabel should be called as: setLabel(site1,site2,weight) 572 | void setNeighbors(SiteID site1, SiteID site2, EnergyTermType weight=1); 573 | 574 | // passes pointers to arrays storing neighbor information 575 | // numNeighbors[i] is the number of neighbors for site i 576 | // neighborsIndexes[i] is a pointer to the array storing the sites which are neighbors to site i 577 | // neighborWeights[i] is a pointer to array storing the weights between site i and its neighbors 578 | // in the same order as neighborIndexes[i] stores the indexes 579 | void setAllNeighbors(SiteID *numNeighbors,SiteID **neighborsIndexes,EnergyTermType **neighborsWeights); 580 | 581 | protected: 582 | virtual void giveNeighborInfo(SiteID site, SiteID *numSites, SiteID **neighbors, EnergyTermType **weights); 583 | virtual void finalizeNeighbors(); 584 | 585 | private: 586 | 587 | typedef struct NeighborStruct{ 588 | SiteID to_node; 589 | EnergyTermType weight; 590 | } Neighbor; 591 | 592 | LinkedBlockList *m_neighbors; 593 | bool m_needToFinishSettingNeighbors; 594 | SiteID **m_neighborsIndexes; 595 | EnergyTermType **m_neighborsWeights; 596 | bool m_needTodeleteNeighbors; 597 | }; 598 | 599 | 600 | //////////////////////////////////////////////////////////////////// 601 | // Methods 602 | //////////////////////////////////////////////////////////////////// 603 | 604 | 605 | OLGA_INLINE GCoptimization::SiteID GCoptimization::numSites() const 606 | { 607 | return m_num_sites; 608 | } 609 | 610 | OLGA_INLINE GCoptimization::LabelID GCoptimization::numLabels() const 611 | { 612 | return m_num_labels; 613 | } 614 | 615 | OLGA_INLINE void GCoptimization::setLabel(SiteID site, LabelID label) 616 | { 617 | assert(label >= 0 && label < m_num_labels && site >= 0 && site < m_num_sites); 618 | m_labeling[site] = label; 619 | m_labelingInfoDirty = true; 620 | } 621 | 622 | OLGA_INLINE GCoptimization::LabelID GCoptimization::whatLabel(SiteID site) 623 | { 624 | assert(site >= 0 && site < m_num_sites); 625 | return m_labeling[site]; 626 | } 627 | 628 | #endif 629 | --------------------------------------------------------------------------------