├── .gitignore ├── LICENCE ├── Makefile ├── README.md ├── examples ├── example1.sh ├── example2.sh ├── example3.sh ├── example4.sh ├── example5.sh ├── example6.sh ├── example7.sh ├── example8.sh ├── example9.sh ├── example_video.sh ├── example_video_first10frames.sh └── matlab │ ├── example1.m │ ├── example2.m │ ├── example3.m │ ├── example4.m │ ├── example5.m │ ├── example6.m │ ├── fastms.m │ └── show_images.m ├── images ├── dog.png ├── dog1_original.png ├── dog2_downscaled50.png ├── dog3_downscaled25.png ├── dog4_downscaled10.png ├── florida-state-university.png ├── gaudi.png ├── hepburn.png ├── lake-powell.png ├── landscape.png ├── lighthouse.png ├── marble.png ├── mountain.png ├── peacock-feather.png ├── peacock.png ├── squirrel.png ├── the-tigers-nest.png ├── video.mp4 └── video_extract_frames.sh └── src ├── examples ├── example_batchprocessing.cpp ├── example_batchprocessing.h ├── example_gui.cpp ├── example_gui.h ├── main.cpp ├── param.h └── util.h ├── libfastms ├── solver │ ├── solver.cpp │ ├── solver.h │ ├── solver_base.cpp │ ├── solver_base.h │ ├── solver_common_operators.h │ ├── solver_device.cu │ ├── solver_device.h │ ├── solver_host.cpp │ └── solver_host.h └── util │ ├── check_cuda.cu │ ├── check_cuda.cuh │ ├── has_cuda.cpp │ ├── has_cuda.h │ ├── image.h │ ├── image_access.h │ ├── image_access_convert.h │ ├── image_access_convert_cuda.cu │ ├── image_mat.cpp │ ├── image_mat.h │ ├── mem.h │ ├── mem_cuda.cuh │ ├── real.h │ ├── sum.h │ ├── sum_cuda.cuh │ ├── timer.h │ ├── timer_cuda.cuh │ ├── types_equal.h │ └── vars_cuda.cuh └── mex ├── fastms_mex.cpp └── mex_util.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cproject 3 | .project 4 | images/video_frames 5 | images_output 6 | tmp 7 | main 8 | examples/matlab/*.mexmaci64 9 | examples/matlab/*.mexa64 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of fastms. 3 | # 4 | # 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | # 6 | # fastms is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # fastms is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with fastms. If not, see . 18 | # 19 | 20 | all: targets 21 | 22 | USE_CUDA:=1 23 | USE_OPENMP:=1 24 | USE_OPENCV:=1 25 | USE_MEX:=1 26 | 27 | TMP_DIR:=tmp 28 | 29 | 30 | 31 | LIBS:= 32 | DEFINES:= 33 | INCLUDES:= 34 | TARGETS:= 35 | 36 | SOLVER_SOURCE_DIR:=src/libfastms 37 | INCLUDES += -I$(SOLVER_SOURCE_DIR) 38 | 39 | 40 | # check if mac or linux 41 | MAC:= 42 | UNAME:=$(shell uname) 43 | ifeq ($(UNAME), Darwin) 44 | MAC:=1 45 | else ifeq ($(UNAME), Linux) 46 | else 47 | $(error Unexpected system: $(UNAME)) 48 | endif 49 | 50 | 51 | # c++ 52 | ifeq ($(MAC), 1) 53 | GXX:=/usr/local/bin/g++-4.2 54 | else 55 | GXX:=g++ 56 | endif 57 | ARGS_GXX:= 58 | ARGS_GXX += -Wall 59 | ARGS_GXX += -O3 60 | ARGS_GXX += -m64 61 | ARGS_GXX += -fPIC 62 | ifeq ($(USE_OPENMP), 1) 63 | ARGS_GXX += -fopenmp 64 | endif 65 | COMMAND_COMPILE_GXX=$(GXX) -c -o $@ $< $(ARGS_GXX) $(INCLUDES) $(DEFINES) 66 | COMMAND_GET_DEPENDENCIES_GXX=@$(GXX) -M $< $(ARGS_GXX) $(INCLUDES) $(DEFINES) > $@.dep 67 | 68 | 69 | # cuda 70 | ifeq ($(USE_CUDA), 1) 71 | NVCC:=$(shell which nvcc) 72 | ifndef NVCC 73 | $(info WARNING: NVCC not in current path, disabling CUDA in compilation.) 74 | USE_CUDA:= 75 | endif 76 | endif 77 | ifeq ($(USE_CUDA), 1) 78 | CUDA_DIR:=$(shell dirname $(NVCC))/.. 79 | ifeq ($(MAC), 1) 80 | CUDA_LIB_DIR:=$(CUDA_DIR)/lib 81 | else 82 | CUDA_LIB_DIR:=$(CUDA_DIR)/lib64 83 | endif 84 | INCLUDES += -I$(CUDA_DIR)/include 85 | LIBS += -L$(CUDA_LIB_DIR) -lcudart -lcublas 86 | ARGS_NVCC:= 87 | ARGS_NVCC += -ccbin $(GXX) 88 | ARGS_NVCC += --use_fast_math 89 | ARGS_NVCC += --compiler-options '$(ARGS_GXX)' 90 | #ARGS_NVCC += -gencode arch=compute_11,code=compute_11 91 | ARGS_NVCC += -gencode arch=compute_20,code=compute_20 92 | ARGS_NVCC += -gencode arch=compute_30,code=\"compute_30,sm_30\" 93 | #ARGS_NVCC += -gencode arch=compute_35,code=\"compute_35,sm_35\" 94 | #ARGS_NVCC += --ptxas-options=-v 95 | COMMAND_NVCC_COMPILE=$(NVCC) -c -o $@ $< $(ARGS_NVCC) $(INCLUDES) $(DEFINES) 96 | COMMAND_GET_DEPENDENCIES_NVCC=@$(NVCC) -M $< $(ARGS_NVCC) $(INCLUDES) $(DEFINES) > $@.dep 97 | else 98 | DEFINES += -DDISABLE_CUDA 99 | endif 100 | 101 | 102 | # openmp 103 | ifeq ($(USE_OPENMP), 1) 104 | LIBS += -lgomp 105 | else 106 | DEFINES += -DDISABLE_OPENMP 107 | endif 108 | 109 | 110 | # opencv 111 | ifeq ($(USE_OPENCV), 1) 112 | OPENCV_EXISTS:=$(shell pkg-config --exists opencv; echo $$?) 113 | ifneq ($(OPENCV_EXISTS), 0) 114 | $(info WARNING: OpenCV not found, disabling OpenCV in compilation.) 115 | USE_OPENCV:= 116 | endif 117 | endif 118 | ifeq ($(USE_OPENCV), 1) 119 | LIBS += -lopencv_highgui -lopencv_core 120 | else 121 | DEFINES += -DDISABLE_OPENCV 122 | endif 123 | 124 | 125 | 126 | # target: solver 127 | SOLVER_SOURCES:= 128 | SOLVER_SOURCES += $(shell find $(SOLVER_SOURCE_DIR) -name '*.cpp') 129 | ifeq ($(USE_CUDA), 1) 130 | SOLVER_SOURCES += $(shell find $(SOLVER_SOURCE_DIR) -name '*.cu') 131 | endif 132 | SOLVER_OBJECTS:=$(foreach file, $(SOLVER_SOURCES), $(TMP_DIR)/$(file).o) 133 | SOLVER_DEPENDENCIES:=$(foreach file, $(SOLVER_OBJECTS), $(file).dep) 134 | -include $(SOLVER_DEPENDENCIES) 135 | SOLVER_TARGET:=$(TMP_DIR)/$(SOLVER_SOURCE_DIR)/libfastms.o 136 | TARGETS += $(SOLVER_TARGET) 137 | COMMAND_LINK_SOLVER=ld -r -o $@ $^ 138 | 139 | 140 | 141 | # target: main 142 | MAIN_SOURCES:= 143 | MAIN_SOURCES += $(shell find src/examples -name '*.cpp') 144 | MAIN_OBJECTS:=$(foreach file, $(MAIN_SOURCES), $(TMP_DIR)/$(file).o) 145 | MAIN_OBJECTS += $(SOLVER_TARGET) 146 | MAIN_DEPENDENCIES:=$(foreach file, $(MAIN_OBJECTS), $(file).dep) 147 | -include $(MAIN_DEPENDENCIES) 148 | MAIN_TARGET:=main 149 | TARGETS += $(MAIN_TARGET) 150 | COMMAND_LINK_MAIN=$(GXX) -o $@ $^ $(LIBS) 151 | 152 | 153 | 154 | # mex 155 | ifeq ($(USE_MEX), 1) 156 | ifeq ($(MAC), 1) 157 | MATLAB_DIR:=/Applications/MATLAB_R2014a.app 158 | else 159 | MATLAB_DIR:=/usr/local/lehrstuhl/DIR/matlab-R2013b 160 | endif 161 | ifeq ($(wildcard $(MATLAB_DIR)/bin/mex),) 162 | $(info WARNING: Did not find MATLAB in the specified directory $(MATLAB_DIR), disabling mex target compilation.) 163 | USE_MEX:= 164 | endif 165 | endif 166 | ifeq ($(USE_MEX), 1) 167 | ifeq ($(MAC), 1) 168 | MEX_SUFFIX:=mexmaci64 169 | SHARED_LIB_EXT:=dylib 170 | else 171 | MEX_SUFFIX:=mexa64 172 | SHARED_LIB_EXT:=so 173 | endif 174 | 175 | MEX_SOURCES:=$(shell find src/mex -name '*.cpp') 176 | MEX_OBJECTS:=$(foreach file, $(MEX_SOURCES), $(TMP_DIR)/$(file).o) 177 | MEX_OBJECTS += $(SOLVER_TARGET) 178 | MEX_DEPENDENCIES:=$(foreach file, $(MEX_OBJECTS), $(file).dep) 179 | -include $(MEX_DEPENDENCIES) 180 | 181 | MEX_DEFINES := $(DEFINES) 182 | 183 | MEX_INCLUDES :=$(INCLUDES) -I$(MATLAB_DIR)/extern/include 184 | 185 | MATLAB_LIB_DIR:=$(shell dirname `find $(MATLAB_DIR)/bin -name libmex.$(SHARED_LIB_EXT)`) 186 | MEX_LIBS:=$(LIBS) -L$(MATLAB_LIB_DIR) -lmex -lmx 187 | 188 | MEX_TARGET:=examples/matlab/fastms_mex.$(MEX_SUFFIX) 189 | TARGETS += $(MEX_TARGET) 190 | 191 | COMMAND_COMPILE_GXX_MEX=$(GXX) -c -o $@ $< $(ARGS_GXX) $(MEX_INCLUDES) $(MEX_DEFINES) 192 | COMMAND_GET_DEPENDENCIES_GXX_MEX=@$(GXX) -M $< $(ARGS_GXX) $(MEX_INCLUDES) $(MEX_DEFINES) > $@.dep 193 | COMMAND_LINK_MEX=$(GXX) -o $@ $^ -shared $(MEX_LIBS) 194 | else 195 | DEFINES += -DDISABLE_MEX 196 | endif 197 | 198 | 199 | 200 | # common commands 201 | COMMAND_POSTPROCESS_DEPENDENCIES=@echo $@:`sed 's/.*://' $@.dep | tr "\n" " " | sed 's/\\\\/ /g'` > $@.dep; sed -e 's/^.*://' -e 's/ */::/g' $@.dep | tr ":" "\n" | sed -e 's/$$/:/' -e 's/^:$$//' >> $@.dep; echo >> $@.dep 202 | COMMAND_MAKE_TARGET_DIR=@mkdir -p $(shell dirname $@) 203 | COMMAND_CLEAN=@rm -rf $(TMP_DIR) $(TARGETS) 204 | 205 | 206 | 207 | targets: $(TARGETS) 208 | 209 | 210 | 211 | # solver 212 | $(TMP_DIR)/$(SOLVER_SOURCE_DIR)/%.cpp.o: $(SOLVER_SOURCE_DIR)/%.cpp Makefile 213 | $(COMMAND_MAKE_TARGET_DIR) 214 | $(COMMAND_COMPILE_GXX) 215 | $(COMMAND_GET_DEPENDENCIES_GXX) 216 | $(COMMAND_POSTPROCESS_DEPENDENCIES) 217 | 218 | $(TMP_DIR)/$(SOLVER_SOURCE_DIR)/%.cu.o: $(SOLVER_SOURCE_DIR)/%.cu Makefile 219 | $(COMMAND_MAKE_TARGET_DIR) 220 | $(COMMAND_NVCC_COMPILE) 221 | $(COMMAND_GET_DEPENDENCIES_NVCC) 222 | $(COMMAND_POSTPROCESS_DEPENDENCIES) 223 | 224 | $(SOLVER_TARGET): $(SOLVER_OBJECTS) 225 | $(COMMAND_MAKE_TARGET_DIR) 226 | $(COMMAND_LINK_SOLVER) 227 | 228 | 229 | 230 | # main 231 | $(TMP_DIR)/src/examples/%.cpp.o: src/examples/%.cpp Makefile 232 | $(COMMAND_MAKE_TARGET_DIR) 233 | $(COMMAND_COMPILE_GXX) 234 | $(COMMAND_GET_DEPENDENCIES_GXX) 235 | $(COMMAND_POSTPROCESS_DEPENDENCIES) 236 | 237 | $(MAIN_TARGET): $(MAIN_OBJECTS) 238 | $(COMMAND_MAKE_TARGET_DIR) 239 | $(COMMAND_LINK_MAIN) 240 | 241 | 242 | 243 | # mex 244 | $(TMP_DIR)/src/mex/%.cpp.o: src/mex/%.cpp Makefile 245 | $(COMMAND_MAKE_TARGET_DIR) 246 | $(COMMAND_COMPILE_GXX_MEX) 247 | $(COMMAND_GET_DEPENDENCIES_GXX_MEX) 248 | $(COMMAND_POSTPROCESS_DEPENDENCIES) 249 | 250 | $(MEX_TARGET): $(MEX_OBJECTS) 251 | $(COMMAND_MAKE_TARGET_DIR) 252 | $(COMMAND_LINK_MEX) 253 | 254 | 255 | 256 | clean: 257 | $(COMMAND_CLEAN) 258 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fastms 2 | 3 | This code implements the approach for the following research paper: 4 | 5 | > **Real-Time Minimization of the Piecewise Smooth Mumford-Shah Functional**, *E. Strekalovskiy, D. Cremers*, European Conference on Computer Vision (ECCV), 2014. ([pdf](https://vision.in.tum.de/_media/spezial/bib/strekalovskiy_cremers_eccv14.pdf)) ([video](https://vision.in.tum.de/_media/spezial/bib/strekalovskiy_cremers_eccv14.mp4)) 6 | 7 | ![alt tag](https://vision.in.tum.de/_media/data/software/fastms.png) 8 | 9 | The algorithms computes piecewise smooth and piecewise constant approximations to input images. The result will be smooth over more or less large regions, but is allowed to have sharp color jumps (discontinuities) between regions of smoothness. Applications range from image denoising to producing cartooning image effects. The model describning how exactly the result should look like -- the Mumford-Shah model -- has a long history and is among the most cited in computer vision. 10 | Current state-of-the-art approaches either use heuristics introducing additional artificial parameters, which leads to parameter-sensitive results, or require minutes of run time for a single VGA color image, see the above paper for more details. 11 | 12 | The approach implemented here produces state-of-the-art quality results and runs in real-time. 13 | 14 | ## Features 15 | 16 | - **GPU implementation** using CUDA, and a **CPU implementation** optionally using OpenMP. Either implementation can be chosen using a command line parameter without recompiling the code. 17 | - **float or double** precision. 18 | - **MATLAB wrapper** for quick prototyping. 19 | 20 | 21 | # 1. Installation 22 | 23 | ## 1.1 Quick start 24 | 25 | Install: 26 | 27 | git clone https://github.com/tum-vision/fastms.git 28 | 29 | cd fastms 30 | 31 | make 32 | 33 | Run: 34 | 35 | ./main 36 | 37 | Or run any of the examples, e.g. 38 | 39 | ./examples/example1.sh 40 | 41 | ## 1.2 Requirements 42 | 43 | ### CUDA: 44 | 45 | To use the **GPU implementation**, [CUDA](https://developer.nvidia.com/cuda-downloads) must be installed and *nvcc* must be in the current PATH. 46 | The code is generated for NVIDIA GPUs of [compute capability](https://developer.nvidia.com/cuda-gpus) at least 2.0 by default. 47 | If your GPU is older, uncomment the corresponding *gencode* line in the *Makefile*. 48 | 49 | *Note: You can still compile and use the* **_CPU version_**, *even if CUDA is not available.* 50 | 51 | ### OpenCV 52 | 53 | The actual algorithm implementation is *independent* of OpenCV. 54 | 55 | [OpenCV](http://opencv.org/downloads.html) is only used for the example usages of the algorithm (*./main*), to read/write and display the images. So you should have it installed for a quick start, but you can of course use any other library of your choice for image reading/writing/displaying, e.g. [Qt](http://qt-project.org). 56 | 57 | ### MATLAB 58 | 59 | If you want to use the provided **MATLAB wrapper**, MATLAB must be installed, of course. 60 | 61 | 62 | #### Notes: 63 | 64 | The code was tested on two different systems: 65 | 66 | - Ubuntu 12.04 (Precise) with CUDA 5.5 and OpenCV 2.3.1, 67 | - Mac OS X 10.9 (Mavericks) and 10.10 (Yosemite) with CUDA 6.5 and OpenCV 2.4.8. 68 | - the CPU-only version (disable *USE_CUDA* in the *Makefile*) can be compiled with either *clang* or *gcc* of any version. 69 | - the CUDA version compiled only with *gcc* on our test system, namely with *gcc-4.2* (installed through [homebrew](http://brew.sh)). Note that OpenCV needs to be compiled with the same version of *gcc*. 70 | 71 | 72 | 73 | # 2 Usage 74 | 75 | Run the code using 76 | 77 | ./main -i 78 | 79 | See Section 4 for all possible parameters. 80 | 81 | ## 2.1 GUI with live results 82 | 83 | If you specify only one image, e.g. 84 | 85 | ./main -i images/hepburn.png 86 | 87 | you will get a GUI where one can change the main regularization parameters *lambda* and *alpha of the Mumford-Shah model, and see the results immediately. 88 | 89 | ### Hotkeys 90 | - e: Toggle edges highlighting on/off 91 | - v: Toggle info printing on/off 92 | - w: Toggle regularizer weighting on/off 93 | - s: Save current result image 94 | - ESC: Exit 95 | 96 | ## 2.2 Batch processing 97 | 98 | You can provide more than one image if you like, e.g. 99 | 100 | ./main -i images/hepburn.png images/gaudi.png 101 | 102 | ./main -i images/*.png 103 | 104 | In this case, the given parameters will be applied to all images one after another, optionally with temporal regularization (if "-temporal " is specified, see Section 4 below), the resulting images will be saved, and then displayed one after another. 105 | Press any key to switch to the next image. 106 | 107 | ## 2.3 Live camera stream 108 | 109 | Run 110 | 111 | ./main -cam 112 | 113 | (and optionally some other parameters) to process the frames from a plugged-in **USB camera** (or the built-in camera) in real-time. 114 | A GUI will be shown with the same active *hotkeys as in Section 2.1*. 115 | 116 | For example, press **'s'** to save the result for the current frame. 117 | 118 | *Note: This requires that the camera is recognizable using OpenCV. This worked fine on Linux, but didn't work on Mac OS X on our test system.* 119 | 120 | ## 2.4 Running the examples 121 | 122 | ### On images 123 | 124 | For a quick start we provide some sample input images in the "images" directory. 125 | The directory *./examples* contains some example usages of the command line tool. 126 | Run e.g. 127 | 128 | ./examples/example1.sh 129 | 130 | ./examples/example2.sh 131 | 132 | etc. 133 | 134 | ### On video 135 | 136 | There is also the *video* "./images/video.mp4". To run the code on the video: 137 | 138 | - first *extract the video frames*, by running (inside the "images" directory) 139 | 140 | ./video_extract_frames.sh 141 | 142 | - run 143 | 144 | ./examples/example_video.sh 145 | 146 | This will load all video frames, process them one after another (with temporal regularization), save the results to *./images_output/images/video_frames*, and display input and output frames side by side. Press any key to swith to the next displayed frame. 147 | 148 | ## 3 MATLAB interface 149 | 150 | To use the **MATLAB wrapper**, 151 | - make sure MATLAB is installed ;-) 152 | - in the *Makefile*, replace the *MATLAB_DIR* variable with the MATLAB directory on your machine. 153 | - compile the code. This will place the MEX-file into *./examples/matlab* 154 | - run MATLAB and switch to the *examples/matlab* directory. 155 | - run any of the examples to see how the wrapper is used, e.g. type 156 | 157 | example1 158 | 159 | The MATLAB wrapper does not need OpenCV to be installed. 160 | 161 | 162 | ## 4 All parameters 163 | ``` 164 | ./main [-i ] [-cam ] [-row1d ] 165 | [-lambda ] [-alpha ] [-temporal ] 166 | [-weight ] [-adapt_params ] 167 | [-save ] [-show ] [-edges ] 168 | [-engine ] [-use_double ] 169 | [-iterations ] [-stop_eps ] [-stop_k ] 170 | [-verbose ] [-h] 171 | ``` 172 | 173 | ### Parameters: 174 | 175 | ``` 176 | -i 177 | One or more input images to process. 178 | - One input image: a GUI is started where you can alter the parameters 179 | and see its effects on the result. 180 | - More than one input image: All images are first processed with the given 181 | parameters, and then displayed one after another. 182 | - No input image: a default image is chosen (images/hepburn.png). 183 | 184 | -cam 185 | Use live camera stream as input. (The camera must be recognizable with OpenCV, 186 | for instance, this might not work on OS X). 187 | Default: false. 188 | 189 | -row1d 190 | Process only a specific row of the input images, 191 | using the 1D version of the Mumford-Shah functional. 192 | The input and result will be visualized as a graph plot. 193 | Default: -1 (processing as 2d image). 194 | 195 | -lambda 196 | The parameter of the Mumford-Shah functional 197 | giving the weight of the discontinuity penalization. 198 | Default: 0.1. 199 | 200 | -alpha 201 | The parameter of the Mumford-Shah functional giving the 202 | weight of the smoothness penalization. 203 | Large alpha produces a more piecewise constant (cartoon-like) looking result. 204 | Alpha = infinity leads to the segmentation special case, 205 | you can set this value using "-alpha -1". 206 | Default: 20. 207 | 208 | -temporal 209 | Parameter for temporal regularization when processing video or live camera 210 | frames. for higher values the result for each frame will be more and more 211 | similar to the result of the previous frame. 212 | Default: 0 (no temporal regularization). 213 | 214 | -weight 215 | Whether to use image edge adaptive Mumford-Shah penalization. 216 | Less smoothing will be applied in pixels where the absolute value of the input 217 | image gradient is large. 218 | Default: false. 219 | 220 | -adapt_params 221 | Whether to adapt the parameters 'lambda' and 'alpha' to image size. 222 | For one and the same input image, the solution look more or less the same 223 | independent of its size. The specified 'lambda' and 'alpha' are regarded 224 | as being the actual parameters for image size 640 x 480, 225 | and are suitably scaled for all other sizes. 226 | Default: false. 227 | 228 | -save 229 | Directory to store the result images. 230 | Default: "./images_output". 231 | 232 | -show 233 | Whether to display the input and result images (in addition to saving them). 234 | Default: true. 235 | 236 | -edges 237 | Visualize the edges (discontinuities) of the result image 238 | (as overlaid black lines). 239 | Default: false. 240 | 241 | -engine 242 | Whether to use the CPU or the CUDA implementation. 243 | Use "-engine cpu" or "-engine 0" for the CPU version, 244 | and "-engine cuda" or "-engine 1" for the CUDA version. 245 | Default: CUDA. 246 | 247 | -use_double 248 | Whether to use to double precision for all computations 249 | ('double' instead of 'float'). 250 | Double precision is slower (especially on the GPU), but should be turned on for 251 | - very small '-stop_eps' values (< 10^-6), 252 | - a huge number of iterations (> 100000), 253 | - or when computing an accurate energy value. 254 | Default: false. 255 | 256 | -iterations 257 | The maximal number of primal-dual iterations. 258 | This is only an upper bound on the actual number of performed iterations, 259 | since the iterations are stopped when the solutions do not 260 | change significantly anymore (see "-stop_eps" and "-stop_k") 261 | Default: 10000. 262 | 263 | -stop_eps 264 | Determines the stopping criterion: 265 | The iterations will be stopped once the average per-pixel value change 266 | of the solution w.r.t. the previous iterations is smaller than this parameter. 267 | Default: 5.5e-5. 268 | 269 | -stop_k 270 | For efficiency, the stopping criterion is checked only every k-th iterations. 271 | Default: 10. 272 | 273 | -verbose 274 | Print various information such as parameters, run time, and energy. 275 | Default: true. 276 | 277 | -h, -help, 278 | Display usage information and exit. 279 | ``` 280 | 281 | > ##### "bool" parameters are set to: 282 | - *true* for values "1", "true", or "yes", or if the parameter is specified without a value (e.g. only "-weight") 283 | - *false* for values "0", "false", or "no". 284 | 285 | 286 | 287 | 5 License 288 | =========== 289 | 290 | fastms is licensed under the GNU General Public License Version 3 (GPLv3), see http://www.gnu.org/licenses/gpl.html, with an additional request: 291 | 292 | If you make use of the library in any form in a scientific publication, please refer to https://github.com/tum-vision/fastms.git and cite the paper 293 | 294 | ``` 295 | @inproceedings{Strekalovskiy-Cremers-eccv14, 296 | author = {E. Strekalovskiy and D. Cremers}, 297 | title = {Real-Time Minimization of the Piecewise Smooth Mumford-Shah Functional}, 298 | booktitle = {European Conference on Computer Vision (ECCV)}, 299 | year = {2014}, 300 | pages = {127-141}, 301 | } 302 | ``` 303 | 304 | 305 | -------------------------------------------------------------------------------- /examples/example1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -i images/hepburn.png 21 | -------------------------------------------------------------------------------- /examples/example2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -i images/hepburn.png -engine cpu 21 | -------------------------------------------------------------------------------- /examples/example3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -i images/*.png 21 | -------------------------------------------------------------------------------- /examples/example4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -adapt_params -edges -i images/dog*_* 21 | -------------------------------------------------------------------------------- /examples/example5.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -i images/lake-powell.png -edges -lambda 0.15 -alpha 10000 21 | -------------------------------------------------------------------------------- /examples/example6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -i images/squirrel.png -lambda 0.5 -alpha -1 21 | -------------------------------------------------------------------------------- /examples/example7.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -i images/dog.png -row1d 479 -stop_eps 1e-7 -lambda 0.5 -alpha 100 21 | -------------------------------------------------------------------------------- /examples/example8.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -i images/dog.png -row1d 479 -stop_eps 1e-7 -alpha 10000 -lambda 1 21 | -------------------------------------------------------------------------------- /examples/example9.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -row1d 0 -i images/marble.png -stop_eps 1e-7 -alpha -1 -lambda 0.3 21 | -------------------------------------------------------------------------------- /examples/example_video.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -lambda 1.5 -alpha 500 -weight 1 -temporal 0.4 -edges 1 -i images/video_frames/frame*.png 21 | -------------------------------------------------------------------------------- /examples/example_video_first10frames.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of fastms. 4 | # 5 | # Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # fastms is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # fastms is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with fastms. If not, see . 19 | # 20 | ./main -lambda 1.5 -alpha 500 -weight 1 -temporal 0.4 -edges 1 -i images/video_frames/frame00*.png 21 | -------------------------------------------------------------------------------- /examples/matlab/example1.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function example1() 21 | in_image = imread('../../images/hepburn.png'); 22 | 23 | out_image = fastms(in_image); 24 | 25 | show_images(in_image, out_image); 26 | end 27 | -------------------------------------------------------------------------------- /examples/matlab/example2.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function example1() 21 | in_image = imread('../../images/hepburn.png'); 22 | 23 | out_image = fastms(in_image, 'engine', 0); 24 | 25 | show_images(in_image, out_image); 26 | end 27 | -------------------------------------------------------------------------------- /examples/matlab/example3.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function example2() 21 | in_image = imread('../../images/hepburn.png'); 22 | 23 | out_image = (in_image, 'weight', true, 'lambda', 3, 'alpha', 100); 24 | 25 | show_images(in_image, out_image); 26 | end 27 | -------------------------------------------------------------------------------- /examples/matlab/example4.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function example3() 21 | in_image = imread('../../images/hepburn.png'); 22 | 23 | out_image = fastms(in_image, 'engine', 1, 'alpha', 100000, 'stop_eps', 1e-8, 'use_double', true, 'iterations', 100000); 24 | 25 | show_images(in_image, out_image); 26 | end 27 | -------------------------------------------------------------------------------- /examples/matlab/example5.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function example3() 21 | in_image = imread('../../images/lake-powell.png'); 22 | 23 | out_image = fastms(in_image, 'engine', 1, 'lambda', 0.15, 'alpha', 10000, 'edges', true); 24 | 25 | show_images(in_image, out_image); 26 | end 27 | -------------------------------------------------------------------------------- /examples/matlab/example6.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function example3() 21 | in_image = imread('../../images/squirrel.png'); 22 | 23 | out_image = fastms(in_image, 'engine', 1, 'lambda', 0.5, 'alpha', -1); 24 | 25 | show_images(in_image, out_image); 26 | end 27 | -------------------------------------------------------------------------------- /examples/matlab/fastms.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function [out_image] = fastms(in_image, varargin) 21 | 22 | % TODO: maybe use inputParser of matlab 23 | options = struct(... 24 | 'lambda', [], ... 25 | 'alpha', [], ... 26 | 'temporal', [], ... 27 | 'iterations', [], ... 28 | 'stop_eps', [], ... 29 | 'stop_k', [], ... 30 | 'adapt_params', [], ... 31 | 'weight', [], ... 32 | 'use_double', [], ... 33 | 'engine', [], ... 34 | 'edges', [], ... 35 | 'verbose', []); 36 | 37 | option_names = fieldnames(options); 38 | num_args = length(varargin); 39 | if rem(num_args,2) ~= 0 40 | error('Options must be name/value pairs'); 41 | end 42 | for pair = reshape(varargin,2,[]) % pair = {name;value} 43 | in_name = lower(pair{1}); 44 | if any(strmatch(in_name, option_names)) 45 | options.(in_name) = pair{2}; 46 | else 47 | error('Unexpected parameter name %s', in_name); 48 | end 49 | end 50 | 51 | out_image = fastms_mex(in_image, options); 52 | end 53 | -------------------------------------------------------------------------------- /examples/matlab/show_images.m: -------------------------------------------------------------------------------- 1 | % 2 | % This file is part of fastms. 3 | % 4 | % Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | % 6 | % fastms is free software: you can redistribute it and/or modify 7 | % it under the terms of the GNU General Public License as published by 8 | % the Free Software Foundation, either version 3 of the License, or 9 | % (at your option) any later version. 10 | % 11 | % fastms is distributed in the hope that it will be useful, 12 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | % GNU General Public License for more details. 15 | % 16 | % You should have received a copy of the GNU General Public License 17 | % along with fastms. If not, see . 18 | % 19 | 20 | function show_images(in_image, out_image) 21 | screen_size = get(0, 'ScreenSize'); 22 | image_size = size(in_image); 23 | w_scr = screen_size(3); 24 | h_scr = screen_size(4); 25 | w_fig = w_scr * 0.4; 26 | h_fig = w_fig * image_size(1) / image_size(2); 27 | w_dist = w_scr * 0.02; 28 | in_pos = [w_scr / 2 - w_fig - w_dist / 2, h_scr - h_fig, w_fig, h_fig]; 29 | out_pos = in_pos; 30 | out_pos(1) = w_scr / 2 + w_dist / 2; 31 | 32 | in_fig = figure('Name','Input','Visible','Off'); 33 | imshow(in_image); 34 | set(in_fig, 'Position', in_pos, 'Visible', 'On'); 35 | 36 | out_fig = figure('Name','Result','Visible','Off'); 37 | imshow(out_image); 38 | set(out_fig, 'Position', out_pos, 'Visible', 'On'); 39 | end 40 | -------------------------------------------------------------------------------- /images/dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/dog.png -------------------------------------------------------------------------------- /images/dog1_original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/dog1_original.png -------------------------------------------------------------------------------- /images/dog2_downscaled50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/dog2_downscaled50.png -------------------------------------------------------------------------------- /images/dog3_downscaled25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/dog3_downscaled25.png -------------------------------------------------------------------------------- /images/dog4_downscaled10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/dog4_downscaled10.png -------------------------------------------------------------------------------- /images/florida-state-university.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/florida-state-university.png -------------------------------------------------------------------------------- /images/gaudi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/gaudi.png -------------------------------------------------------------------------------- /images/hepburn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/hepburn.png -------------------------------------------------------------------------------- /images/lake-powell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/lake-powell.png -------------------------------------------------------------------------------- /images/landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/landscape.png -------------------------------------------------------------------------------- /images/lighthouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/lighthouse.png -------------------------------------------------------------------------------- /images/marble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/marble.png -------------------------------------------------------------------------------- /images/mountain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/mountain.png -------------------------------------------------------------------------------- /images/peacock-feather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/peacock-feather.png -------------------------------------------------------------------------------- /images/peacock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/peacock.png -------------------------------------------------------------------------------- /images/squirrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/squirrel.png -------------------------------------------------------------------------------- /images/the-tigers-nest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/the-tigers-nest.png -------------------------------------------------------------------------------- /images/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tum-vision/fastms/554c37b54403b6121b9c9a6fd47f7b94fb2435b9/images/video.mp4 -------------------------------------------------------------------------------- /images/video_extract_frames.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of msfast. 4 | # 5 | # 2014 Evgeny Strekalovskiy (Technical University of Munich) 6 | # 7 | # msfast is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # msfast is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with msfast. If not, see . 19 | # 20 | mkdir -p video_frames 21 | ffmpeg -i video.mp4 -f image2 video_frames/frame%3d.png 22 | -------------------------------------------------------------------------------- /src/examples/example_batchprocessing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "example_batchprocessing.h" 21 | 22 | #include "solver/solver.h" 23 | #include "param.h" 24 | #ifndef DISABLE_OPENCV 25 | #include "util/image_mat.h" 26 | #endif // DISABLE_OPENCV 27 | #include 28 | #include 29 | #include "util.h" 30 | 31 | 32 | 33 | int example_batchprocessing(int argc, char **argv) 34 | { 35 | bool show_help = false; 36 | get_param("help", show_help, argc, argv); 37 | get_param("-help", show_help, argc, argv); 38 | get_param("h", show_help, argc, argv); 39 | get_param("-h", show_help, argc, argv); 40 | if (show_help) { std::cout << "Usage: " << argv[0] << " -i " << std::endl; return 0; } 41 | 42 | // get params 43 | Par par; 44 | get_param("verbose", par.verbose, argc, argv); 45 | if (par.verbose) std::cout << std::boolalpha; 46 | get_param("lambda", par.lambda, argc, argv); 47 | get_param("alpha", par.alpha, argc, argv); 48 | get_param("temporal", par.temporal, argc, argv); 49 | get_param("iterations", par.iterations, argc, argv); 50 | get_param("stop_eps", par.stop_eps, argc, argv); 51 | get_param("stop_k", par.stop_k, argc, argv); 52 | get_param("adapt_params", par.adapt_params, argc, argv); 53 | get_param("weight", par.weight, argc, argv); 54 | get_param("use_double", par.use_double, argc, argv); 55 | { 56 | std::string s_engine = ""; 57 | if (get_param("engine", s_engine, argc, argv)) 58 | { 59 | std::transform(s_engine.begin(), s_engine.end(), s_engine.begin(), ::tolower); 60 | if (s_engine.find("cpu") == 0 || s_engine.find("host") == 0) 61 | { 62 | par.engine = Par::engine_cpu; 63 | } 64 | else if (s_engine.find("cuda") == 0 || s_engine.find("device") == 0) 65 | { 66 | par.engine = Par::engine_cuda; 67 | } 68 | else 69 | { 70 | get_param("engine", par.engine, argc, argv); 71 | } 72 | } 73 | } 74 | get_param("edges", par.edges, argc, argv); 75 | if (par.verbose) { par.print(); } 76 | std::cout << std::endl; 77 | 78 | int row1d = -1; 79 | get_param("row1d", row1d, argc, argv); 80 | if (par.verbose) std::cout << " row1d: "; if (row1d == -1) std::cout << "-1 (processing as 2d image)" << std::endl; else std::cout << "processing only row " << row1d << " as 1d image" << std::endl; 81 | 82 | bool show_result = true; 83 | get_param("show", show_result, argc, argv); 84 | if (par.verbose) std::cout << " show: " << show_result << std::endl; 85 | 86 | std::string save_dir = "images_output"; 87 | get_param("save", save_dir, argc, argv); 88 | bool save_result = (save_dir != ""); 89 | if (par.verbose && save_result) { std::cout << " save (RESULTS DIRECTORY): " << save_dir.c_str() << std::endl; } 90 | else { std::cout << " save (results directory): empty (result saving disabled))" << std::endl; } 91 | 92 | std::cout << std::endl; 93 | 94 | #ifndef DISABLE_OPENCV 95 | // get input files 96 | std::vector input_names; 97 | std::vector input_images; 98 | std::vector inputfiles; 99 | bool has_i_param = get_param("i", inputfiles, argc, argv); 100 | if (!has_i_param) 101 | { 102 | std::string default_file = "images/hepburn.png"; 103 | //std::cerr << "Using " << default_file << " (no option \"-i \" given)" << std::endl; 104 | inputfiles.push_back(default_file); 105 | } 106 | //if (par.verbose) std::cout << "loading input files" << std::endl; 107 | for (int i = 0; i < (int)inputfiles.size(); i++) 108 | { 109 | cv::Mat input_image = cv::imread(inputfiles[i].c_str()); 110 | if (input_image.data == NULL) { std::cerr << "ERROR: Could not load image " << inputfiles[i].c_str() << std::endl; continue; } 111 | input_images.push_back(input_image); 112 | input_names.push_back(inputfiles[i]); 113 | } 114 | if (input_images.size() == 0) 115 | { 116 | std::cerr << "No input files" << std::endl; 117 | return -1; 118 | } 119 | 120 | // for 1d processing: extract rows 121 | if (row1d >= 0) 122 | { 123 | for (int i = 0; i < (int)input_images.size(); i++) 124 | { 125 | input_images[i] = extract_row(input_images[i], row1d); 126 | } 127 | } 128 | 129 | // process 130 | std::vector result_images(input_images.size()); 131 | Solver solver; 132 | for (int i = 0; i < (int)input_images.size(); i++) 133 | { 134 | if (par.verbose) std::cout << input_names[i].c_str() << ": "; 135 | result_images[i] = solver.run(input_images[i], par); 136 | } 137 | 138 | // for 1d processing: replace 1d input and result with its graph visualization 139 | if (row1d >= 0) 140 | { 141 | int graph_height = 200; 142 | double thresh_jump = (par.alpha > 0.0? std::sqrt(par.lambda / par.alpha) : -1.0); 143 | for (int i = 0; i < (int)result_images.size(); i++) 144 | { 145 | input_images[i] = image1d_to_graph(input_images[i], graph_height, -1.0); 146 | result_images[i] = image1d_to_graph(result_images[i], graph_height, thresh_jump); 147 | } 148 | } 149 | 150 | 151 | // show results 152 | if (save_result) 153 | { 154 | for (int i = 0; i < (int)input_images.size(); i++) 155 | { 156 | std::string dir; 157 | std::string basename; 158 | FilesUtil::to_dir_basename(input_names[i], dir, basename); 159 | if (row1d >= 0) { std::stringstream s; s << "_row" << row1d; basename += s.str(); } 160 | 161 | std::string out_dir = save_dir + '/' + dir; 162 | if (!FilesUtil::mkdir(out_dir)) { std::cerr << "ERROR: Could not create output directory " << out_dir.c_str() << std::endl; continue; } 163 | std::string out_file_input = out_dir + '/' + basename + "__input.png"; 164 | std::string out_file_result = out_dir + '/' + basename + "__result" + par_to_string(par) + ".png"; 165 | if (!cv::imwrite(out_file_input, input_images[i])) { std::cerr << "ERROR: Could not save input image " << out_file_input.c_str() << std::endl; continue; } 166 | if (!cv::imwrite(out_file_result, result_images[i])) { std::cerr << "ERROR: Could not save result image " << out_file_result.c_str() << std::endl; continue; } 167 | std::cout << "SAVED RESULT: " << out_file_result.c_str() << " (SAVED INPUT: " << out_file_input.c_str() << ")" << std::endl; 168 | } 169 | } 170 | if (show_result) 171 | { 172 | for (int i = 0; i < (int)input_images.size(); i++) 173 | { 174 | show_image("Input", input_images[i], 100, 100); 175 | show_image("Output", result_images[i], 100 + input_images[i].cols + 40, 100); 176 | cv::waitKey(0); 177 | } 178 | } 179 | cvDestroyAllWindows(); 180 | #else 181 | std::cerr << "ERROR: " << __FILE__ << ": OpenCV disabled in compilation, but this example requires OpenCV." << std::endl; 182 | #endif // DISABLE_OPENCV 183 | 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /src/examples/example_batchprocessing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef EXAMPLES_EXAMPLE_BATCHPROCESSING_H 21 | 22 | 23 | 24 | int example_batchprocessing(int argc, char **argv); 25 | 26 | 27 | 28 | #endif // EXAMPLES_EXAMPLE_BATCHPROCESSING_H 29 | -------------------------------------------------------------------------------- /src/examples/example_gui.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "example_gui.h" 21 | 22 | #include "solver/solver.h" 23 | #include "param.h" 24 | #ifndef DISABLE_OPENCV 25 | #include "util/image_mat.h" 26 | #endif // not DISABLE_OPENCV 27 | #include "util.h" 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | 35 | 36 | #ifndef DISABLE_OPENCV 37 | class SliderExpTransform 38 | { 39 | public: 40 | SliderExpTransform() : min_val_exp(0.001), max_val_exp(100.0), min_val(0.0), max_val(100.0), pos_max(100), pos(0) {} 41 | void set_val_range(double min_val_exp, double max_val_exp, double min_val, double max_val, int pos_max) 42 | { 43 | this->min_val_exp = min_val_exp; 44 | this->max_val_exp = max_val_exp; 45 | this->min_val = min_val; 46 | this->max_val = max_val; 47 | this->pos_max = pos_max; 48 | } 49 | double pos2val(int pos) 50 | { 51 | if (pos == 0) { return min_val; } 52 | else if (pos == pos_max) { return max_val; } 53 | else 54 | { 55 | double val = min_val_exp * pow(max_val_exp / min_val_exp, (double)pos / (double)pos_max); 56 | double pwr10 = pow(10.0, floor(log(val) / log(10.0))); 57 | val = floor(val / pwr10 * 100.0 + 0.5) / 100.0 * pwr10; 58 | return val; 59 | } 60 | } 61 | int val2pos(double val) 62 | { 63 | if (val == min_val) { return 0; } 64 | else if (val == max_val) { return pos_max; } 65 | else 66 | { 67 | val = std::max(min_val_exp, std::min(max_val_exp, val)); 68 | double pos_double = log(val / min_val_exp) / log(max_val_exp / min_val_exp) * (double)pos_max; 69 | int pos = (int)floor(pos_double + 0.5); 70 | pos = std::max(0, std::min(pos_max, pos)); 71 | return pos; 72 | } 73 | } 74 | double min_val_exp; 75 | double max_val_exp; 76 | double min_val; 77 | double max_val; 78 | int pos_max; 79 | int pos; 80 | }; 81 | 82 | 83 | void slider_callback_lambda(int pos, void *data_void); 84 | void slider_callback_alpha(int pos, void *data_void); 85 | void slider_callback_temporal(int pos, void *data_void); 86 | 87 | 88 | class Data 89 | { 90 | public: 91 | Data() : windows_created(false), windows_positioned(false), recompute_on_param_change(true), show_temporal(false), channel_id(-1) {} 92 | 93 | void compute() 94 | { 95 | result_image = solver.run(input_image, par); 96 | if (input_image.rows == 1) 97 | { 98 | int graph_height = 200; 99 | double thresh_jump = (par.alpha > 0.0? std::sqrt(par.lambda / par.alpha) : -1.0); 100 | shown_input_image = image1d_to_graph(input_image, graph_height, channel_id, -1.0); 101 | shown_result_image = image1d_to_graph(result_image, graph_height, channel_id, thresh_jump); 102 | } 103 | else 104 | { 105 | shown_input_image = input_image; 106 | shown_result_image = result_image; 107 | } 108 | } 109 | void compute_and_show_results() 110 | { 111 | compute(); 112 | 113 | std::string title_input = "Input"; 114 | std::string title_result = "Result"; 115 | if (input_image.rows == 1) 116 | { 117 | std::string to_add = ""; 118 | if (channel_id == 0) { to_add = " (R of RGB)"; } 119 | else if (channel_id == 1) { to_add = " (G of RGB)"; } 120 | else if (channel_id == 2) { to_add = " (B of RGB)"; } 121 | else { to_add = " (RGB)"; } 122 | title_input += to_add; 123 | title_result += to_add; 124 | } 125 | std::string title_params = "Parameters"; 126 | if (!windows_created) 127 | { 128 | cv::namedWindow(title_params.c_str(), CV_WINDOW_NORMAL); 129 | slider_lambda.set_val_range(0.001, 1000, 0.0, -1.0, 500); 130 | slider_lambda.pos = slider_lambda.val2pos(par.lambda); 131 | cv::createTrackbar("Lambda", title_params.c_str(), &slider_lambda.pos, slider_lambda.pos_max, slider_callback_lambda, (void*)this); 132 | slider_alpha.set_val_range(0.1, 10000, 0.0, -1.0, 500); 133 | slider_alpha.pos = slider_alpha.val2pos(par.alpha); 134 | cv::createTrackbar("Alpha", title_params.c_str(), &slider_alpha.pos, slider_alpha.pos_max, slider_callback_alpha, (void*)this); 135 | if (show_temporal) 136 | { 137 | slider_temporal.set_val_range(0.01, 2, 0.0, 2.0, 500); 138 | slider_temporal.pos = slider_temporal.val2pos(par.temporal); 139 | cv::createTrackbar("Temporal", title_params.c_str(), &slider_temporal.pos, slider_temporal.pos_max, slider_callback_temporal, (void*)this); 140 | } 141 | 142 | cv::namedWindow(title_input.c_str(), CV_WINDOW_NORMAL); 143 | 144 | cv::namedWindow(title_result.c_str(), CV_WINDOW_NORMAL); 145 | 146 | windows_created = true; 147 | } 148 | if (!windows_positioned) 149 | { 150 | cvMoveWindow(title_input.c_str(), 100, 300); 151 | cvMoveWindow(title_result.c_str(), 100 + shown_input_image.cols + 40, 300); 152 | cvMoveWindow(title_params.c_str(), 100 + shown_input_image.cols + 40, 100); 153 | windows_positioned = true; 154 | } 155 | cv::imshow(title_input.c_str(), shown_input_image); 156 | cv::imshow(title_result.c_str(), shown_result_image); 157 | } 158 | 159 | Par par; 160 | Solver solver; 161 | cv::Mat input_image; 162 | cv::Mat result_image; 163 | cv::Mat shown_input_image; 164 | cv::Mat shown_result_image; 165 | 166 | SliderExpTransform slider_lambda; 167 | SliderExpTransform slider_alpha; 168 | SliderExpTransform slider_temporal; 169 | bool windows_created; 170 | bool windows_positioned; 171 | bool recompute_on_param_change; 172 | bool show_temporal; 173 | int channel_id; 174 | }; 175 | 176 | 177 | void slider_callback_lambda(int pos, void *data_void) 178 | { 179 | Data *data = (Data*)data_void; 180 | data->par.lambda = data->slider_lambda.pos2val(pos); 181 | if (data->recompute_on_param_change) { data->compute_and_show_results(); } 182 | } 183 | void slider_callback_alpha(int pos, void *data_void) 184 | { 185 | Data *data = (Data*)data_void; 186 | data->par.alpha = data->slider_alpha.pos2val(pos); 187 | if (data->recompute_on_param_change) { data->compute_and_show_results(); } 188 | } 189 | void slider_callback_temporal(int pos, void *data_void) 190 | { 191 | Data *data = (Data*)data_void; 192 | data->par.temporal = data->slider_temporal.pos2val(pos); 193 | if (data->recompute_on_param_change) { data->compute_and_show_results(); } 194 | } 195 | 196 | 197 | void print_keys() 198 | { 199 | std::cout << " e: edges highlighting (on/off)\n"; 200 | std::cout << " v: info printing (on/off)\n"; 201 | std::cout << " w: regularizer weighting (on/off)\n"; 202 | std::cout << " s: save result image\n"; 203 | std::cout << " escape: exit\n"; 204 | std::cout << std::endl; 205 | } 206 | 207 | 208 | // returns: whether the result should be recomputed due to changed parameters 209 | bool process_key(int key, Data &data, bool &running, bool &save) 210 | { 211 | bool params_changed = false; 212 | save = false; 213 | if (key == 27) 214 | { 215 | running = false; 216 | } 217 | else if (key == 'e') 218 | { 219 | data.par.edges = !data.par.edges; 220 | params_changed = true; 221 | } 222 | else if (key == 'v') 223 | { 224 | data.par.verbose = !data.par.verbose; 225 | params_changed = true; 226 | } 227 | else if (key == 'w') 228 | { 229 | data.par.weight = !data.par.weight; 230 | params_changed = true; 231 | } 232 | else if (key == 's') 233 | { 234 | save = true; 235 | } 236 | else if (((int)('a') <= key && key <= (int)('z')) || ((int)('A') <= key && key <= (int)('Z')) || ((int)('0') <= key && key <= (int)('9'))) 237 | { 238 | std::cout << "\nNo action set for key '" << (char)key << "'. You can use one of the following:" << std::endl; 239 | print_keys(); 240 | } 241 | return params_changed; 242 | } 243 | #endif // not DISABLE_OPENCV 244 | 245 | 246 | int example_gui(int argc, char **argv) 247 | { 248 | #ifndef DISABLE_OPENCV 249 | Data data; 250 | 251 | bool show_help = false; 252 | get_param("help", show_help, argc, argv); 253 | get_param("-help", show_help, argc, argv); 254 | get_param("h", show_help, argc, argv); 255 | get_param("-h", show_help, argc, argv); 256 | if (show_help) { std::cout << "Usage: " << argv[0] << " -i " << std::endl; return 0; } 257 | 258 | // get params 259 | Par &par = data.par; 260 | get_param("verbose", par.verbose, argc, argv); 261 | if (par.verbose) std::cout << std::boolalpha; 262 | get_param("lambda", par.lambda, argc, argv); 263 | get_param("alpha", par.alpha, argc, argv); 264 | get_param("temporal", par.temporal, argc, argv); 265 | get_param("iterations", par.iterations, argc, argv); 266 | get_param("stop_eps", par.stop_eps, argc, argv); 267 | get_param("stop_k", par.stop_k, argc, argv); 268 | get_param("adapt_params", par.adapt_params, argc, argv); 269 | get_param("weight", par.weight, argc, argv); 270 | get_param("edges", par.edges, argc, argv); 271 | get_param("use_double", par.use_double, argc, argv); 272 | { 273 | std::string s_engine = ""; 274 | if (get_param("engine", s_engine, argc, argv)) 275 | { 276 | std::transform(s_engine.begin(), s_engine.end(), s_engine.begin(), ::tolower); 277 | if (s_engine.find("cpu") == 0 || s_engine.find("host") == 0) 278 | { 279 | par.engine = Par::engine_cpu; 280 | } 281 | else if (s_engine.find("cuda") == 0 || s_engine.find("device") == 0) 282 | { 283 | par.engine = Par::engine_cuda; 284 | } 285 | else 286 | { 287 | get_param("engine", par.engine, argc, argv); 288 | } 289 | } 290 | } 291 | if (par.verbose) { par.print(); } 292 | std::cout << std::endl; 293 | 294 | int row1d = -1; 295 | get_param("row1d", row1d, argc, argv); 296 | if (par.verbose) std::cout << " row1d: "; if (row1d == -1) std::cout << "-1 (processing as 2d image)" << std::endl; else std::cout << "processing only row " << row1d << " as 1d image" << std::endl; 297 | 298 | bool show_result = true; 299 | get_param("show", show_result, argc, argv); 300 | if (par.verbose) std::cout << " show: " << show_result << std::endl; 301 | 302 | std::string save_dir = "images_output"; 303 | get_param("save", save_dir, argc, argv); 304 | if (par.verbose && save_dir != "") { std::cout << " save (RESULTS DIRECTORY): " << save_dir.c_str() << std::endl; } 305 | else { std::cout << " save (results directory): empty (result saving disabled))" << std::endl; } 306 | 307 | bool use_cam = false; 308 | get_param("cam", use_cam, argc, argv); 309 | std::cout << " cam: " << use_cam << std::endl; 310 | 311 | std::cout << "\nKeys:\n"; 312 | print_keys(); 313 | 314 | cv::VideoCapture *camera = NULL; 315 | std::string in_dir; 316 | std::string in_basename; 317 | if (use_cam) 318 | { 319 | camera = new cv::VideoCapture(0); 320 | if(!camera->isOpened()) { delete camera; std::cerr << "ERROR: Could not open camera" << std::endl; return -1; } 321 | int w_cam = 640; 322 | int h_cam = 480; 323 | camera->set(CV_CAP_PROP_FRAME_WIDTH, w_cam); 324 | camera->set(CV_CAP_PROP_FRAME_HEIGHT, h_cam); 325 | data.recompute_on_param_change = false; 326 | data.show_temporal = true; 327 | in_dir = "camera"; 328 | in_basename = "frame"; 329 | } 330 | else 331 | { 332 | std::string inputfile; 333 | bool has_i_param = get_param("i", inputfile, argc, argv); 334 | if (!has_i_param) 335 | { 336 | std::string default_file = "images/hepburn.png"; 337 | inputfile = default_file; 338 | } 339 | data.input_image = cv::imread(inputfile.c_str()); 340 | if (data.input_image.data == NULL) { std::cerr << "ERROR: Could not load image " << inputfile.c_str() << std::endl; return -1; } 341 | data.recompute_on_param_change = true; 342 | data.show_temporal = false; 343 | FilesUtil::to_dir_basename(inputfile, in_dir, in_basename); 344 | } 345 | std::string out_dir = save_dir + '/' + in_dir; 346 | 347 | 348 | bool running = true; 349 | bool input_changed = true; 350 | bool params_changed = false; 351 | bool already_saved = false; 352 | while(running) 353 | { 354 | if (use_cam) { *camera >> data.input_image; input_changed = true; } 355 | if (input_changed) 356 | { 357 | if (row1d >= 0) { data.input_image = extract_row(data.input_image, row1d); } 358 | } 359 | 360 | if (input_changed || params_changed) 361 | { 362 | if (show_result) { data.compute_and_show_results(); } else { data.compute(); } 363 | input_changed = false; 364 | params_changed = false; 365 | } 366 | 367 | bool save_result = false; 368 | if (show_result) 369 | { 370 | int key = cv::waitKey( (use_cam? 15 : 0) ); 371 | params_changed = process_key(key, data, running, save_result); 372 | } 373 | else 374 | { 375 | save_result = true; 376 | } 377 | if (!running && !already_saved) { save_result = true; } 378 | if (save_result && save_dir != "") 379 | { 380 | std::string basename = (use_cam? "frame_at_time_" + str_curtime() : in_basename); 381 | if (row1d >= 0) { std::stringstream s; s << "_row" << row1d; basename += s.str(); } 382 | std::string out_file_input = out_dir + '/' + basename + "__input.png"; 383 | std::string out_file_result = out_dir + '/' + basename + "__result" + par_to_string(data.par) + ".png"; 384 | if (!FilesUtil::mkdir(out_dir)) { std::cerr << "ERROR: Could not create output directory " << out_dir.c_str() << std::endl; continue; } 385 | if (!cv::imwrite(out_file_input, data.shown_input_image)) { std::cerr << "ERROR: Could not save input image " << out_file_input.c_str() << std::endl; continue; } 386 | if (!cv::imwrite(out_file_result, data.shown_result_image)) { std::cerr << "ERROR: Could not save result image " << out_file_result.c_str() << std::endl; continue; } 387 | std::cout << "SAVED RESULT: " << out_file_result.c_str() << " (SAVED INPUT: " << out_file_input.c_str() << ")" << std::endl; 388 | already_saved = true; 389 | } 390 | if (!show_result) { running = false; } 391 | } 392 | 393 | if (use_cam) { delete camera; } 394 | 395 | cvDestroyAllWindows(); 396 | #else 397 | std::cerr << "ERROR: " << __FILE__ << ": OpenCV disabled in compilation, but this example requires OpenCV." << std::endl; 398 | #endif // DISABLE_OPENCV 399 | return 0; 400 | } 401 | 402 | -------------------------------------------------------------------------------- /src/examples/example_gui.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef EXAMPLES_EXAMPLE_GUI_H 21 | 22 | 23 | 24 | int example_gui(int argc, char **argv); 25 | 26 | 27 | 28 | #endif // EXAMPLES_EXAMPLE_GUI_H 29 | -------------------------------------------------------------------------------- /src/examples/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "example_batchprocessing.h" 21 | #include "example_gui.h" 22 | #include "param.h" 23 | #include 24 | 25 | 26 | 27 | int main(int argc, char **argv) 28 | { 29 | // example_gui: ability to change the parameters and see the result immediately 30 | // --> if camera or only one input image (or no input image): example_gui 31 | // example_batchprocessing: set parameters once and apply them to all input images ("-i image1 image2 image3 ...") 32 | // --> if multiple input images given 33 | 34 | bool use_cam = false; 35 | get_param("cam", use_cam, argc, argv); 36 | 37 | std::vector inputfiles; 38 | get_param("i", inputfiles, argc, argv); 39 | 40 | if (use_cam || inputfiles.size() <= 1) 41 | { 42 | return example_gui(argc, argv); 43 | } 44 | else 45 | { 46 | return example_batchprocessing(argc, argv); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/examples/param.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_PARAM_H 21 | #define UTIL_PARAM_H 22 | 23 | #include // for strcmp 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | 30 | namespace 31 | { 32 | 33 | template inline bool get_param__string_to_var(const std::string &s, T &var) 34 | { 35 | std::stringstream ss; 36 | ss << s.c_str(); 37 | ss >> var; 38 | return (bool)ss; 39 | } 40 | template<> inline bool get_param__string_to_var(const std::string &s, std::string &var) 41 | { 42 | if (s.length() > 0 && s[0] == '-') 43 | { 44 | return false; 45 | } 46 | else 47 | { 48 | var = s; 49 | return true; 50 | } 51 | } 52 | template<> inline bool get_param__string_to_var(const std::string &s, bool &var) 53 | { 54 | if (s.length() == 0 || s[0] == 't' || s[0] == 'T' || s[0] == 'y' || s[0] == 'Y') 55 | { 56 | var = true; 57 | return true; 58 | } 59 | else if (s[0] == 'f' || s[0] == 'F' || s[0] == 'n' || s[0] == 'N') 60 | { 61 | var = false; 62 | return true; 63 | } 64 | else 65 | { 66 | std::stringstream ss; 67 | ss << s.c_str(); 68 | ss >> var; 69 | return (bool)ss; 70 | } 71 | } 72 | 73 | 74 | template inline void get_param__empty_to_var(T &var) 75 | { 76 | } 77 | template<> inline void get_param__empty_to_var(bool &var) 78 | { 79 | var = true; 80 | } 81 | template<> inline void get_param__empty_to_var(std::string &var) 82 | { 83 | var = ""; 84 | } 85 | 86 | } // namespace 87 | 88 | 89 | // get arguments for parameter 90 | template bool get_param(std::string param, std::vector &vars, int argc, char **argv) 91 | { 92 | bool param_found = false; 93 | vars.clear(); 94 | for(int i = argc - 1; i >= 1; i--) 95 | { 96 | if (argv[i][0] != '-') continue; 97 | if (strcmp(argv[i] + 1, param.c_str()) == 0) 98 | { 99 | param_found = true; 100 | // read arguments 101 | for (int k = i + 1; k < argc; k++) 102 | { 103 | T var; 104 | if (!get_param__string_to_var(argv[k], var)) { break; } 105 | vars.push_back(var); 106 | } 107 | break; 108 | } 109 | } 110 | return param_found; 111 | } 112 | 113 | 114 | // get last argument for parameter 115 | template bool get_param(std::string param, T &var, int argc, char **argv) 116 | { 117 | std::vector vars; 118 | bool param_found = get_param(param, vars, argc, argv); 119 | if (param_found) 120 | { 121 | if (vars.size() > 0) 122 | { 123 | var = vars[vars.size() - 1]; 124 | } 125 | else 126 | { 127 | get_param__empty_to_var(var); 128 | } 129 | } 130 | return param_found; 131 | } 132 | 133 | 134 | 135 | #endif // UTIL_PARAM_H 136 | -------------------------------------------------------------------------------- /src/examples/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef EXAMPLES_UTIL_H 21 | #define EXAMPLES_UTIL_H 22 | 23 | #include 24 | #include // for system() 25 | #include "solver/solver.h" 26 | 27 | 28 | 29 | class FilesUtil 30 | { 31 | public: 32 | static void to_dir_basename(const std::string filename, std::string &dir, std::string &basename) 33 | { 34 | std::string ext = ""; 35 | to_dir_basename_ext(filename, dir, basename, ext); 36 | } 37 | 38 | static void to_dir_basename_ext(const std::string filename, std::string &dir, std::string &basename, std::string &ext) 39 | { 40 | // filename = dir/name 41 | dir = "."; 42 | std::string name = filename; 43 | size_t ind_slash = filename.rfind('/'); 44 | if (ind_slash != std::string::npos) 45 | { 46 | dir = filename.substr(0, ind_slash); 47 | name = filename.substr(ind_slash + 1, filename.length() - (ind_slash + 1)); 48 | } 49 | 50 | // name = basename.ext 51 | basename = name; 52 | ext = ""; 53 | size_t ind_dot = basename.rfind('.'); 54 | if (ind_dot != std::string::npos) 55 | { 56 | basename = name.substr(0, ind_dot); 57 | ext = name.substr(ind_dot + 1, name.length() - (ind_dot + 1)); 58 | } 59 | } 60 | 61 | static bool mkdir(const std::string dir) 62 | { 63 | return (system(("mkdir -p " + dir).c_str()) == 0); 64 | } 65 | 66 | }; 67 | 68 | 69 | std::string inline par_to_string(const Par &par) 70 | { 71 | std::stringstream str_params; 72 | str_params << "_alpha"; if (par.alpha >= 0.0) { str_params << par.alpha; } else { str_params << "Infinity"; } 73 | str_params << "_lambda"; if (par.lambda >= 0.0) { str_params << par.lambda; } else { str_params << "Infinity"; } 74 | if (par.temporal > 0.0 || par.temporal < 0.0) 75 | { 76 | str_params << "_temporal"; if (par.temporal >= 0.0) { str_params << par.temporal; } else { str_params << "Infinity"; } 77 | } 78 | if (par.weight) 79 | { 80 | str_params << "_weighting"; 81 | } 82 | if (par.edges) 83 | { 84 | str_params << "_edges"; 85 | } 86 | return str_params.str(); 87 | } 88 | 89 | 90 | std::string inline str_curtime() 91 | { 92 | time_t rawtime; 93 | time (&rawtime); 94 | tm *timeinfo = localtime(&rawtime); 95 | char buffer[100]; 96 | strftime(buffer, sizeof(buffer), "%I_%M_%S", timeinfo); 97 | return std::string(buffer); 98 | } 99 | 100 | 101 | #endif // EXAMPLES_UTIL_H 102 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "solver.h" 21 | 22 | #include "solver_host.h" 23 | #ifndef DISABLE_CUDA 24 | #include "solver_device.h" 25 | #endif // not DISABLE_CUDA 26 | #ifndef DISABLE_OPENCV 27 | #include "util/image_mat.h" 28 | #endif // not DISABLE_OPENCV 29 | #include "util/image.h" 30 | #include "util/types_equal.h" 31 | #include "util/has_cuda.h" 32 | #include 33 | 34 | 35 | 36 | class SolverImplementation 37 | { 38 | public: 39 | virtual ~SolverImplementation() {} 40 | 41 | // general 42 | virtual BaseImage* run(const BaseImage *in, const Par &par) = 0; 43 | 44 | // layered real 45 | virtual void run(float *&out_image, const float *in_image, const ArrayDim &dim, const Par &par) = 0; 46 | virtual void run(double *&out_image, const double *in_image, const ArrayDim &dim, const Par &par) = 0; 47 | 48 | // interlaced char 49 | virtual void run(unsigned char *&out_image, const unsigned char *in_image, const ArrayDim &dim, const Par &par) = 0; 50 | 51 | // cv::Mat 52 | #ifndef DISABLE_OPENCV 53 | virtual cv::Mat run(const cv::Mat in_image, const Par &par) = 0; 54 | #endif // not DISABLE_OPENCV 55 | 56 | virtual int get_class_type() = 0; // for is_instance_of() 57 | }; 58 | 59 | 60 | 61 | namespace 62 | { 63 | 64 | template 65 | class SolverImplementationConcrete: public SolverImplementation 66 | { 67 | public: 68 | virtual ~SolverImplementationConcrete() {}; 69 | 70 | // general 71 | virtual BaseImage* run(const BaseImage *in, const Par &par) 72 | { 73 | return solver.run(in, par); 74 | } 75 | 76 | // layered real 77 | virtual void run(float *&out_image, const float *in_image, const ArrayDim &dim, const Par &par) 78 | { 79 | run_real(out_image, in_image, dim, par); 80 | } 81 | virtual void run(double *&out_image, const double *in_image, const ArrayDim &dim, const Par &par) 82 | { 83 | run_real(out_image, in_image, dim, par); 84 | } 85 | template void run_real(real *&out_image, const real *in_image, const ArrayDim &dim, const Par &par) 86 | { 87 | typedef ManagedImage managed_image_t; 88 | 89 | managed_image_t in_managed(const_cast(in_image), dim); 90 | managed_image_t *out_managed = static_cast(solver.run(&in_managed, par)); 91 | if (out_image) 92 | { 93 | // copy 94 | managed_image_t outimage_managed(out_image, dim); 95 | outimage_managed.copy_from_samekind(out_managed); 96 | } 97 | else 98 | { 99 | // move 100 | out_image = out_managed->release_data(); 101 | } 102 | delete out_managed; 103 | } 104 | 105 | // interlaced char 106 | virtual void run(unsigned char *&out_image, const unsigned char *in_image, const ArrayDim &dim, const Par &par) 107 | { 108 | typedef ManagedImage managed_image_t; 109 | 110 | managed_image_t in_managed(const_cast(in_image), dim); 111 | managed_image_t *out_managed = static_cast(solver.run(&in_managed, par)); 112 | if (out_image) 113 | { 114 | // copy 115 | managed_image_t outimage_managed(out_image, dim); 116 | outimage_managed.copy_from_samekind(out_managed); 117 | } 118 | else 119 | { 120 | // move 121 | out_image = out_managed->release_data(); 122 | } 123 | delete out_managed; 124 | } 125 | 126 | // cv::Mat 127 | #ifndef DISABLE_OPENCV 128 | cv::Mat run(const cv::Mat in_mat, const Par &par) 129 | { 130 | MatImage in_matimage(in_mat); 131 | MatImage *out_matimage = static_cast(solver.run(&in_matimage, par)); 132 | cv::Mat out_mat = out_matimage->get_mat(); 133 | delete out_matimage; 134 | return out_mat; 135 | } 136 | #endif // not DISABLE_OPENCV 137 | 138 | int get_class_type() { return class_type; } 139 | static int static_get_class_type() { return class_type; } 140 | 141 | private: 142 | Solver solver; 143 | 144 | static const int class_type = 145 | #ifndef DISABLE_CUDA 146 | (types_equal >::value? 0 : \ 147 | types_equal >::value? 1 : \ 148 | types_equal >::value? 2 : \ 149 | types_equal >::value? 3 : -1); 150 | #else 151 | (types_equal >::value? 0 : \ 152 | types_equal >::value? 1 : -1); 153 | #endif // not DISABLE_CUDA 154 | }; 155 | 156 | 157 | template bool is_instance_of(T_object *object) 158 | { 159 | return (T_class::static_get_class_type() == object->get_class_type()); 160 | } 161 | template void set_implementation_concrete(SolverImplementation *&implementation, const Par &par) 162 | { 163 | if (implementation && !is_instance_of(implementation)) 164 | { 165 | // allocated, but wrong class 166 | delete implementation; 167 | implementation = NULL; 168 | } 169 | if (!implementation) 170 | { 171 | implementation = new Implementation(); 172 | } 173 | } 174 | template void set_implementation_real(SolverImplementation *&implementation, const Par &par) 175 | { 176 | switch (par.engine) 177 | { 178 | case Par::engine_cpu: 179 | { 180 | set_implementation_concrete > >(implementation, par); 181 | return; 182 | } 183 | case Par::engine_cuda: 184 | { 185 | std::string error_str; 186 | bool cuda_ok = has_cuda(&error_str); 187 | #ifndef DISABLE_CUDA 188 | if (cuda_ok) { set_implementation_concrete > >(implementation, par); } 189 | #endif // not DISABLE_CUDA 190 | if (!cuda_ok) 191 | { 192 | std::cerr << "ERROR: Solver::run(): Could not select CUDA engine, USING CPU VERSION INSTEAD (" << error_str.c_str() << ")." << std::endl; 193 | Par par_cpu = par; 194 | par_cpu.engine = Par::engine_cpu; 195 | set_implementation_real(implementation, par_cpu); 196 | } 197 | break; 198 | } 199 | default: 200 | { 201 | std::cerr << "ERROR: Solver::run(): Unexpected engine " << par.engine << ", USING CPU VERSION INSTEAD" << std::endl; 202 | Par par_cpu = par; 203 | par_cpu.engine = Par::engine_cpu; 204 | set_implementation_real(implementation, par_cpu); 205 | } 206 | } 207 | } 208 | void set_implementation(SolverImplementation *&implementation, const Par &par) 209 | { 210 | if (par.use_double) 211 | { 212 | set_implementation_real(implementation, par); 213 | } 214 | else 215 | { 216 | set_implementation_real(implementation, par); 217 | } 218 | } 219 | 220 | } // namespace 221 | 222 | 223 | 224 | Solver::Solver() : implementation(NULL) {} 225 | Solver::~Solver() { if (implementation) { delete implementation; } } 226 | BaseImage* Solver::run(const BaseImage *in, const Par &par) 227 | { 228 | set_implementation(implementation, par); if (!implementation) { return NULL; } 229 | return implementation->run(in, par); 230 | } 231 | void Solver::run(float *&out_image, const float *in_image, const ArrayDim &dim, const Par &par) 232 | { 233 | set_implementation_real(implementation, par); if (!implementation) { return; } 234 | return implementation->run(out_image, in_image, dim, par); 235 | } 236 | void Solver::run(double *&out_image, const double *in_image, const ArrayDim &dim, const Par &par) 237 | { 238 | set_implementation_real(implementation, par); if (!implementation) { return; } 239 | return implementation->run(out_image, in_image, dim, par); 240 | } 241 | void Solver::run(unsigned char *&out_image, const unsigned char *in_image, const ArrayDim &dim, const Par &par) 242 | { 243 | set_implementation(implementation, par); if (!implementation) { return; } 244 | return implementation->run(out_image, in_image, dim, par); 245 | } 246 | #ifndef DISABLE_OPENCV 247 | cv::Mat Solver::run(const cv::Mat in_image, const Par &par) 248 | { 249 | set_implementation(implementation, par); if (!implementation) { return cv::Mat(); } 250 | return implementation->run(in_image, par); 251 | } 252 | #endif // not DISABLE_OPENCV 253 | 254 | 255 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef SOLVER_H 21 | #define SOLVER_H 22 | 23 | #ifndef DISABLE_OPENCV 24 | #include 25 | #endif // not DISABLE_OPENCV 26 | 27 | #include 28 | 29 | 30 | 31 | struct Par 32 | { 33 | Par() 34 | { 35 | lambda = 0.1; 36 | alpha = 20.0; 37 | temporal = 0.0; 38 | iterations = 10000; 39 | stop_eps = 5e-5; 40 | stop_k = 10; 41 | adapt_params = false; 42 | weight = false; 43 | edges = false; 44 | use_double = false; 45 | engine = engine_cuda; 46 | verbose = true; 47 | } 48 | 49 | void print() const 50 | { 51 | std::cout << "Params:\n"; 52 | std::cout << " lambda: " << lambda << "\n"; 53 | std::cout << " alpha: " << alpha << "\n"; 54 | std::cout << " temporal: " << temporal << "\n"; 55 | std::cout << " iterations: " << iterations << "\n"; 56 | std::cout << " stop_eps: " << stop_eps << "\n"; 57 | std::cout << " stop_k: " << stop_k << "\n"; 58 | std::cout << " adapt_params: " << adapt_params << "\n"; 59 | std::cout << " weight: " << weight << "\n"; 60 | std::cout << " edges: " << edges << "\n"; 61 | std::cout << " use_double: " << use_double << "\n"; 62 | std::cout << " engine: " << (engine == Par::engine_cpu? "cpu" : "cuda") << "\n"; 63 | } 64 | 65 | // Length penalization parameter. 66 | // For bigger values: 67 | // Number of discontinuities will be smaller, i.e. the solution will be smooth over larger regions. 68 | // To set lambda = infinity: Set lambda to any value < 0. Solution will be a constant one, with one and the same color in every pixel ( = mean color). 69 | // For smaller values: 70 | // More discontinuities will arise, i.e. the regions of smoothness will be smaller and the solution will resemble the input image more and more. 71 | // Value lambda = 0: Solution will be equal to the original input image. 72 | double lambda; 73 | 74 | // Smoothness penalization parameter. 75 | // For bigger values: 76 | // Solution will be more "flat" in the regions of smoothness (between the color edges), i.e. there will be only a small change in color values from pixel to pixel. 77 | // To set alpha = infinity: Set alpha to any value < 0. This is the cartoon limit case, i.e. the solution will be piecewise constant. This is the segmentation case. 78 | // For smaller values: 79 | // Solution will be more "rough" in the regions of smoothness (between the color edges), i.e. the color values are allowed to change more rapidly from pixel to pixel. 80 | // Value alpha = 0: Solution will be equal to the original input image. 81 | double alpha; 82 | 83 | // Temporal penalization parameter. 84 | // For bigger values: 85 | // Solution will be driven to be similar to the previous frame solutions. 86 | // To set temporal_regularization = infinity: Set to any value < 0. Solution will not change from frame to frame. 87 | // For smaller values: 88 | // Each frame is mostly independent. 89 | // Value temporal_regularization = 0: No temporal regularization, each frame is independent. 90 | double temporal; 91 | 92 | // Maximal number of iterations to perform. 93 | // This is only an upper bound for the maximal number of iterations. The actual number of iterations may be less than this, since the iterations will be stopped once difference between consecutive solutions is small enough. 94 | int iterations; 95 | 96 | // Determines the stopping criterion: 97 | // Iterations will be stopped if 1/(w*h) sum_{x,y,i} |u_{n+1}(x,y,i) - u_n(x,y,i)| < stopping_eps. 98 | double stop_eps; 99 | 100 | // The stopping criterion will be checked for only every k-th iteration, where k is given by this parameter. 101 | // If set to <= 0, no checking will be performed, i.e. all max_num_iterations iterations will be made. 102 | int stop_k; 103 | 104 | // If true: lambda and alpha will be adapted so that the solution will look more or less the same, for one and the same input image and for different scalings. 105 | // Using this, one can run time intensive experiments on downscaled images, find suitable parameters, and then run the experiment on the original images, with the same parameters. 106 | // Effectively, lambda and alpha are used as is for a "standard" image scale (640 x 480), and for a general image size w * h 107 | // they are set to 108 | // lambda_actual = lambda * factor 109 | // alpha_actual = alpha * factor * factor 110 | // where factor = sqrt(640 * 480) / sqrt(w * h). 111 | // If false: lambda and alpha are used as is, regardless of image scale. 112 | bool adapt_params; 113 | 114 | // If true: The regularizer will be adjust to smooth less at pixels with high edge probability 115 | // This changes the regularizer to 116 | // 117 | // min(alpha * |gradient u(x, y)| ^ 2, lambda * weight(x, y)), 118 | // 119 | // instead of the original regularizer with weight(x, y) = 1 for all (x, y). 120 | // The weight is set as 121 | // 122 | // weight(x, y) := exp(-|gradient_of_input_image(x, y)| / sigma), 123 | // 124 | // with sigma := 1 / (w * h) * sum_{pixels (x, y)} |gradient_of_input_image(x, y)|. 125 | // 126 | bool weight; 127 | 128 | // If true: The edge set will be overlaid on top of the computed color image. 129 | bool edges; 130 | 131 | // Compute everything with double instead of float. 132 | bool use_double; 133 | 134 | // Use CPU or CUDA. 135 | int engine; 136 | static const int engine_cpu = 0; 137 | static const int engine_cuda = 1; 138 | 139 | // If true: Output information: 140 | // - image dimensions 141 | // - required memory 142 | // - number of iterations after which the stopping criterion has been reached 143 | // - time for computation only (excluding allocation and initialization) 144 | // - energy 145 | bool verbose; 146 | }; 147 | 148 | 149 | // p_impl design pattern to reduce header to the minimum in order to avoid unnecessary dependencies 150 | class SolverImplementation; 151 | 152 | // forward-declare here to avoid unnecessary dependencies 153 | class ArrayDim; 154 | class BaseImage; 155 | 156 | // class instead of function to be able to maintain state, i.e. use same memory allocation for several images 157 | class Solver 158 | { 159 | public: 160 | Solver(); 161 | ~Solver(); 162 | 163 | // general 164 | BaseImage* run(const BaseImage *in, const Par &par); 165 | 166 | // layered real 167 | void run(float *&out_image, const float *in_image, const ArrayDim &dim, const Par &par); 168 | void run(double *&out_image, const double *in_image, const ArrayDim &dim, const Par &par); 169 | 170 | // interlaced char 171 | void run(unsigned char *&out_image, const unsigned char *in_image, const ArrayDim &dim, const Par &par); 172 | 173 | // cv::Mat 174 | #ifndef DISABLE_OPENCV 175 | cv::Mat run(const cv::Mat in_image, const Par &par); 176 | #endif // not DISABLE_OPENCV 177 | 178 | 179 | private: 180 | Solver(const Solver &other_solver); // disable 181 | Solver& operator= (const Solver &other_solver); // disable 182 | 183 | SolverImplementation *implementation; 184 | }; 185 | 186 | 187 | 188 | #endif // SOLVER_H 189 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver_base.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "solver_base.h" 21 | #include // for snprintf 22 | #include "util/timer.h" 23 | 24 | 25 | 26 | template 27 | SolverBase::SolverBase() 28 | { 29 | engine = NULL; 30 | u_is_computed = false; 31 | } 32 | 33 | 34 | template 35 | SolverBase::~SolverBase() 36 | { 37 | } 38 | 39 | 40 | template 41 | void SolverBase::set_engine(Engine *engine) 42 | { 43 | this->engine = engine; 44 | } 45 | 46 | 47 | template 48 | size_t SolverBase::alloc(const ArrayDim &dim_u) 49 | { 50 | engine->alloc(dim_u); 51 | const ArrayDim &dim_p = pd_vars.linear_operator.dim_range(dim_u); 52 | size_t mem = arr.alloc(engine, dim_u, dim_p); 53 | if (mem > 0) { u_is_computed = false; } 54 | return mem; 55 | } 56 | 57 | 58 | template 59 | void SolverBase::free() 60 | { 61 | arr.free(engine); 62 | engine->free(); 63 | } 64 | 65 | 66 | template 67 | void SolverBase::init(const BaseImage *image) 68 | { 69 | image->copy_to_layered(arr.f.get_untyped_access()); 70 | if (par.temporal == real(0)) { u_is_computed = false; } 71 | if (u_is_computed) 72 | { 73 | engine->image_manager()->copy_from_samekind(arr.prev_u, arr.u); 74 | } 75 | engine->image_manager()->copy_from_samekind(arr.u, arr.f); 76 | engine->image_manager()->copy_from_samekind(arr.ubar, arr.u); 77 | engine->image_manager()->setzero(arr.p); 78 | if (par.weight) 79 | { 80 | set_regularizer_weight_from(arr.f); 81 | } 82 | pd_vars.init(par, arr.f, arr.regularizer_weight, (u_is_computed? arr.prev_u : image_access_t())); 83 | } 84 | 85 | 86 | template 87 | void SolverBase::set_regularizer_weight_from(image_access_t image) 88 | { 89 | linear_operator_t linear_operator; 90 | const Dim2D &dim2d = image.dim().dim2d(); 91 | 92 | // real gamma = real(1); 93 | engine->set_regularizer_weight_from__normgrad(arr.regularizer_weight, image, linear_operator); 94 | real sigma = engine->get_sum(arr.regularizer_weight) / (real(dim2d.w) * real(dim2d.h)); 95 | 96 | real coeff = (sigma > real(0)? real(2) / sigma : real(0)); // 2 = dim_image_domain 97 | engine->set_regularizer_weight_from__exp (arr.regularizer_weight, coeff); 98 | } 99 | 100 | 101 | template 102 | real SolverBase::energy() 103 | { 104 | engine->energy_base(arr.u, arr.aux_reduce, pd_vars.linear_operator, pd_vars.dataterm, pd_vars.regularizer); 105 | real energy = engine->get_sum(arr.aux_reduce); 106 | real mult = real(1) / (pd_vars.scale_omega * pd_vars.scale_omega); 107 | energy *= mult; 108 | return energy; 109 | } 110 | 111 | 112 | template 113 | real SolverBase::diff_l1(image_access_t a, image_access_t b) 114 | { 115 | engine->diff_l1_base(a, b, arr.aux_reduce); 116 | real diff = engine->get_sum(arr.aux_reduce); 117 | const Dim2D &dim2d = a.dim().dim2d(); 118 | diff /= (size_t)dim2d.w * dim2d.h; 119 | return diff; 120 | } 121 | template 122 | bool SolverBase::is_converged(int iteration) 123 | { 124 | if (par.stop_k <= 0 || (iteration + 1) % par.stop_k != 0) 125 | { 126 | return false; 127 | } 128 | real diff_to_prev = diff_l1(arr.u, arr.ubar) / pd_vars.theta_bar; 129 | return (diff_to_prev <= par.stop_eps); 130 | } 131 | 132 | 133 | template 134 | BaseImage* SolverBase::get_solution(const BaseImage *image) 135 | { 136 | engine->image_manager()->copy_from_samekind(arr.aux_result, arr.u); 137 | if (par.edges) 138 | { 139 | engine->add_edges(arr.aux_result, pd_vars.linear_operator, pd_vars.regularizer); 140 | } 141 | BaseImage* out_image = image->new_of_same_type_and_size(); 142 | out_image->copy_from_layered(arr.aux_result.get_untyped_access()); 143 | return out_image; 144 | } 145 | 146 | 147 | template 148 | void SolverBase::print_stats() 149 | { 150 | if (stats.mem > 0) 151 | { 152 | std::cout << "alloc " << (stats.mem + (1<<20) - 1) / (1<<20) << " MB for "; 153 | std::cout << stats.dim_u << ", "; 154 | } 155 | std::string str_from_engine = engine->str(); 156 | if (str_from_engine != "") { std::cout << str_from_engine.c_str() << ", "; } 157 | char buffer[100]; 158 | snprintf(buffer, sizeof(buffer), "%2.4f s compute / %2.4f s all (+ %2.4f)", stats.time_compute, stats.time, stats.time - stats.time_compute); std::cout << buffer; 159 | if (stats.num_runs > 1) 160 | { 161 | snprintf(buffer, sizeof(buffer), ", average %2.4f s / %2.4f s (+ %2.4f)", stats.time_compute_sum / stats.num_runs, stats.time_sum / stats.num_runs, (stats.time_sum - stats.time_compute_sum) / stats.num_runs); std::cout << buffer; 162 | } 163 | if (stats.stop_iteration != -1) 164 | { 165 | std::cout << ", " << (stats.stop_iteration + 1) << " iterations"; 166 | } 167 | else 168 | { 169 | std::cout << ", did not stop after " << par.iterations << " iterations"; 170 | } 171 | std::cout << ", lambda " << par.lambda; 172 | if (par.adapt_params) { std::cout << " (adapted " << pd_vars.regularizer.lambda << ")"; } 173 | std::cout << ", alpha " << par.alpha; 174 | if (par.adapt_params) { std::cout << " (adapted " << pd_vars.regularizer.alpha << ")"; } 175 | if (par.temporal > 0) 176 | { 177 | std::cout << ", temporal " << par.temporal; 178 | } 179 | if (par.weight) 180 | { 181 | std::cout << ", weighting"; 182 | } 183 | std::cout << ", energy "; 184 | snprintf(buffer, sizeof(buffer), "%4.4f", stats.energy); std::cout << buffer; 185 | std::cout << std::endl; 186 | } 187 | 188 | 189 | template 190 | BaseImage* SolverBase::run(const BaseImage *image, const Par &par_const) 191 | { 192 | if (!engine->is_valid()) { BaseImage *out_image = image->new_of_same_type_and_size(); return out_image; } 193 | Timer timer_all; 194 | timer_all.start(); 195 | 196 | // allocate (only if not already allocated) 197 | this->par = par_const; 198 | stats.dim_u = image->dim(); 199 | stats.dim_p = linear_operator_t::dim_range(stats.dim_u); 200 | stats.mem = alloc(stats.dim_u); 201 | 202 | 203 | // initialize 204 | init(image); 205 | 206 | 207 | // compute 208 | engine->timer_start(); 209 | stats.stop_iteration = -1; 210 | for (int iteration = 0; iteration < par.iterations; iteration++) 211 | { 212 | pd_vars.update_vars(); 213 | engine->run_dual_p(arr.p, arr.ubar, pd_vars.linear_operator, pd_vars.regularizer, pd_vars.dt_d); 214 | engine->run_prim_u(arr.u, arr.ubar, arr.p, pd_vars.linear_operator, pd_vars.dataterm, pd_vars.theta_bar, pd_vars.dt_p); 215 | if (is_converged(iteration)) { stats.stop_iteration = iteration; break; } 216 | } 217 | engine->timer_end(); 218 | u_is_computed = true; 219 | stats.time_compute = engine->timer_get(); 220 | stats.time_compute_sum += stats.time_compute; 221 | stats.num_runs++; 222 | stats.energy = energy(); 223 | 224 | 225 | // get solution 226 | BaseImage *result = get_solution(image); 227 | engine->synchronize(); 228 | timer_all.end(); 229 | stats.time = timer_all.get(); 230 | stats.time_sum += stats.time; 231 | if (par.verbose) { print_stats(); } 232 | return result; 233 | } 234 | 235 | 236 | template class SolverBase; 237 | template class SolverBase; 238 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef SOLVER_BASE_H 21 | #define SOLVER_BASE_H 22 | 23 | #include "solver_common_operators.h" 24 | #include "util/image.h" 25 | 26 | 27 | 28 | template 29 | class Engine 30 | { 31 | public: 32 | typedef ImageAccess image_access_t; 33 | typedef typename image_access_t::data_interpretation_t data_interpretation_t; 34 | typedef LinearOperator linear_operator_t; 35 | typedef Regularizer regularizer_t; 36 | typedef Dataterm dataterm_t; 37 | typedef ImageManagerBase image_manager_base_t; 38 | 39 | virtual ~Engine() {} 40 | virtual std::string str() { return ""; }; 41 | virtual void alloc(const ArrayDim &dim_u) = 0; 42 | virtual void free() = 0; 43 | virtual bool is_valid() = 0; 44 | virtual image_manager_base_t* image_manager() = 0; 45 | virtual real get_sum(image_access_t a) = 0; 46 | virtual void timer_start() = 0; 47 | virtual void timer_end() = 0; 48 | virtual double timer_get() = 0; 49 | virtual void synchronize() = 0; 50 | 51 | virtual void run_dual_p(image_access_t p, image_access_t u, linear_operator_t linear_operator, regularizer_t regularizer, real dt) = 0; 52 | virtual void run_prim_u(image_access_t u, image_access_t ubar, image_access_t p, linear_operator_t linear_operator, dataterm_t dataterm, real theta_bar, real dt) = 0; 53 | virtual void energy_base(image_access_t u, image_access_t aux_reduce, linear_operator_t linear_operator, dataterm_t dataterm, regularizer_t regularizer) = 0; 54 | virtual void add_edges(image_access_t cur_result, linear_operator_t linear_operator, regularizer_t regularizer) = 0; 55 | virtual void set_regularizer_weight_from__normgrad(image_access_t regularizer_weight, image_access_t image, linear_operator_t linear_operator) = 0; 56 | virtual void set_regularizer_weight_from__exp(image_access_t regularizer_weight, real coeff) = 0; 57 | virtual void diff_l1_base(image_access_t a, image_access_t b, image_access_t aux_reduce) = 0; 58 | }; 59 | 60 | 61 | template 62 | class SolverBase 63 | { 64 | public: 65 | SolverBase(); 66 | virtual ~SolverBase(); 67 | 68 | BaseImage* run(const BaseImage *image, const Par &par_const); 69 | 70 | protected: 71 | void set_engine(Engine *engine); 72 | 73 | private: 74 | typedef typename Engine::image_access_t image_access_t; 75 | typedef typename Engine::linear_operator_t linear_operator_t; 76 | 77 | size_t alloc(const ArrayDim &dim_u); 78 | void free(); 79 | void init(const BaseImage *image); 80 | void set_regularizer_weight_from(image_access_t image); 81 | real energy(); 82 | real diff_l1(image_access_t a, image_access_t b); 83 | bool is_converged(int iteration); 84 | void print_stats(); 85 | BaseImage* get_solution(const BaseImage *image); 86 | 87 | Engine *engine; 88 | Par par; 89 | PrimalDualVars pd_vars; 90 | bool u_is_computed; 91 | 92 | struct Arrays 93 | { 94 | size_t alloc(Engine *engine, const ArrayDim &dim_u, const ArrayDim &dim_p) 95 | { 96 | ArrayDim dim_scalar(dim_u.w, dim_u.h, 1); 97 | size_t mem = 0; 98 | mem += engine->image_manager()->alloc(u, dim_u); 99 | mem += engine->image_manager()->alloc(ubar, dim_u); 100 | mem += engine->image_manager()->alloc(f, dim_u); 101 | mem += engine->image_manager()->alloc(p, dim_p); 102 | mem += engine->image_manager()->alloc(regularizer_weight, dim_scalar); 103 | mem += engine->image_manager()->alloc(prev_u, dim_u); 104 | mem += engine->image_manager()->alloc(aux_result, dim_u); 105 | mem += engine->image_manager()->alloc(aux_reduce, dim_scalar); 106 | return mem; 107 | } 108 | void free(Engine *engine) 109 | { 110 | engine->image_manager()->free(u); 111 | engine->image_manager()->free(ubar); 112 | engine->image_manager()->free(f); 113 | engine->image_manager()->free(p); 114 | engine->image_manager()->free(regularizer_weight); 115 | engine->image_manager()->free(prev_u); 116 | engine->image_manager()->free(aux_result); 117 | engine->image_manager()->free(aux_reduce); 118 | } 119 | image_access_t u; 120 | image_access_t ubar; 121 | image_access_t f; 122 | image_access_t p; 123 | image_access_t regularizer_weight; 124 | image_access_t prev_u; 125 | image_access_t aux_result; 126 | image_access_t aux_reduce; 127 | } arr; 128 | 129 | struct ResultStats 130 | { 131 | ResultStats() 132 | { 133 | mem = 0; 134 | stop_iteration = -1; 135 | time_compute = 0.0; 136 | time_compute_sum = 0.0; 137 | time = 0.0; 138 | time_sum = 0.0; 139 | num_runs = 0; 140 | energy = real(0); 141 | } 142 | ArrayDim dim_u; 143 | ArrayDim dim_p; 144 | size_t mem; 145 | int stop_iteration; 146 | double time_compute; // actual computation without alloc and image conversions and copying, in seconds 147 | double time_compute_sum; // accumulation for averaging 148 | double time; // overall time, including alloc, image conversions and copying, in second 149 | double time_sum; // accumulation for averaging 150 | int num_runs; 151 | real energy; 152 | } stats; 153 | }; 154 | 155 | 156 | #endif // SOLVER_BASE_H 157 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver_common_operators.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef SOLVER_COMMON_OPERATORS_HCU 21 | #define SOLVER_COMMON_OPERATORS_HCU 22 | 23 | #include "solver.h" 24 | #include "util/image_access.h" 25 | 26 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 27 | #define HOST_DEVICE __host__ __device__ 28 | #define FORCEINLINE __forceinline__ 29 | #else 30 | #define HOST_DEVICE 31 | #define FORCEINLINE inline 32 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 33 | 34 | 35 | 36 | // Gradient operator with forward differences 37 | template 38 | class LinearOperator 39 | { 40 | public: 41 | HOST_DEVICE static int num_channels_range(int num_channels_domain) 42 | { 43 | return 2 * num_channels_domain; 44 | } 45 | 46 | HOST_DEVICE static ArrayDim dim_range(const ArrayDim &dim_domain) 47 | { 48 | ArrayDim dim_range_result = dim_domain; 49 | dim_range_result.num_channels = num_channels_range(dim_domain.num_channels); 50 | return dim_range_result; 51 | } 52 | 53 | HOST_DEVICE static real maximal_possible_range_norm(int num_channels_domain) 54 | { 55 | return realsqrt(real(2)) * num_channels_range(num_channels_domain); 56 | } 57 | 58 | template 59 | HOST_DEVICE void apply(TArray &p, TAccess &u, int x, int y, const Dim2D &dim2d, const int u_num_channels) 60 | { 61 | for(int i = 0; i < u_num_channels; i++) 62 | { 63 | real u0 = u.get(x, y, i); 64 | real uplusx = (x + 1 < dim2d.w? u.get(x + 1, y, i) : real(0)); 65 | real uplusy = (y + 1 < dim2d.h? u.get(x, y + 1, i) : real(0)); 66 | p.get(0 + 2 * i) = (x + 1 < dim2d.w? uplusx - u0 : real(0)); 67 | p.get(1 + 2 * i) = (y + 1 < dim2d.h? uplusy - u0 : real(0)); 68 | } 69 | } 70 | 71 | HOST_DEVICE real apply_sumcoeffs() 72 | { 73 | return real(2); 74 | } 75 | 76 | template 77 | HOST_DEVICE void apply_transpose(Array1D &u, TAccess &p, int x, int y, const Dim2D &dim2d, const int u_num_channels) 78 | { 79 | for(int i = 0; i < u_num_channels; i++) 80 | { 81 | real p1_0 = (x + 1 < dim2d.w? p.get(x, y, 0 + 2 * i) : real(0)); 82 | real p1_x = (x > 0? p.get(x - 1, y, 0 + 2 * i) : real(0)); 83 | real p2_0 = (y + 1 < dim2d.h? p.get(x, y, 1 + 2 * i) : real(0)); 84 | real p2_y = (y > 0? p.get(x, y - 1, 1 + 2 * i) : real(0)); 85 | real val = p1_x - p1_0 + p2_y - p2_0; 86 | u.get(i) = val; 87 | } 88 | } 89 | 90 | HOST_DEVICE real apply_transpose_sumcoeffs() 91 | { 92 | return real(4); 93 | } 94 | }; 95 | 96 | 97 | // Quadratic data term (u - f) ^ 2 98 | template 99 | class Dataterm 100 | { 101 | public: 102 | typedef typename TImageAccess::elem_t real; 103 | 104 | HOST_DEVICE Dataterm() : temporal(real(0)) 105 | { 106 | } 107 | 108 | // the coefficient c in the data term: c * (u-f) ^ 2, usually c = 1. 109 | HOST_DEVICE real get_coeff() 110 | { 111 | return real(1); 112 | } 113 | 114 | HOST_DEVICE bool has_temporal() 115 | { 116 | return prev_u.is_valid() && (temporal > real(0) || temporal < real(0)); 117 | } 118 | 119 | template 120 | HOST_DEVICE void prox (Array1D &u, real dt, int x, int y, const Dim2D &dim2d, const int u_num_channels) 121 | { 122 | // arg min_u (u - u0)^2 / (2 * dt) + coeff * (u - f)^2 123 | real c0 = get_coeff(); 124 | 125 | for(int i = 0; i < u_num_channels; i++) 126 | { 127 | real f0 = f.get(x, y, i); 128 | real u0 = u.get(i); 129 | u0 = f0 + (u0 - f0) / (real(1) + real(2) * dt * c0); 130 | u.get(i) = u0; 131 | } 132 | 133 | if (has_temporal()) 134 | { 135 | for (int i = 0; i < u_num_channels; i++) { u.get(i) -= prev_u.get(x, y, i); } 136 | 137 | real nrm = vec_norm(u, u_num_channels); 138 | if (nrm > real(0)) 139 | { 140 | // default value for temporal = infinity 141 | real mult = real(0); 142 | if (temporal > real(0) && temporal < realmax()) 143 | { 144 | real gamma = temporal * dt / (real(1) + real(2) * dt * c0); 145 | real a = gamma * real(1.5) / realsqrt(nrm); 146 | mult = real(2) / (a + realsqrt(a * a + real(4))); 147 | mult = mult * mult; 148 | } 149 | vec_scale_eq(u, u_num_channels, mult); 150 | } 151 | 152 | for(int i = 0; i < u_num_channels; i++) { u.get(i) += prev_u.get(x, y, i); } 153 | } 154 | } 155 | 156 | template 157 | HOST_DEVICE real value (Array1D &u, int x, int y, const Dim2D &dim2d, const int u_num_channels) 158 | { 159 | // coeff * (u - f)^2 160 | real c0 = get_coeff(); 161 | 162 | real val = real(0); 163 | 164 | real diff_f = real(0); 165 | for(int i = 0; i < u_num_channels; i++) 166 | { 167 | real diff = u.get(i) - f.get(x, y, i); 168 | diff_f += diff * diff; 169 | } 170 | diff_f *= c0; 171 | val += diff_f; 172 | 173 | if (has_temporal()) 174 | { 175 | real diff_prev = 0; 176 | for(int i = 0; i < u_num_channels; i++) 177 | { 178 | real diff = u.get(i) - prev_u.get(x, y, i); 179 | diff_prev += diff * diff; 180 | } 181 | diff_prev = realsqrt(diff_prev); 182 | diff_prev = temporal * diff_prev * realsqrt(diff_prev); 183 | val += diff_prev; 184 | } 185 | 186 | return val; 187 | } 188 | 189 | TImageAccess f; 190 | TImageAccess prev_u; 191 | real temporal; 192 | }; 193 | 194 | 195 | // Mumford-Shah regularizer min(alpha * |nabla u| ^ 2, lambda) 196 | template 197 | class Regularizer 198 | { 199 | public: 200 | typedef typename TImageAccess::elem_t real; 201 | 202 | HOST_DEVICE Regularizer() : lambda(0), alpha(0) 203 | { 204 | } 205 | 206 | template 207 | HOST_DEVICE void prox_star(Array1D &p, real dt, int x, int y, const Dim2D &dim2d, const int p_num_channels) 208 | { 209 | real weight0 = (weight.is_valid()? weight.get(x, y, 0) : real(1)); 210 | // min(alpha * |g|^2, lambda * weight) 211 | real nrm2 = vec_norm_squared(p, p_num_channels); 212 | real A = (alpha >= 0 && alpha < realmax()? real(2) * alpha / (dt + real(2) * alpha) : real(1)); 213 | real L = (lambda >= 0 && lambda < realmax()? real(2) * dt * lambda * weight0 : realmax()); 214 | real mult = (nrm2 * A <= L? A : real(0)); 215 | vec_scale_eq (p, p_num_channels, mult); 216 | } 217 | 218 | template 219 | HOST_DEVICE real value(Array1D &p, int x, int y, const Dim2D &dim2d, const int p_num_channels) 220 | { 221 | real weight0 = (weight.is_valid()? weight.get(x, y, 0) : real(1)); 222 | real A = (alpha >= 0 && alpha < realmax()? alpha : realmax()); 223 | real L = (lambda >= 0 && lambda < realmax()? lambda * weight0 : realmax()); 224 | real nrm = vec_norm(p, p_num_channels); 225 | real val = real(0); 226 | if (A < realmax()) 227 | { 228 | val = realmin(A * nrm * nrm, L); 229 | } 230 | else 231 | { 232 | real eps = (alpha < real(0)? real(1e-6) : -alpha); 233 | val = (nrm > eps? L : real(0)); 234 | } 235 | return val; 236 | } 237 | 238 | template 239 | HOST_DEVICE real edge_indicator(Array1D &p, real max_range_norm, int x, int y, const Dim2D &dim2d, const int p_num_channels) 240 | { 241 | real weight0 = (weight.is_valid()? weight.get(x, y, 0) : real(1)); 242 | real A = (alpha >= 0 && alpha < realmax()? alpha : realmax()); 243 | real L = (lambda >= 0 && lambda < realmax()? lambda * weight0 : realmax()); 244 | // Pixel (x,y) is an edge pixel if the gradient is so large that in 245 | // min(alpha * |gradient| ^ 2, lambda * weight) = min(A * |gradient| ^ 2, L) 246 | // the minimum is achieved by the second argument. 247 | real norm_threshold = realsqrt(L / A); 248 | const real eps = real(5e-3); 249 | //if (A >= realmax()) norm_threshold = eps; 250 | norm_threshold = realmax(norm_threshold, eps); 251 | 252 | real cur_norm = vec_norm(p, p_num_channels); 253 | max_range_norm = realmax(max_range_norm, cur_norm); // to be sure 254 | real val_edge_indicator = real(0); 255 | if (cur_norm > norm_threshold) 256 | { 257 | // It holds 1 < cur_norm / norm_threshold. 258 | // Because of max_range_norm >= cur_norm: Also 1 < cur_norm / norm_threshold <= max_range_norm / norm_threshold. 259 | // Therefore 0 < log(cur_norm / norm_threshold) <= log(max_range_norm / norm_threshold), 260 | // i.e. 0 < log(cur_norm / norm_threshold) / log(max_range_norm / norm_threshold) <= 1. 261 | // Use this as edge indicator. 262 | val_edge_indicator = reallog(cur_norm / norm_threshold) / reallog(max_range_norm / norm_threshold); 263 | } 264 | return val_edge_indicator; 265 | } 266 | 267 | real lambda; 268 | real alpha; 269 | TImageAccess weight; 270 | }; 271 | 272 | 273 | template 274 | class PrimalDualVars 275 | { 276 | public: 277 | typedef typename TImageAccess::elem_t real; 278 | 279 | PrimalDualVars() 280 | { 281 | dt_p = real(0); 282 | dt_d = real(0); 283 | theta_bar = real(0); 284 | gamma_dataterm = real(0); 285 | scale_omega = real(0); 286 | } 287 | 288 | void init(const Par &par, TImageAccess f, TImageAccess regularizer_weight, TImageAccess prev_u) 289 | { 290 | real dt_factor = real(1); 291 | dt_p = real(1) * dt_factor / linear_operator.apply_transpose_sumcoeffs(); 292 | dt_d = real(1) / dt_factor / linear_operator.apply_sumcoeffs(); 293 | theta_bar = real(1); 294 | gamma_dataterm = real(2); 295 | if (par.adapt_params) 296 | { 297 | if (f.dim().h > 1) 298 | { 299 | scale_omega = realsqrt(real(f.dim().w) * real(f.dim().h)) / realsqrt(real(640) * real(480)); 300 | } 301 | else 302 | { 303 | scale_omega = real(f.dim().w) / real(640); 304 | } 305 | } 306 | else 307 | { 308 | scale_omega = real(1); 309 | } 310 | 311 | dataterm.f = f; 312 | bool has_temporal = (prev_u.is_valid() && (par.temporal > real(0) || par.temporal < real(0))); 313 | dataterm.prev_u = (has_temporal? prev_u : TImageAccess()); 314 | dataterm.temporal = (has_temporal? par.temporal : real(0)); 315 | regularizer.alpha = (par.adapt_params && par.alpha >= 0 && par.alpha < realmax()? par.alpha * scale_omega * scale_omega : par.alpha); 316 | regularizer.lambda = (par.adapt_params && par.lambda >= 0 && par.lambda < realmax()? par.lambda * scale_omega : par.lambda); 317 | regularizer.weight = (par.weight? regularizer_weight : TImageAccess()); 318 | } 319 | 320 | void update_vars() 321 | { 322 | dt_p *= theta_bar; 323 | dt_d /= theta_bar; 324 | theta_bar = real(1) / realsqrt(real(1) + real(2) * gamma_dataterm * dt_p); 325 | } 326 | 327 | real dt_p; 328 | real dt_d; 329 | real theta_bar; 330 | real gamma_dataterm; 331 | real scale_omega; 332 | 333 | LinearOperator linear_operator; 334 | Dataterm dataterm; 335 | Regularizer regularizer; 336 | }; 337 | 338 | 339 | 340 | #undef HOST_DEVICE 341 | #undef FORCEINLINE 342 | 343 | #endif // SOLVER_COMMON_OPERATORS_HCU 344 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver_device.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef SOLVER_DEVICE_H 21 | #define SOLVER_DEVICE_H 22 | 23 | #ifndef DISABLE_CUDA 24 | 25 | #include "solver.h" 26 | 27 | 28 | 29 | template class SolverDeviceImplementation; 30 | 31 | template 32 | class SolverDevice 33 | { 34 | public: 35 | typedef real real_t; 36 | 37 | SolverDevice(); 38 | ~SolverDevice(); 39 | 40 | BaseImage* run(const BaseImage *image, const Par &par); 41 | 42 | private: 43 | SolverDevice(const SolverDevice &other_solver); // disable 44 | SolverDevice& operator= (const SolverDevice &other_solver); // disable 45 | 46 | SolverDeviceImplementation *implementation; 47 | }; 48 | 49 | 50 | #endif // not DISABLE_CUDA 51 | 52 | #endif // SOLVER_DEVICE_H 53 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver_host.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "solver_host.h" 21 | #include "solver_base.h" 22 | #include "util/mem.h" 23 | #include "util/sum.h" 24 | #include "util/timer.h" 25 | 26 | 27 | 28 | template 29 | class HostEngine: public Engine 30 | { 31 | public: 32 | typedef Engine Base; 33 | typedef typename Base::image_access_t image_access_t; 34 | typedef typename Base::linear_operator_t linear_operator_t; 35 | typedef typename Base::regularizer_t regularizer_t; 36 | typedef typename Base::dataterm_t dataterm_t; 37 | typedef HostAllocator allocator_t; 38 | typedef ImageManager image_manager_t; 39 | 40 | HostEngine() {} 41 | virtual ~HostEngine() {} 42 | virtual std::string str(); 43 | virtual void alloc(const ArrayDim &dim_u) {} 44 | virtual void free() {} 45 | virtual bool is_valid() { return true; } 46 | virtual typename Base::image_manager_base_t* image_manager() { return &image_manager_; } 47 | virtual real get_sum(image_access_t a) { return cpu_sum_reduce(a); } 48 | virtual void timer_start() { timer.start(); } 49 | virtual void timer_end() { timer.end(); } 50 | virtual double timer_get() { return timer.get(); } 51 | virtual void synchronize() {} 52 | 53 | virtual void run_dual_p(image_access_t p, image_access_t u, linear_operator_t linear_operator, regularizer_t regularizer, real dt); 54 | virtual void run_prim_u(image_access_t u, image_access_t ubar, image_access_t p, linear_operator_t linear_operator, dataterm_t dataterm, real theta_bar, real dt); 55 | virtual void energy_base(image_access_t u, image_access_t aux_reduce, linear_operator_t linear_operator, dataterm_t dataterm, regularizer_t regularizer); 56 | virtual void add_edges(image_access_t cur_result, linear_operator_t linear_operator, regularizer_t regularizer); 57 | virtual void set_regularizer_weight_from__normgrad(image_access_t regularizer_weight, image_access_t image, linear_operator_t linear_operator); 58 | virtual void set_regularizer_weight_from__exp(image_access_t regularizer_weight, real coeff); 59 | virtual void diff_l1_base(image_access_t a, image_access_t b, image_access_t aux_reduce); 60 | 61 | image_manager_t image_manager_; 62 | Timer timer; 63 | }; 64 | 65 | 66 | template 67 | std::string HostEngine::str() 68 | { 69 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 70 | return "cpu with openmp"; 71 | #else 72 | return "cpu"; 73 | #endif 74 | } 75 | 76 | 77 | template 78 | void HostEngine::run_dual_p(image_access_t p, image_access_t u, linear_operator_t linear_operator, regularizer_t regularizer, real dt) 79 | { 80 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 81 | #pragma omp parallel default(none) firstprivate(p, u, linear_operator, regularizer, dt) 82 | { 83 | #endif 84 | const Dim2D &dim2d = u.dim().dim2d(); 85 | const int u_num_channels = u.dim().num_channels; 86 | const int p_num_channels = linear_operator.num_channels_range(u_num_channels); 87 | HeapArray p_sh(p_num_channels); 88 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 89 | #pragma omp for 90 | #endif 91 | for (int y = 0; y < dim2d.h; y++) 92 | { 93 | for (int x = 0; x < dim2d.w; x++) 94 | { 95 | linear_operator.apply(p_sh, u, x, y, dim2d, u_num_channels); 96 | 97 | for(int i = 0; i < p_num_channels; i++) 98 | { 99 | p_sh.get(i) = p.get(x, y, i) + p_sh.get(i) * dt; 100 | } 101 | 102 | regularizer.prox_star(p_sh, dt, x, y, dim2d, p_num_channels); 103 | 104 | for(int i = 0; i < p_num_channels; i++) 105 | { 106 | p.get(x, y, i) = p_sh.get(i); 107 | } 108 | } 109 | } 110 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 111 | } 112 | #endif 113 | } 114 | 115 | 116 | template 117 | void HostEngine::run_prim_u(image_access_t u, image_access_t ubar, image_access_t p, linear_operator_t linear_operator, dataterm_t dataterm, real theta_bar, real dt) 118 | { 119 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 120 | #pragma omp parallel default(none) firstprivate(u, ubar, p, linear_operator, dataterm, theta_bar, dt) 121 | { 122 | #endif 123 | const Dim2D &dim2d = u.dim().dim2d(); 124 | const int u_num_channels = u.dim().num_channels; 125 | HeapArray u_sh(u_num_channels); 126 | HeapArray valold_sh(u_num_channels); 127 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 128 | #pragma omp for 129 | #endif 130 | for (int y = 0; y < dim2d.h; y++) 131 | { 132 | for (int x = 0; x < dim2d.w; x++) 133 | { 134 | linear_operator.apply_transpose(u_sh, p, x, y, dim2d, u_num_channels); 135 | 136 | for(int i = 0; i < u_num_channels; i++) 137 | { 138 | real valold = u.get(x, y, i); 139 | u_sh.get(i) = valold - u_sh.get(i) * dt; 140 | valold_sh.get(i) = valold; 141 | } 142 | 143 | dataterm.prox(u_sh, dt, x, y, dim2d, u_num_channels); 144 | 145 | for(int i = 0; i < u_num_channels; i++) 146 | { 147 | real valnew = u_sh.get(i); 148 | u.get(x, y, i) = valnew; 149 | real valold = valold_sh.get(i); 150 | ubar.get(x, y, i) = valnew + (valnew - valold) * theta_bar; 151 | } 152 | } 153 | } 154 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 155 | } 156 | #endif 157 | } 158 | 159 | 160 | template 161 | void HostEngine::energy_base(image_access_t u, image_access_t aux_reduce, linear_operator_t linear_operator, dataterm_t dataterm, regularizer_t regularizer) 162 | { 163 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 164 | #pragma omp parallel default(none) firstprivate(u, aux_reduce, linear_operator, dataterm, regularizer) 165 | { 166 | #endif 167 | const Dim2D &dim2d = u.dim().dim2d(); 168 | const int u_num_channels = u.dim().num_channels; 169 | const int p_num_channels = linear_operator.num_channels_range(u_num_channels); 170 | HeapArray u_sh(u_num_channels); 171 | HeapArray p_sh(p_num_channels); 172 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 173 | #pragma omp for 174 | #endif 175 | for (int y = 0; y < dim2d.h; y++) 176 | { 177 | for (int x = 0; x < dim2d.w; x++) 178 | { 179 | real energy = real(0); 180 | linear_operator.apply(p_sh, u, x, y, dim2d, u_num_channels); 181 | energy += regularizer.value(p_sh, x, y, dim2d, p_num_channels); 182 | 183 | for(int i = 0; i < u_num_channels; i++) 184 | { 185 | u_sh.get(i) = u.get(x, y, i); 186 | } 187 | energy += dataterm.value(u_sh, x, y, dim2d, u_num_channels); 188 | 189 | aux_reduce.get(x, y, 0) = energy; 190 | } 191 | } 192 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 193 | } 194 | #endif 195 | } 196 | 197 | 198 | template 199 | void HostEngine::add_edges(image_access_t image, linear_operator_t linear_operator, regularizer_t regularizer) 200 | { 201 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 202 | #pragma omp parallel default(none) firstprivate(image, linear_operator, regularizer) 203 | { 204 | #endif 205 | const Dim2D &dim2d = image.dim().dim2d(); 206 | const int u_num_channels = image.dim().num_channels; 207 | const int p_num_channels = linear_operator.num_channels_range(u_num_channels); 208 | HeapArray p_sh(p_num_channels); 209 | const real max_range_norm = linear_operator.maximal_possible_range_norm(u_num_channels); 210 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 211 | #pragma omp for 212 | #endif 213 | for (int y = 0; y < dim2d.h; y++) 214 | { 215 | for (int x = 0; x < dim2d.w; x++) 216 | { 217 | linear_operator.apply(p_sh, image, x, y, dim2d, u_num_channels); 218 | real val_edge_indicator = regularizer.edge_indicator(p_sh, max_range_norm, x, y, dim2d, p_num_channels); 219 | real mult = real(1) - val_edge_indicator; 220 | for (int i = 0; i < u_num_channels; i++) 221 | { 222 | image.get(x, y, i) *= mult; 223 | } 224 | } 225 | } 226 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 227 | } 228 | #endif 229 | } 230 | 231 | 232 | template 233 | void HostEngine::set_regularizer_weight_from__normgrad(image_access_t regularizer_weight, image_access_t image, linear_operator_t linear_operator) 234 | { 235 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 236 | #pragma omp parallel default(none) firstprivate(regularizer_weight, image, linear_operator) 237 | { 238 | #endif 239 | const Dim2D &dim2d = image.dim().dim2d(); 240 | const int u_num_channels = image.dim().num_channels; 241 | const int p_num_channels = linear_operator.num_channels_range(u_num_channels); 242 | HeapArray gradient_sh(p_num_channels); 243 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 244 | #pragma omp for 245 | #endif 246 | for (int y = 0; y < dim2d.h; y++) 247 | { 248 | for (int x = 0; x < dim2d.w; x++) 249 | { 250 | linear_operator.apply(gradient_sh, image, x, y, dim2d, u_num_channels); 251 | real val = vec_norm(gradient_sh, p_num_channels); 252 | regularizer_weight.get(x, y, 0) = val; 253 | } 254 | } 255 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 256 | } 257 | #endif 258 | } 259 | 260 | 261 | template 262 | void HostEngine::set_regularizer_weight_from__exp(image_access_t regularizer_weight, real coeff) 263 | { 264 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 265 | #pragma omp parallel default(none) firstprivate(regularizer_weight, coeff) 266 | { 267 | #endif 268 | const Dim2D &dim2d = regularizer_weight.dim().dim2d(); 269 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 270 | #pragma omp for 271 | #endif 272 | for (int y = 0; y < dim2d.h; y++) 273 | { 274 | for (int x = 0; x < dim2d.w; x++) 275 | { 276 | static const real eps = real(1e-6); 277 | regularizer_weight.get(x, y, 0) = realmax(eps, realexp(-coeff * regularizer_weight.get(x, y, 0))); 278 | } 279 | } 280 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 281 | } 282 | #endif 283 | } 284 | 285 | 286 | template 287 | void HostEngine::diff_l1_base(image_access_t a, image_access_t b, image_access_t aux_reduce) 288 | { 289 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 290 | #pragma omp parallel firstprivate(a, b, aux_reduce) 291 | { 292 | #endif 293 | const Dim2D &dim2d = a.dim().dim2d(); 294 | int a_num_channels = a.dim().num_channels; 295 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 296 | #pragma omp for 297 | #endif 298 | for (int y = 0; y < dim2d.h; y++) 299 | { 300 | for (int x = 0; x < dim2d.w; x++) 301 | { 302 | real diff = real(0); 303 | for (int i = 0; i < a_num_channels; i++) 304 | { 305 | real val_a = a.get(x, y, i); 306 | real val_b = b.get(x, y, i); 307 | diff += realabs(val_a - val_b); 308 | } 309 | aux_reduce.get(x, y, 0) = diff; 310 | } 311 | } 312 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 313 | } 314 | #endif 315 | } 316 | 317 | 318 | 319 | 320 | template 321 | class SolverHostImplementation: public SolverBase 322 | { 323 | public: 324 | SolverHostImplementation() { SolverBase::set_engine(&engine); } 325 | private: 326 | HostEngine engine; 327 | }; 328 | 329 | 330 | template SolverHost::SolverHost() : implementation(NULL) { implementation = new SolverHostImplementation(); } 331 | template SolverHost::~SolverHost() { delete implementation; } 332 | template BaseImage* SolverHost::run(const BaseImage *image, const Par &par) { return implementation->run(image, par); } 333 | 334 | template class SolverHost; 335 | template class SolverHost; 336 | -------------------------------------------------------------------------------- /src/libfastms/solver/solver_host.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef SOLVER_HOST_H 21 | #define SOLVER_HOST_H 22 | 23 | #include "solver.h" 24 | 25 | 26 | template class SolverHostImplementation; 27 | 28 | template 29 | class SolverHost 30 | { 31 | public: 32 | typedef real real_t; 33 | 34 | SolverHost(); 35 | ~SolverHost(); 36 | 37 | BaseImage* run(const BaseImage *in_image, const Par &par); 38 | 39 | private: 40 | SolverHost(const SolverHost &other_solver); // disable 41 | SolverHost& operator= (const SolverHost &other_solver); // disable 42 | 43 | SolverHostImplementation *implementation; 44 | }; 45 | 46 | 47 | 48 | #endif // SOLVER_HOST_H 49 | -------------------------------------------------------------------------------- /src/libfastms/util/check_cuda.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "check_cuda.cuh" 21 | 22 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 23 | 24 | #include 25 | #include 26 | 27 | 28 | 29 | namespace 30 | { 31 | 32 | std::string prev_file = ""; 33 | int prev_line = 0; 34 | 35 | } // namespace 36 | 37 | 38 | 39 | void cuda_check(std::string file, int line) 40 | { 41 | cudaError_t e = cudaGetLastError(); 42 | if (e != cudaSuccess) 43 | { 44 | std::cerr << std::endl << file.c_str() << ", line " << line << ": " << cudaGetErrorString(e) << " (" << e << ")" << std::endl; 45 | if (prev_line>0) std::cerr << "Previous CUDA call:" << std::endl << prev_file.c_str() << ", line " << prev_line << std::endl; 46 | exit(1); 47 | } 48 | prev_file = file; 49 | prev_line = line; 50 | } 51 | 52 | 53 | 54 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 55 | -------------------------------------------------------------------------------- /src/libfastms/util/check_cuda.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_CUDA_CHECK_H 21 | #define UTIL_CUDA_CHECK_H 22 | 23 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 24 | 25 | #include 26 | 27 | 28 | 29 | #define CUDA_CHECK cuda_check(__FILE__, __LINE__) 30 | void cuda_check(std::string file, int line); 31 | 32 | 33 | 34 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 35 | 36 | #endif // UTIL_CUDA_CHECK_H 37 | -------------------------------------------------------------------------------- /src/libfastms/util/has_cuda.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #include "has_cuda.h" 21 | 22 | #ifndef DISABLE_CUDA 23 | #include 24 | #endif // not DISABLE_CUDA 25 | 26 | #include 27 | 28 | 29 | 30 | bool has_cuda(std::string *error_str) 31 | { 32 | #ifndef DISABLE_CUDA 33 | int num_dev = 0; 34 | cudaError_t e = cudaGetDeviceCount(&num_dev); 35 | if (e == cudaSuccess) 36 | { 37 | if (num_dev > 0) 38 | { 39 | if (error_str) { *error_str = ""; } 40 | return true; 41 | } 42 | else 43 | { 44 | if (error_str) { *error_str = "No CUDA capable devices detected"; } 45 | return false; 46 | } 47 | } 48 | else 49 | { 50 | if (error_str) 51 | { 52 | std::stringstream s; 53 | s << "cuda error code " << e << ": " << cudaGetErrorString(e); 54 | *error_str = s.str(); 55 | } 56 | return false; 57 | } 58 | #else 59 | if (error_str) { *error_str = "CUDA was disabled during compilation"; } 60 | return false; 61 | #endif // not DISABLE_CUDA 62 | } 63 | -------------------------------------------------------------------------------- /src/libfastms/util/has_cuda.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_HAS_CUDA_H 21 | #define UTIL_HAS_CUDA_H 22 | 23 | #include 24 | 25 | 26 | 27 | bool has_cuda(std::string *error_str = NULL); 28 | 29 | 30 | 31 | #endif // UTIL_CUDA_CHECK_H 32 | -------------------------------------------------------------------------------- /src/libfastms/util/image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_IMAGE_H 21 | #define UTIL_IMAGE_H 22 | 23 | #include "image_access.h" 24 | #include "image_access_convert.h" 25 | #include 26 | 27 | #ifndef DISABLE_CUDA 28 | #include 29 | #endif // not DISABLE_CUDA 30 | 31 | 32 | 33 | 34 | // Base class for input images. 35 | // Each input image should know for itself how to convert its data from/to the solver image classes. 36 | class BaseImage 37 | { 38 | public: 39 | virtual ~BaseImage() {} 40 | virtual BaseImage* new_of_same_type_and_size() const = 0; 41 | virtual ArrayDim dim() const = 0; 42 | virtual void copy_from_layered(const ImageUntypedAccess &in) = 0; 43 | virtual void copy_to_layered(ImageUntypedAccess out) const = 0; 44 | }; 45 | 46 | 47 | template 48 | class ImageManagerBase 49 | { 50 | public: 51 | virtual ~ImageManagerBase() {} 52 | virtual void copy_from_samekind(ImageAccess out, ImageAccess in) = 0; 53 | virtual void setzero(ImageAccess image) = 0; 54 | virtual size_t alloc(ImageAccess &image, const ArrayDim &dim) = 0; 55 | virtual void free(ImageAccess &image) = 0; 56 | }; 57 | 58 | template 59 | class ImageManager: public ImageManagerBase 60 | { 61 | public: 62 | typedef Allocator allocator_t; 63 | 64 | virtual ~ImageManager() {} 65 | 66 | virtual void copy_from_samekind(ImageAccess out, ImageAccess in) 67 | { 68 | allocator_t::copy2d(out.data(), out.data_pitch(), in.const_data(), in.data_pitch(), in.data_width_in_bytes(), in.data_height()); 69 | } 70 | 71 | virtual void setzero(ImageAccess image) 72 | { 73 | if (image.is_valid()) 74 | { 75 | allocator_t::setzero(image.data(), image.num_bytes()); 76 | } 77 | } 78 | 79 | virtual size_t alloc(ImageAccess &image, const ArrayDim &dim) 80 | { 81 | typedef ImageAccess image_access_t; 82 | bool do_allocation = (!image.is_valid() || image.dim() != dim); 83 | size_t mem = 0; 84 | if (do_allocation) 85 | { 86 | if (image.is_valid()) { allocator_t::free(image.data()); } 87 | DataDim data_dim = image_access_t::data_interpretation_t::used_data_dim(dim, sizeof(T)); 88 | void *data = allocator_t::alloc2d(&data_dim); 89 | image = image_access_t(ImageData(data, dim, data_dim.pitch), is_on_host()); 90 | allocator_t::setzero(image.data(), image.num_bytes()); 91 | mem = image.num_bytes(); 92 | } 93 | return mem; 94 | } 95 | 96 | virtual void free(ImageAccess &image) 97 | { 98 | if (image.is_valid()) { allocator_t::free(image.data()); } 99 | } 100 | 101 | private: 102 | bool is_on_host() { return types_equal::value; } 103 | }; 104 | 105 | 106 | // Image with deep-copy semantics 107 | template 108 | class ManagedImage: public BaseImage 109 | { 110 | public: 111 | typedef T elem_t; 112 | typedef DataInterpretation data_interpretation_t; 113 | typedef Allocator allocator_t; 114 | typedef ManagedImage Self; 115 | typedef ImageAccess image_access_t; 116 | typedef ImageManager image_manager_t; 117 | 118 | ManagedImage() : is_owner(true) {} 119 | ManagedImage(const ArrayDim &dim) : is_owner(true) { alloc(dim); } 120 | ManagedImage(elem_t *data, const ArrayDim &dim) : array(data, dim, is_on_host()), is_owner(false) {} 121 | ManagedImage(elem_t *data, const ArrayDim &dim, size_t pitch) : array(data, dim, pitch, ElemType2Kind::value, is_on_host()), is_owner(false) {} 122 | ManagedImage(const Self& other) : is_owner(true) 123 | { 124 | // copy 125 | if (!other.array.is_valid()) { return; } 126 | alloc(other.dim()); 127 | copy_from_samekind(&other); 128 | } 129 | virtual ~ManagedImage() { if (is_owner) { free(); } }; 130 | Self& operator= (const Self &other) 131 | { 132 | if (&other != this) 133 | { 134 | if (!is_owner) 135 | { 136 | is_owner = true; 137 | array = image_access_t(); 138 | } 139 | alloc(other.dim()); 140 | copy_from_samekind(&other); 141 | } 142 | return *this; 143 | } 144 | void copy_from_samekind(const Self *other) { image_manager.copy_from_samekind(this->array, other->array); } 145 | 146 | elem_t* release_data() { is_owner = false; return (elem_t*)array.data(); } 147 | size_t alloc(const ArrayDim &dim) 148 | { 149 | if (!is_owner) { std::cerr << "ERROR: ManagedImage::alloc(): Currently using external image data, calling alloc() not allowed" << std::endl; return 0; } 150 | return image_manager.alloc(array, dim); 151 | } 152 | void free() 153 | { 154 | if (!is_owner) { std::cerr << "ERROR: ManagedImage::free(): Currently using external image data, calling free() not allowed" << std::endl; return; } 155 | image_manager.free(array); 156 | } 157 | void setzero() 158 | { 159 | image_manager.setzero(array); 160 | } 161 | 162 | typename image_access_t::image_untyped_access_t get_untyped_access() { return array.get_untyped_access(); } 163 | image_access_t& get_access() { return array; } 164 | const image_access_t& get_access() const { return array; } 165 | virtual BaseImage* new_of_same_type_and_size() const { return new Self(dim()); } 166 | virtual ArrayDim dim() const { return array.dim(); } 167 | virtual void copy_from_layered(const ImageUntypedAccess &in) { copy_image(this->array.get_untyped_access(), in); } 168 | virtual void copy_to_layered(ImageUntypedAccess out) const { copy_image(out, this->array.get_untyped_access()); } 169 | 170 | private: 171 | static bool is_on_host() { return types_equal::value; } 172 | 173 | image_manager_t image_manager; 174 | image_access_t array; 175 | bool is_owner; 176 | }; 177 | 178 | 179 | 180 | #endif // UTIL_IMAGE_H 181 | -------------------------------------------------------------------------------- /src/libfastms/util/image_access.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_IMAGE_ACCESS_H 21 | #define UTIL_IMAGE_ACCESS_H 22 | 23 | #include // for memset, memcpy 24 | #include "real.h" 25 | #include "types_equal.h" 26 | #include 27 | 28 | #ifndef DISABLE_CUDA 29 | #include 30 | #endif // not DISABLE_CUDA 31 | 32 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 33 | #define HOST_DEVICE __host__ __device__ 34 | #define FORCEINLINE __forceinline__ 35 | #else 36 | #define HOST_DEVICE 37 | #define FORCEINLINE inline 38 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 39 | 40 | 41 | 42 | struct DataIndex 43 | { 44 | HOST_DEVICE DataIndex() : x(0), y(0) {} 45 | HOST_DEVICE DataIndex(size_t x, size_t y) : x(x), y(y) {} 46 | size_t x; 47 | size_t y; 48 | }; 49 | 50 | 51 | struct DataDim 52 | { 53 | HOST_DEVICE DataDim() : pitch(0), height(0) {} 54 | HOST_DEVICE DataDim(size_t pitch, size_t height) : pitch(pitch), height(height) {} 55 | HOST_DEVICE size_t num_bytes() const { return pitch * height; } 56 | size_t pitch; 57 | size_t height; 58 | }; 59 | 60 | 61 | struct Dim2D 62 | { 63 | HOST_DEVICE Dim2D() : w(0), h(0) {} 64 | HOST_DEVICE Dim2D(int w, int h) : w(w), h(h) {} 65 | HOST_DEVICE size_t num_elem() const { return (size_t)w * h; } 66 | HOST_DEVICE bool operator== (const Dim2D &other_dim) { return w == other_dim.w && h == other_dim.h; } 67 | HOST_DEVICE bool operator!= (const Dim2D &other_dim) { return !(operator==(other_dim)); } 68 | 69 | int w; 70 | int h; 71 | }; 72 | 73 | 74 | struct ArrayDim 75 | { 76 | HOST_DEVICE ArrayDim() : w(0), h(0), num_channels(0) {} 77 | HOST_DEVICE ArrayDim(int w, int h, int num_channels) : w(w), h(h), num_channels(num_channels) {} 78 | HOST_DEVICE Dim2D dim2d() const { return Dim2D(w, h); } 79 | HOST_DEVICE size_t num_elem() const { return (size_t)w * h * num_channels; } 80 | HOST_DEVICE bool operator== (const ArrayDim &other_dim) { return w == other_dim.w && h == other_dim.h && num_channels == other_dim.num_channels; } 81 | HOST_DEVICE bool operator!= (const ArrayDim &other_dim) { return !(operator==(other_dim)); } 82 | 83 | int w; 84 | int h; 85 | int num_channels; 86 | }; 87 | inline std::ostream& operator<< (std::ostream &out, const ArrayDim &dim) 88 | { 89 | out << dim.w << " x " << dim.h << " x " << dim.num_channels; 90 | return out; 91 | } 92 | 93 | 94 | class HostAllocator 95 | { 96 | public: 97 | static void free(void *&ptr) { delete[] (char*)ptr; ptr = NULL; } 98 | static void setzero(void *ptr, size_t num_bytes) { memset(ptr, 0, num_bytes); } 99 | static void* alloc2d(DataDim *used_data_dim) 100 | { 101 | return (void*)(new char[used_data_dim->num_bytes()]); 102 | } 103 | static void copy2d(void *out, size_t out_pitch, const void *in, size_t in_pitch, size_t w_bytes, size_t h_lines) 104 | { 105 | if (out_pitch == in_pitch) 106 | { 107 | size_t num_bytes = in_pitch * h_lines; 108 | memcpy(out, in, num_bytes); 109 | } 110 | else 111 | { 112 | for (size_t y = 0; y < h_lines; y++) 113 | { 114 | void *out_y = (void*)((char*)out + out_pitch * y); 115 | const void *in_y = (const void*)((const char*)in + in_pitch * y); 116 | memcpy(out_y, in_y, w_bytes); 117 | } 118 | } 119 | } 120 | }; 121 | 122 | 123 | #ifndef DISABLE_CUDA 124 | class DeviceAllocator 125 | { 126 | public: 127 | static void free(void *&ptr_cuda) { cudaFree(ptr_cuda); ptr_cuda = NULL; } 128 | static void setzero(void *ptr_cuda, size_t num_bytes) 129 | { 130 | cudaMemset(ptr_cuda, 0, num_bytes); 131 | } 132 | static void* alloc2d(DataDim *used_data_dim) 133 | { 134 | void *ptr_cuda = NULL; 135 | size_t pitch0 = 0; 136 | cudaMallocPitch(&ptr_cuda, &pitch0, used_data_dim->pitch, used_data_dim->height); 137 | used_data_dim->pitch = pitch0; 138 | return ptr_cuda; 139 | } 140 | static void copy2d(void *out_cuda, size_t out_pitch, const void *in_cuda, size_t in_pitch, size_t w_bytes, size_t h_lines) 141 | { 142 | cudaMemcpy2D(out_cuda, out_pitch, in_cuda, in_pitch, w_bytes, h_lines, cudaMemcpyDeviceToDevice); 143 | } 144 | static void copy2d_h2d(void *out_cuda, size_t out_pitch, const void *in_host, size_t in_pitch, size_t w_bytes, size_t h_lines) 145 | { 146 | cudaMemcpy2D(out_cuda, out_pitch, in_host, in_pitch, w_bytes, h_lines, cudaMemcpyHostToDevice); 147 | } 148 | static void copy2d_d2h(void *out_host, size_t out_pitch, const void *in_cuda, size_t in_pitch, size_t w_bytes, size_t h_lines) 149 | { 150 | cudaMemcpy2D(out_host, out_pitch, in_cuda, in_pitch, w_bytes, h_lines, cudaMemcpyDeviceToHost); 151 | } 152 | }; 153 | #endif // not DISABLE_CUDA 154 | 155 | 156 | struct ImageData 157 | { 158 | HOST_DEVICE ImageData() : data_(NULL), data_pitch_(0) {} 159 | HOST_DEVICE ImageData(void *data, const ArrayDim &dim, size_t data_pitch) : data_(data), dim_(dim), data_pitch_(data_pitch) {} 160 | void *data_; 161 | ArrayDim dim_; 162 | size_t data_pitch_; 163 | }; 164 | 165 | 166 | template 167 | TUntypedAccess alloc_untyped_access(const ArrayDim &dim, ElemKind elem_kind, bool on_host) 168 | { 169 | DataDim data_dim = TUntypedAccess::data_interpretation_t::used_data_dim(dim, ElemKindGeneral::size(elem_kind)); 170 | #ifndef DISABLE_CUDA 171 | void *data = (on_host? HostAllocator::alloc2d(&data_dim) : DeviceAllocator::alloc2d(&data_dim)); 172 | #else 173 | void *data = HostAllocator::alloc2d(&data_dim); 174 | #endif // not DISABLE_CUDA 175 | return TUntypedAccess(ImageData(data, dim, data_dim.pitch), elem_kind, on_host); 176 | } 177 | 178 | 179 | template struct ImageUntypedAccess; 180 | 181 | template 182 | struct ImageAccess 183 | { 184 | typedef T elem_t; 185 | typedef DataInterpretation data_interpretation_t; 186 | typedef ImageUntypedAccess image_untyped_access_t; 187 | 188 | HOST_DEVICE ImageAccess() : is_on_host_(true) {} 189 | HOST_DEVICE ImageAccess(void *data, const ArrayDim &dim, bool is_on_host) : 190 | image_data_(data, dim, data_interpretation_t::used_data_dim(dim, sizeof(T)).pitch), is_on_host_(is_on_host) {} 191 | HOST_DEVICE ImageAccess(const ImageData &image_data, bool is_on_host) : 192 | image_data_(image_data), is_on_host_(is_on_host) {} 193 | 194 | HOST_DEVICE image_untyped_access_t get_untyped_access() const { return image_untyped_access_t(image_data_, ElemType2Kind::value, is_on_host_); } 195 | 196 | HOST_DEVICE T& get(int x, int y, int i) { return *(T*)((char*)image_data_.data_ + offset(x, y, i)); } 197 | HOST_DEVICE const T& get(int x, int y, int i) const { return *(T*)((char*)image_data_.data_ + offset(x, y, i)); } 198 | HOST_DEVICE ArrayDim dim() const { return image_data_.dim_; } 199 | HOST_DEVICE bool is_valid() const { return image_data_.data_ != NULL; } 200 | HOST_DEVICE bool is_on_host() const { return is_on_host_; } 201 | 202 | HOST_DEVICE void*& data() { return image_data_.data_; } 203 | HOST_DEVICE const void* const_data() const { return image_data_.data_; } 204 | HOST_DEVICE size_t data_pitch() const { return image_data_.data_pitch_; } 205 | HOST_DEVICE size_t data_height() const { return used_data_dim().height; } 206 | HOST_DEVICE size_t data_width_in_bytes() const { return used_data_dim().pitch; } 207 | HOST_DEVICE size_t num_bytes() const { return data_pitch() * data_height(); } 208 | 209 | private: 210 | HOST_DEVICE size_t offset(int x, int y, int i) const 211 | { 212 | const DataIndex &data_index = data_interpretation_t::get(x, y, i, image_data_.dim_); 213 | return data_index.x * sizeof(T) + image_data_.data_pitch_ * data_index.y; 214 | } 215 | HOST_DEVICE DataDim used_data_dim() const { return data_interpretation_t::used_data_dim(image_data_.dim_, sizeof(T)); } 216 | 217 | ImageData image_data_; 218 | bool is_on_host_; 219 | }; 220 | 221 | 222 | template 223 | struct ImageUntypedAccess 224 | { 225 | typedef DataInterpretation data_interpretation_t; 226 | template struct image_access_t { typedef ImageAccess type; }; 227 | 228 | HOST_DEVICE ImageUntypedAccess() : elem_kind_(elem_kind_uchar), is_on_host_(true) {} 229 | HOST_DEVICE ImageUntypedAccess(void *data, const ArrayDim &dim, ElemKind elem_kind, bool is_on_host) : 230 | image_data_(data, dim, data_interpretation_t::used_data_dim(dim, ElemKindGeneral::size(elem_kind)).pitch), 231 | elem_kind_(elem_kind), is_on_host_(is_on_host) {} 232 | HOST_DEVICE ImageUntypedAccess(const ImageData &image_data, ElemKind elem_kind, bool is_on_host) : 233 | image_data_(image_data), 234 | elem_kind_(elem_kind), is_on_host_(is_on_host) {} 235 | 236 | template HOST_DEVICE typename image_access_t::type get_access() const { return typename image_access_t::type(image_data_, is_on_host_); } 237 | HOST_DEVICE ElemKind elem_kind() const { return elem_kind_; } 238 | 239 | HOST_DEVICE void* get_address(int x, int y, int i) { return (void*)((char*)image_data_.data_ + offset_address(x, y, i)); } 240 | HOST_DEVICE const void* get_address(int x, int y, int i) const { return (const void*)((const char*)image_data_.data_ + offset_address(x, y, i)); } 241 | HOST_DEVICE ArrayDim dim() const { return image_data_.dim_; } 242 | HOST_DEVICE bool is_valid() const { return image_data_.data_ != NULL; } 243 | HOST_DEVICE bool is_on_host() const { return is_on_host_; } 244 | 245 | HOST_DEVICE void*& data() { return image_data_.data_; } 246 | HOST_DEVICE const void* const_data() const { return image_data_.data_; } 247 | HOST_DEVICE size_t data_pitch() const { return image_data_.data_pitch_; } 248 | HOST_DEVICE size_t data_height() const { return used_data_dim().height; } 249 | HOST_DEVICE size_t data_width_in_bytes() const { return used_data_dim().pitch; } 250 | HOST_DEVICE size_t num_bytes() const { return data_pitch() * data_height(); } 251 | 252 | private: 253 | HOST_DEVICE size_t offset_address(int x, int y, int i) const 254 | { 255 | const DataIndex &data_index = data_interpretation_t::get(x, y, i, image_data_.dim_); 256 | return data_index.x * elem_size() + image_data_.data_pitch_ * data_index.y; 257 | } 258 | HOST_DEVICE DataDim used_data_dim() const { return data_interpretation_t::used_data_dim(image_data_.dim_, elem_size()); } 259 | HOST_DEVICE size_t elem_size() const { return ElemKindGeneral::size(elem_kind_); } 260 | 261 | ImageData image_data_; 262 | ElemKind elem_kind_; 263 | bool is_on_host_; 264 | }; 265 | 266 | 267 | struct DataInterpretationLayered 268 | { 269 | HOST_DEVICE static DataIndex get(int x, int y, int i, const ArrayDim &dim) 270 | { 271 | return DataIndex(x, y + (size_t)dim.h * i); 272 | } 273 | HOST_DEVICE static DataDim used_data_dim (const ArrayDim &dim, size_t elem_size) 274 | { 275 | return DataDim(dim.w * elem_size, (size_t)dim.h * dim.num_channels); 276 | } 277 | }; 278 | 279 | 280 | struct DataInterpretationLayeredTransposed 281 | { 282 | HOST_DEVICE static DataIndex get(int x, int y, int i, const ArrayDim &dim) 283 | { 284 | return DataIndex(y, x + (size_t)dim.w * i); 285 | } 286 | 287 | HOST_DEVICE static DataDim used_data_dim (const ArrayDim &dim, size_t elem_size) 288 | { 289 | return DataDim(dim.h * elem_size, (size_t)dim.w * dim.num_channels); 290 | } 291 | }; 292 | 293 | 294 | struct DataInterpretationInterlaced 295 | { 296 | HOST_DEVICE static DataIndex get(int x, int y, int i, const ArrayDim &dim) 297 | { 298 | return DataIndex(i + (size_t)dim.num_channels * x, y); 299 | } 300 | HOST_DEVICE static DataDim used_data_dim (const ArrayDim &dim, size_t elem_size) 301 | { 302 | return DataDim((size_t)dim.num_channels * dim.w * elem_size, dim.h); 303 | } 304 | }; 305 | 306 | 307 | struct DataInterpretationInterlacedReversed 308 | { 309 | HOST_DEVICE static DataIndex get(int x, int y, int i, const ArrayDim &dim) 310 | { 311 | return DataIndex((dim.num_channels - 1 - i) + (size_t)dim.num_channels * x, y); 312 | } 313 | HOST_DEVICE static DataDim used_data_dim (const ArrayDim &dim, size_t elem_size) 314 | { 315 | return DataDim((size_t)dim.num_channels * dim.w * elem_size, dim.h); 316 | } 317 | }; 318 | 319 | 320 | 321 | #undef HOST_DEVICE 322 | #undef FORCEINLINE 323 | 324 | #endif // UTIL_IMAGE_ACCESS_H 325 | -------------------------------------------------------------------------------- /src/libfastms/util/image_access_convert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_IMAGE_ACCESS_CONVERT_H 21 | #define UTIL_IMAGE_ACCESS_CONVERT_H 22 | 23 | #include "image_access.h" 24 | 25 | 26 | template 27 | void copy_image_h2h_base(TUntypedAccessOut out, TUntypedAccessIn in) 28 | { 29 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 30 | #pragma omp parallel default(none) firstprivate(out, in) 31 | { 32 | #endif 33 | const ElemKind out_kind = out.elem_kind(); 34 | const ElemKind in_kind = in.elem_kind(); 35 | const Dim2D &dim2d = in.dim().dim2d(); 36 | const int num_channels = in.dim().num_channels; 37 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 38 | #pragma omp for 39 | #endif 40 | for (int y = 0; y < dim2d.h; y++) 41 | { 42 | for (int i = 0; i < num_channels; i++) 43 | { 44 | for (int x = 0; x < dim2d.w; x++) 45 | { 46 | convert_type(out_kind, in_kind, out.get_address(x, y, i), in.get_address(x, y, i)); 47 | } 48 | } 49 | } 50 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 51 | } 52 | #endif 53 | } 54 | 55 | 56 | template 57 | void copy_image_h2h(TUntypedAccessOut out, TUntypedAccessIn in) 58 | { 59 | if (out.elem_kind() == in.elem_kind() && 60 | types_equal::value) 61 | { 62 | HostAllocator::copy2d(out.data(), out.data_pitch(), in.const_data(), in.data_pitch(), in.data_width_in_bytes(), in.data_height()); 63 | } 64 | else 65 | { 66 | copy_image_h2h_base(out, in); 67 | } 68 | } 69 | 70 | 71 | #ifndef DISABLE_CUDA 72 | template 73 | void copy_image_d2d_base(TUntypedAccessOut out, TUntypedAccessIn in); 74 | 75 | 76 | template 77 | void copy_image_d2d(TUntypedAccessOut out, TUntypedAccessIn in) 78 | { 79 | if (out.elem_kind() == in.elem_kind() && 80 | types_equal::value) 81 | { 82 | DeviceAllocator::copy2d(out.data(), out.data_pitch(), in.data(), in.data_pitch(), in.data_width_in_bytes(), in.data_height()); 83 | } 84 | else 85 | { 86 | copy_image_d2d_base(out, in); 87 | } 88 | } 89 | 90 | 91 | template 92 | void copy_image_h2d(TUntypedAccessOut out, TUntypedAccessIn in) 93 | { 94 | if (out.elem_kind() == in.elem_kind() && 95 | types_equal::value) 96 | { 97 | DeviceAllocator::copy2d_h2d(out.data(), out.data_pitch(), in.data(), in.data_pitch(), in.data_width_in_bytes(), in.data_height()); 98 | } 99 | else 100 | { 101 | TUntypedAccessIn in_device = alloc_untyped_access(in.dim(), in.elem_kind(), false); // false: not on_host = on_device 102 | DeviceAllocator::copy2d_h2d(in_device.data(), in_device.data_pitch(), in.data(), in.data_pitch(), in.data_width_in_bytes(), in.data_height()); 103 | copy_image_d2d(out, in_device); 104 | DeviceAllocator::free(in_device.data()); 105 | } 106 | } 107 | 108 | 109 | template 110 | void copy_image_d2h(TUntypedAccessOut out, TUntypedAccessIn in) 111 | { 112 | if (out.elem_kind() == in.elem_kind() && 113 | types_equal::value) 114 | { 115 | DeviceAllocator::copy2d_d2h(out.data(), out.data_pitch(), in.data(), in.data_pitch(), in.data_width_in_bytes(), in.data_height()); 116 | } 117 | else 118 | { 119 | TUntypedAccessOut out_device = alloc_untyped_access(out.dim(), out.elem_kind(), false); // false: not on_host = on_device 120 | copy_image_d2d(out_device, in); 121 | DeviceAllocator::copy2d_d2h(out.data(), out.data_pitch(), out_device.data(), out_device.data_pitch(), out.data_width_in_bytes(), out.data_height()); 122 | DeviceAllocator::free(out_device.data()); 123 | } 124 | } 125 | #endif // not DISABLE_CUDA 126 | 127 | #include 128 | template 129 | void copy_image(TUntypedAccessOut out, TUntypedAccessIn in) 130 | { 131 | #ifndef DISABLE_CUDA 132 | if (in.is_on_host() && out.is_on_host()) 133 | { 134 | copy_image_h2h(out, in); 135 | } 136 | else if (!in.is_on_host() && out.is_on_host()) 137 | { 138 | copy_image_d2h(out, in); 139 | } 140 | else if (in.is_on_host() && !out.is_on_host()) 141 | { 142 | copy_image_h2d(out, in); 143 | } 144 | else 145 | { 146 | copy_image_d2d(out, in); 147 | } 148 | #else 149 | copy_image_h2h(out, in); 150 | #endif // not DISABLE_CUDA 151 | } 152 | 153 | 154 | #undef HOST_DEVICE 155 | #undef FORCEINLINE 156 | 157 | #endif // UTIL_IMAGE_ACCESS_CONVERT_H 158 | -------------------------------------------------------------------------------- /src/libfastms/util/image_access_convert_cuda.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 21 | 22 | #include "image_access_convert.h" 23 | #include "vars_cuda.cuh" 24 | #include "check_cuda.cuh" 25 | 26 | 27 | 28 | template 29 | __global__ void copy_image_d2d_base_kernel (TUntypedAccessOut out, TUntypedAccessIn in) 30 | { 31 | const ElemKind out_kind = out.elem_kind(); 32 | const ElemKind in_kind = in.elem_kind(); 33 | const Dim2D &dim2d = in.dim().dim2d(); 34 | const int num_channels = in.dim().num_channels; 35 | int x = cuda_x(); 36 | int y = cuda_y(); 37 | if (is_active(x, y, dim2d)) 38 | { 39 | for (int i = 0; i < num_channels; i++) 40 | { 41 | convert_type(out_kind, in_kind, out.get_address(x, y, i), in.get_address(x, y, i)); 42 | } 43 | } 44 | } 45 | 46 | 47 | template 48 | void copy_image_d2d_base(TUntypedAccessOut out, TUntypedAccessIn in) 49 | { 50 | const Dim2D &dim2d = in.dim().dim2d(); 51 | dim3 block = cuda_block_size(dim2d.w, dim2d.h); 52 | dim3 grid = cuda_grid_size(block, dim2d.w, dim2d.h); 53 | copy_image_d2d_base_kernel <<>> (out, in); CUDA_CHECK; 54 | } 55 | 56 | 57 | #define COPY_Iout_Iin(Iout, Iin) template void copy_image_d2d_base, ImageUntypedAccess >(ImageUntypedAccess, ImageUntypedAccess); 58 | COPY_Iout_Iin(DataInterpretationLayered, DataInterpretationLayered) 59 | 60 | COPY_Iout_Iin(DataInterpretationLayeredTransposed, DataInterpretationLayered) 61 | COPY_Iout_Iin(DataInterpretationLayered, DataInterpretationLayeredTransposed) 62 | 63 | COPY_Iout_Iin(DataInterpretationInterlaced, DataInterpretationLayered) 64 | COPY_Iout_Iin(DataInterpretationLayered, DataInterpretationInterlaced) 65 | 66 | COPY_Iout_Iin(DataInterpretationInterlacedReversed, DataInterpretationLayered) 67 | COPY_Iout_Iin(DataInterpretationLayered, DataInterpretationInterlacedReversed) 68 | #undef COPY_Iout_Iin 69 | 70 | 71 | 72 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 73 | -------------------------------------------------------------------------------- /src/libfastms/util/image_mat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef DISABLE_OPENCV 21 | 22 | #include "image_mat.h" 23 | #include 24 | 25 | 26 | 27 | void show_image(std::string title, const cv::Mat &mat, int x_window, int y_window) 28 | { 29 | if (mat.cols == 0 || mat.rows == 0 || mat.data == NULL) 30 | { 31 | std::cerr << "ERROR: show_image(): empty input cv::Mat" << std::endl; 32 | return; 33 | } 34 | const char *wTitle = title.c_str(); 35 | cv::namedWindow(wTitle, CV_WINDOW_NORMAL); 36 | cvMoveWindow(wTitle, x_window, y_window); 37 | cv::imshow(wTitle, mat); 38 | } 39 | 40 | 41 | cv::Mat image1d_to_graph(const cv::Mat &mat, int graph_height, int channel_id, double thresh_jump) 42 | { 43 | if (mat.cols == 0 || mat.rows == 0 || mat.data == NULL) 44 | { 45 | std::cerr << "ERROR: image1d_to_graph: empty input cv::Mat" << std::endl; 46 | return cv::Mat(); 47 | } 48 | typedef float real; 49 | typedef ManagedImage managed_image_t; 50 | typedef managed_image_t::image_access_t image_access_t; 51 | managed_image_t image(MatImage(mat).dim()); 52 | MatImage(mat).copy_to_layered(image.get_untyped_access()); 53 | image_access_t &image_access = image.get_access(); 54 | 55 | int w = image.dim().w; 56 | int num_channels = image.dim().num_channels; 57 | managed_image_t image_graph(ArrayDim(w, graph_height, 3)); 58 | image_access_t &image_graph_access = image_graph.get_access(); 59 | 60 | real val_white = real(1); 61 | real val_grey = real(0.15); 62 | 63 | for (int x = 0; x < w; x++) 64 | { 65 | real g_abs = real(0); 66 | for (int i = 0; i < num_channels; i++) 67 | { 68 | real diff = (x + 1 < w? image_access.get(x + 1, 0, i) - image_access.get(x, 0, i) : real(0)); 69 | g_abs += diff * diff; 70 | } 71 | g_abs = std::sqrt(g_abs); 72 | bool is_jump = (real(thresh_jump) > real(0) && g_abs > real(thresh_jump)); 73 | 74 | for (int i = 0; i < std::min(num_channels, 3); i++) 75 | { 76 | real val_cur = image_access.get(x, 0, i); 77 | real val_next = (x + 1 < w? image_access.get(x + 1, 0, i) : val_cur); 78 | int y_cur = graph_height - 1 - std::max(0, std::min(graph_height - 1, (int)std::floor(val_cur * real(graph_height)))); 79 | int y_next = graph_height - 1 - std::max(0, std::min(graph_height - 1, (int)std::floor(val_next * real(graph_height)))); 80 | int y0 = std::min(y_cur, y_next); 81 | int y1 = std::max(y_cur, y_next); 82 | for (int y = y0; y <= y1; y++) 83 | { 84 | real val = val_white; 85 | if (is_jump && y0 < y && y < y1) { val = val_grey; } 86 | image_graph_access.get(x, y, i) = val; 87 | } 88 | } 89 | } 90 | 91 | if (channel_id >= 0) 92 | { 93 | for (int x = 0; x < image_graph_access.dim().w; x++) 94 | { 95 | for (int y = 0; y < image_graph_access.dim().h; y++) 96 | { 97 | real val = image_graph_access.get(x, y, channel_id); 98 | val = real(1) - val; 99 | for (int i = 0; i < image_graph_access.dim().num_channels; i++) 100 | { 101 | image_graph_access.get(x, y, i) = val; 102 | } 103 | } 104 | } 105 | } 106 | 107 | MatImage matimage_result(image_graph.dim(), CV_8UC3); 108 | matimage_result.copy_from_layered(image_graph_access.get_untyped_access()); 109 | return matimage_result.get_mat(); 110 | } 111 | 112 | 113 | cv::Mat extract_row(const cv::Mat in_mat, int row) 114 | { 115 | // row image will have the same number of channels as the input image 116 | int w = in_mat.cols; 117 | int h = in_mat.rows; 118 | if (row < 0 || row >= h) 119 | { 120 | int row_new = std::max(0, std::min(h - 1, row)); 121 | std::cerr << "WARNING: extract_row: " << row << " is not a valid row (0 .. " << h - 1 << "), using row = " << row_new << std::endl; 122 | row = row_new; 123 | } 124 | cv::Mat mat_row(1, w, in_mat.type(), cv::Scalar::all(0)); 125 | memcpy(mat_row.data, in_mat.ptr(row), (size_t)w * in_mat.elemSize()); 126 | return mat_row; 127 | } 128 | 129 | 130 | #endif // not DISABLE_OPENCV 131 | -------------------------------------------------------------------------------- /src/libfastms/util/image_mat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_IMAGE_MAT_H 21 | #define UTIL_IMAGE_MAT_H 22 | 23 | #ifndef DISABLE_OPENCV 24 | 25 | #include "image.h" 26 | 27 | #include 28 | #include 29 | 30 | 31 | 32 | void show_image(std::string title, const cv::Mat &mat, int x_window, int y_window); 33 | cv::Mat image1d_to_graph(const cv::Mat &mat, int graph_height, int channel_id = -1, double thresh_jump = -1.0); 34 | cv::Mat extract_row(const cv::Mat mat, int row); // extract a row from a 2d image, to process this row as a single 1d image 35 | 36 | 37 | 38 | template struct MatDepth { static const int value = cv::DataDepth::value; }; 39 | 40 | class MatImage: public BaseImage 41 | { 42 | public: 43 | MatImage(cv::Mat image) { mat = image; } 44 | MatImage(const ArrayDim &dim, int depth) { mat = cv::Mat(dim.h, dim.w, CV_MAKETYPE(depth, dim.num_channels), cv::Scalar::all(0)); } 45 | virtual ~MatImage() {} 46 | 47 | virtual BaseImage* new_of_same_type_and_size() const { return new MatImage(dim(), mat.depth()); } 48 | virtual ArrayDim dim() const { return ArrayDim(mat.cols, mat.rows, mat.channels()); } 49 | virtual void copy_from_layered(const ImageUntypedAccess &in) { copy_image(this->get_untyped_access(), in); } 50 | virtual void copy_to_layered(ImageUntypedAccess out) const { copy_image(out, this->get_untyped_access()); } 51 | 52 | cv::Mat get_mat() const { return mat; } 53 | 54 | private: 55 | typedef ImageUntypedAccess image_untyped_access_t; 56 | image_untyped_access_t get_untyped_access() const 57 | { 58 | return image_untyped_access_t(get_data(), dim(), elem_kind(), true); // true = on_host 59 | } 60 | 61 | void* get_data() const { return (void*)mat.data; } 62 | ElemKind elem_kind() const 63 | { 64 | int mat_depth = mat.depth(); 65 | switch (mat_depth) 66 | { 67 | case MatDepth::value: { return elem_kind_uchar; } 68 | case MatDepth::value: { return elem_kind_float; } 69 | case MatDepth::value: { return elem_kind_double; } 70 | default: { std::cerr << "ERROR: MatImage::elem_kind(): Unexpected cv::Mat depth " << mat_depth << std::endl; return elem_kind_uchar; } 71 | } 72 | } 73 | 74 | cv::Mat mat; 75 | }; 76 | 77 | 78 | 79 | #endif // not DISABLE_OPENCV 80 | 81 | #endif // UTIL_IMAGE_MAT_H 82 | -------------------------------------------------------------------------------- /src/libfastms/util/mem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_MEM_H 21 | #define UTIL_MEM_H 22 | 23 | 24 | 25 | template 26 | class HeapArray 27 | { 28 | public: 29 | typedef T elem_type; 30 | 31 | explicit HeapArray(int num_elem) : data(NULL) 32 | { 33 | data = new T[num_elem]; 34 | } 35 | ~HeapArray() 36 | { 37 | if (data) delete[] data; 38 | data = NULL; 39 | } 40 | T& get(int i) 41 | { 42 | return data[i]; 43 | } 44 | const T& get(int i) const 45 | { 46 | return data[i]; 47 | } 48 | 49 | private: 50 | HeapArray(const HeapArray &other_array); 51 | HeapArray& operator= (const HeapArray &other_array); 52 | 53 | T *data; 54 | }; 55 | 56 | 57 | 58 | #endif // UTIL_MEM_H 59 | -------------------------------------------------------------------------------- /src/libfastms/util/mem_cuda.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_MEM_CUDA_H 21 | #define UTIL_MEM_CUDA_H 22 | 23 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 24 | 25 | #include 26 | 27 | 28 | 29 | template __device__ T* shmem_ptr(); 30 | // must specialize here for cuda to have everything in one place 31 | #define SPECIALIZATION(TYPE) template<> __device__ __forceinline__ TYPE* shmem_ptr() { extern __shared__ TYPE shmem_##TYPE[]; return shmem_##TYPE; } 32 | SPECIALIZATION(float) 33 | SPECIALIZATION(double) 34 | #undef SPECIALIZATION 35 | 36 | 37 | template 38 | class ShMemArray 39 | { 40 | public: 41 | typedef T elem_type; 42 | 43 | // Since all CUDA shared memory arrays begin at the same address, 44 | // the following constructor should be used only for the first array. 45 | __device__ ShMemArray(int num_elem) : num_elem(num_elem) 46 | { 47 | index_thread = threadIdx.x + blockDim.x * threadIdx.y; 48 | num_threads = blockDim.x * blockDim.y; 49 | data_start = shmem_ptr(); 50 | data_end = data_start + num_elem * num_threads; 51 | } 52 | // The second and all subsequent arrays should use the following constructor, 53 | // where the second argument is the previously declared array. 54 | // Example: 55 | // ShMemArray myarray1(10); 56 | // ShMemArray myarray2(50, myarray1); 57 | // ShMemArray myarray3(2, myarray2); 58 | template __device__ ShMemArray(int num_elem, const ShMemArray &from_array) : num_elem(num_elem) 59 | { 60 | index_thread = from_array.index_thread; 61 | num_threads = from_array.num_threads; 62 | data_start = (T*)from_array.data_end; 63 | data_end = data_start + num_elem * num_threads; 64 | } 65 | __device__ T& get(int i) 66 | { 67 | return data_start[index(i)]; 68 | } 69 | __device__ const T& get(int i) const 70 | { 71 | return data_start[index(i)]; 72 | } 73 | __host__ static size_t size(int num_elem, dim3 block) 74 | { 75 | return block.x * block.y * block.z * sizeof(T) * num_elem; 76 | } 77 | private: 78 | __device__ ShMemArray(const ShMemArray &other_array); 79 | __device__ ShMemArray& operator= (const ShMemArray &other_array); 80 | __device__ int index(int i) const 81 | { 82 | return i + num_elem * index_thread; 83 | //return index_thread + num_threads * i; // slower by factor 1.3 84 | } 85 | int num_elem; 86 | int index_thread; 87 | int num_threads; 88 | T *data_start; 89 | T *data_end; 90 | }; 91 | 92 | 93 | 94 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 95 | 96 | #endif // UTIL_MEM_CUDA_H 97 | -------------------------------------------------------------------------------- /src/libfastms/util/real.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_REAL_H 21 | #define UTIL_REAL_H 22 | 23 | #include // for min, max 24 | #include 25 | #include 26 | 27 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 28 | #include 29 | #define HOST_DEVICE __host__ __device__ 30 | #define FORCEINLINE __forceinline__ 31 | #else 32 | #define HOST_DEVICE 33 | #define FORCEINLINE inline 34 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 35 | 36 | 37 | 38 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 39 | template bool gpu_supports_real(); 40 | template<> inline bool gpu_supports_real() { return true; } 41 | template<> inline bool gpu_supports_real() 42 | { 43 | // check gpu for double support 44 | int device = 0; 45 | cudaGetDevice(&device); 46 | cudaDeviceProp prop; 47 | cudaGetDeviceProperties(&prop, device); 48 | return (prop.major >= 2 || (prop.major == 1 && prop.minor >= 3)); 49 | } 50 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 51 | 52 | 53 | template HOST_DEVICE FORCEINLINE real realabs(real x); 54 | template<> HOST_DEVICE FORCEINLINE float realabs (float x) 55 | { 56 | #ifdef __CUDA_ARCH__ 57 | // device code 58 | return fabsf(x); 59 | #else 60 | // host code 61 | return std::fabs(x); 62 | #endif 63 | } 64 | template<> HOST_DEVICE FORCEINLINE double realabs (double x) 65 | { 66 | #ifdef __CUDACC__ 67 | return fabs(x); 68 | #else 69 | return std::fabs(x); 70 | #endif 71 | } 72 | 73 | 74 | template HOST_DEVICE FORCEINLINE real realsqrt(real x); 75 | template<> HOST_DEVICE FORCEINLINE float realsqrt (float x) 76 | { 77 | #ifdef __CUDACC__ 78 | return sqrtf(x); 79 | #else 80 | return std::sqrt(x); 81 | #endif 82 | } 83 | template<> HOST_DEVICE FORCEINLINE double realsqrt (double x) 84 | { 85 | #ifdef __CUDACC__ 86 | return sqrt(x); 87 | #else 88 | return std::sqrt(x); 89 | #endif 90 | } 91 | 92 | 93 | template HOST_DEVICE FORCEINLINE real realexp(real x); 94 | template<> HOST_DEVICE FORCEINLINE float realexp (float x) 95 | { 96 | #ifdef __CUDACC__ 97 | return expf(x); 98 | #else 99 | return std::exp(x); 100 | #endif 101 | } 102 | template<> HOST_DEVICE FORCEINLINE double realexp (double x) 103 | { 104 | #ifdef __CUDACC__ 105 | return exp(x); 106 | #else 107 | return std::exp(x); 108 | #endif 109 | } 110 | 111 | 112 | template HOST_DEVICE FORCEINLINE real reallog(real x); 113 | template<> HOST_DEVICE FORCEINLINE float reallog (float x) 114 | { 115 | #ifdef __CUDACC__ 116 | return logf(x); 117 | #else 118 | return std::log(x); 119 | #endif 120 | } 121 | template<> HOST_DEVICE FORCEINLINE double reallog (double x) 122 | { 123 | #ifdef __CUDACC__ 124 | return log(x); 125 | #else 126 | return std::log(x); 127 | #endif 128 | } 129 | 130 | 131 | template HOST_DEVICE FORCEINLINE real realfloor(real x); 132 | template<> HOST_DEVICE FORCEINLINE float realfloor (float x) 133 | { 134 | #ifdef __CUDACC__ 135 | return floorf(x); 136 | #else 137 | return std::floor(x); 138 | #endif 139 | } 140 | template<> HOST_DEVICE FORCEINLINE double realfloor (double x) 141 | { 142 | #ifdef __CUDACC__ 143 | return floor(x); 144 | #else 145 | return std::floor(x); 146 | #endif 147 | } 148 | 149 | 150 | template HOST_DEVICE FORCEINLINE real realmax(real x, real y) 151 | { 152 | #ifdef __CUDACC__ 153 | return max(x, y); 154 | #else 155 | return std::max(x, y); 156 | #endif 157 | } 158 | 159 | 160 | template HOST_DEVICE FORCEINLINE real realmin(real x, real y) 161 | { 162 | #ifdef __CUDACC__ 163 | return min(x, y); 164 | #else 165 | return std::min(x, y); 166 | #endif 167 | } 168 | 169 | 170 | template HOST_DEVICE FORCEINLINE real realmax(); 171 | // divide max values by 4 to adjust for ancient GPUs which couldn't represent all CPU float values 172 | template<> HOST_DEVICE FORCEINLINE float realmax () { return FLT_MAX / 4.0f; } 173 | template<> HOST_DEVICE FORCEINLINE double realmax () { return DBL_MAX / 4.0; } 174 | 175 | 176 | template HOST_DEVICE typename Array1D::elem_type vec_norm_squared(const Array1D &a, int num) 177 | { 178 | typedef typename Array1D::elem_type real; 179 | real result = real(0); 180 | for (int i = 0; i < num; i++) 181 | { 182 | real val = a.get(i); 183 | result += val * val; 184 | } 185 | return result; 186 | } 187 | 188 | 189 | template HOST_DEVICE typename Array1D::elem_type vec_norm(const Array1D &a, int num) 190 | { 191 | return realsqrt(vec_norm_squared(a, num)); 192 | } 193 | 194 | 195 | template HOST_DEVICE void vec_scale_eq(Array1D &a, int num, typename Array1D::elem_type mult) 196 | { 197 | for (int i = 0; i < num; i++) 198 | { 199 | a.get(i) *= mult; 200 | } 201 | } 202 | 203 | 204 | template HOST_DEVICE typename Array1D::elem_type vec_diff_l1(const Array1D &a, const Array1D &b, int num) 205 | { 206 | typedef typename Array1D::elem_type real; 207 | real result = real(0); 208 | for (int i = 0; i < num; i++) 209 | { 210 | real val_a = a(i); 211 | real val_b = b(i); 212 | real diff = realabs(val_a - val_b); 213 | result += diff; 214 | } 215 | return result; 216 | } 217 | 218 | 219 | template HOST_DEVICE FORCEINLINE Tout convert_type(Tin in); 220 | template<> HOST_DEVICE FORCEINLINE float convert_type(float in) { return in; } 221 | template<> HOST_DEVICE FORCEINLINE float convert_type(double in) { return (float)in; } 222 | template<> HOST_DEVICE FORCEINLINE float convert_type(unsigned char in) { return (float)in / 255.0f; } 223 | template<> HOST_DEVICE FORCEINLINE double convert_type(float in) { return (double)in; } 224 | template<> HOST_DEVICE FORCEINLINE double convert_type(double in) { return in; } 225 | template<> HOST_DEVICE FORCEINLINE double convert_type(unsigned char in) { return (double)in / 255.0; } 226 | template<> HOST_DEVICE FORCEINLINE unsigned char convert_type(float in) { return (unsigned char)realmax(0, realmin(255, (int)realfloor(in * 255.0f))); } 227 | template<> HOST_DEVICE FORCEINLINE unsigned char convert_type(double in) { return (unsigned char)realmax(0, realmin(255, (int)realfloor(in * 255.0))); } 228 | 229 | 230 | enum ElemKind 231 | { 232 | elem_kind_uchar = 0, 233 | elem_kind_float, 234 | elem_kind_double 235 | }; 236 | 237 | 238 | template struct ElemType2Kind; 239 | template<> struct ElemType2Kind { static const ElemKind value = elem_kind_uchar; }; 240 | template<> struct ElemType2Kind { static const ElemKind value = elem_kind_float; }; 241 | template<> struct ElemType2Kind { static const ElemKind value = elem_kind_double; }; 242 | 243 | 244 | struct ElemKindGeneral 245 | { 246 | HOST_DEVICE static size_t size(ElemKind elem_kind) 247 | { 248 | switch (elem_kind) 249 | { 250 | case elem_kind_uchar: { return sizeof(unsigned char); } 251 | case elem_kind_float: { return sizeof(float); } 252 | case elem_kind_double: { return sizeof(double); } 253 | default: { return 0; } 254 | } 255 | } 256 | }; 257 | 258 | 259 | HOST_DEVICE FORCEINLINE void convert_type(ElemKind out_kind, ElemKind in_kind, void *out, const void *in) 260 | { 261 | if (out_kind == elem_kind_float && in_kind == elem_kind_float) { *(float*)out = convert_type(*(const float*)in); } 262 | if (out_kind == elem_kind_float && in_kind == elem_kind_double) { *(float*)out = convert_type(*(const double*)in); } 263 | if (out_kind == elem_kind_float && in_kind == elem_kind_uchar) { *(float*)out = convert_type(*(const unsigned char*)in); } 264 | if (out_kind == elem_kind_double && in_kind == elem_kind_float) { *(double*)out = convert_type(*(const float*)in); } 265 | if (out_kind == elem_kind_double && in_kind == elem_kind_double) { *(double*)out = convert_type(*(const double*)in); } 266 | if (out_kind == elem_kind_double && in_kind == elem_kind_uchar) { *(double*)out = convert_type(*(const unsigned char*)in); } 267 | if (out_kind == elem_kind_uchar && in_kind == elem_kind_float) { *(unsigned char*)out = convert_type(*(const float*)in); } 268 | if (out_kind == elem_kind_uchar && in_kind == elem_kind_double) { *(unsigned char*)out = convert_type(*(const double*)in); } 269 | } 270 | 271 | 272 | 273 | #undef HOST_DEVICE 274 | #undef FORCEINLINE 275 | 276 | #endif // AUX_REAL_H 277 | -------------------------------------------------------------------------------- /src/libfastms/util/sum.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_SUM_H 21 | #define UTIL_SUM_H 22 | 23 | 24 | #include "image_access.h" 25 | 26 | 27 | 28 | template 29 | class KahanSummation 30 | { 31 | public: 32 | KahanSummation() 33 | { 34 | clear(); 35 | } 36 | void clear() 37 | { 38 | s = T(0); 39 | addend_small = T(0); 40 | } 41 | void add(T a) 42 | { 43 | T addend_compensated = a - addend_small; 44 | T s_compensated = s + addend_compensated; 45 | addend_small = (s_compensated-s) - addend_compensated; 46 | s = s_compensated; 47 | } 48 | T sum() 49 | { 50 | return s; 51 | } 52 | private: 53 | T s; 54 | T addend_small; 55 | }; 56 | 57 | 58 | template 59 | T cpu_sum(const void *a, size_t num) 60 | { 61 | const T *a_T = (const T*)a; 62 | KahanSummation summation; 63 | for (size_t i = 0; i < num; i++) 64 | { 65 | summation.add(a_T[i]); 66 | } 67 | return summation.sum(); 68 | } 69 | 70 | 71 | template 72 | T cpu_sum2d(const void *a, size_t pitch, int w, int h) 73 | { 74 | KahanSummation summation; 75 | for (int y = 0; y < h; y++) 76 | { 77 | const T *y_ptr = (const T*)((char*)a + pitch * y); 78 | for (int x = 0; x < w; x++) 79 | { 80 | summation.add(y_ptr[x]); 81 | } 82 | } 83 | return summation.sum(); 84 | } 85 | 86 | 87 | template 88 | typename TImageAccess::elem_t cpu_sum_reduce(TImageAccess aux_reduce) 89 | { 90 | typedef typename TImageAccess::elem_t real; 91 | 92 | real sum = real(0); 93 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 94 | #pragma omp parallel default(none) shared(sum) firstprivate(aux_reduce) 95 | { 96 | #endif 97 | const Dim2D &dim2d = aux_reduce.dim().dim2d(); 98 | KahanSummation summation; 99 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 100 | #pragma omp for 101 | #endif 102 | for (int y = 0; y < dim2d.h; y++) 103 | { 104 | for (int x = 0; x < dim2d.w; x++) 105 | { 106 | summation.add(aux_reduce.get(x, y, 0)); 107 | } 108 | } 109 | real sub_sum = summation.sum(); 110 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 111 | #pragma omp atomic 112 | #endif 113 | sum += sub_sum; 114 | #if !defined(DISABLE_OPENMP) && defined(_OPENMP) 115 | } 116 | #endif 117 | return sum; 118 | } 119 | 120 | 121 | 122 | #endif // UTIL_SUM_H 123 | -------------------------------------------------------------------------------- /src/libfastms/util/sum_cuda.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_CUDA_SUM_H 21 | #define UTIL_CUDA_SUM_H 22 | 23 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | 31 | namespace 32 | { 33 | 34 | template 35 | T cuda_sum_on_cpu(const T *a, int num) 36 | { 37 | T *host_copy = new T[num]; 38 | cudaMemcpy(host_copy, a, num * sizeof(T), cudaMemcpyDeviceToHost); 39 | T sum = cpu_sum(host_copy, num); 40 | delete[] host_copy; 41 | return sum; 42 | } 43 | 44 | template 45 | T cuda_sum_with_existing_handle(const void *a, int num, const cublasHandle_t &handle) 46 | { 47 | // sum on cpu for general T (except T=float and T=double, see specializations below) 48 | return cuda_sum_on_cpu(a, num); 49 | } 50 | template<> __forceinline__ float cuda_sum_with_existing_handle(const void *a, int num, const cublasHandle_t &handle) 51 | { 52 | float sum = 0.0f; 53 | cublasSasum(handle, num, (float*)a, 1, &sum); // 1: sum every element (not only every 2nd, or every 3rd etc.) 54 | return sum; 55 | } 56 | template<> __forceinline__ double cuda_sum_with_existing_handle(const void *a, int num, const cublasHandle_t &handle) 57 | { 58 | double sum = 0.0; 59 | cublasDasum(handle, num, (double*)a, 1, &sum); 60 | return sum; 61 | } 62 | 63 | } // namespace 64 | 65 | 66 | 67 | template 68 | class DeviceSummator 69 | { 70 | public: 71 | DeviceSummator() : cublas_handle(NULL) {} 72 | void alloc() 73 | { 74 | cublasCreate(&cublas_handle); 75 | } 76 | void free() 77 | { 78 | cublasDestroy(cublas_handle); 79 | } 80 | real sum(const void *data, size_t num_bytes) 81 | { 82 | size_t elem_size = sizeof(real); 83 | if (num_bytes % elem_size == 0) 84 | { 85 | size_t effective_num_elem = num_bytes / elem_size; 86 | return cuda_sum_with_existing_handle(data, effective_num_elem, cublas_handle); 87 | } 88 | else 89 | { 90 | std::cerr << "ERROR: DeviceSummator::sum(): array size (" << num_bytes << " B) not multiple of element size (" << elem_size << " B)." << std::endl; 91 | return real(0); 92 | } 93 | } 94 | private: 95 | cublasHandle_t cublas_handle; 96 | }; 97 | 98 | 99 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 100 | 101 | #endif // UTIL_CUDA_SUM_H 102 | -------------------------------------------------------------------------------- /src/libfastms/util/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_TIMER_H 21 | #define UTIL_TIMER_H 22 | 23 | //#include 24 | #include 25 | #include 26 | 27 | 28 | class Timer 29 | { 30 | public: 31 | Timer() : time_start(0.0), running(false), seconds(0.0) 32 | { 33 | } 34 | void start() 35 | { 36 | time_start = get_cur_seconds(); 37 | running = true; 38 | } 39 | void end() 40 | { 41 | if (!running) { seconds = 0.0; return; } 42 | seconds = get_cur_seconds() - time_start; 43 | running = false; 44 | } 45 | double get() 46 | { 47 | if (running) end(); 48 | return seconds; 49 | } 50 | private: 51 | // this method accumulates the time spent in all threads as if they were running in parallel, 52 | // so we can't use this if we compute something with OpenMP 53 | // double get_cur_seconds() { return (double)clock() / CLOCKS_PER_SEC; } 54 | 55 | // this gives the wall clock time, and works as expected with OpenMP 56 | double get_cur_seconds() 57 | { 58 | struct timeval cur_time; 59 | if (gettimeofday(&cur_time, NULL)) { return 0.0; } 60 | return (double)cur_time.tv_sec + 1e-6 * (double)cur_time.tv_usec; 61 | } 62 | double time_start; 63 | bool running; 64 | double seconds; 65 | }; 66 | 67 | 68 | #endif // UTIL_TIMER_H 69 | -------------------------------------------------------------------------------- /src/libfastms/util/timer_cuda.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_CUDA_TIMER_H 21 | #define UTIL_CUDA_TIMER_H 22 | 23 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 24 | 25 | #include 26 | 27 | 28 | 29 | class DeviceTimer 30 | { 31 | public: 32 | DeviceTimer() : running(false), sec(0.0) 33 | { 34 | cudaEventCreate(&event_start); 35 | cudaEventCreate(&event_stop); 36 | } 37 | ~DeviceTimer() 38 | { 39 | cudaEventDestroy(event_start); 40 | cudaEventDestroy(event_stop); 41 | } 42 | void start() 43 | { 44 | cudaEventRecord(event_start,0); 45 | cudaEventSynchronize(event_start); 46 | running = true; 47 | } 48 | void end() 49 | { 50 | if (!running) 51 | { 52 | sec = 0; 53 | return; 54 | } 55 | cudaEventRecord(event_stop,0); 56 | cudaEventSynchronize(event_stop); 57 | float cuda_duration; 58 | cudaEventElapsedTime(&cuda_duration, event_start, event_stop); 59 | sec = (double)cuda_duration / 1000.0; 60 | running = false; 61 | } 62 | double get() 63 | { 64 | if (running) end(); 65 | return sec; 66 | } 67 | private: 68 | cudaEvent_t event_start; 69 | cudaEvent_t event_stop; 70 | bool running; 71 | double sec; 72 | }; 73 | 74 | 75 | 76 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 77 | 78 | #endif // UTIL_CUDA_TIMER_H 79 | -------------------------------------------------------------------------------- /src/libfastms/util/types_equal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_TYPES_EQUAL_H 21 | #define UTIL_TYPES_EQUAL_H 22 | 23 | 24 | 25 | template struct types_equal { static const bool value = false; }; 26 | template struct types_equal { static const bool value = true; }; 27 | 28 | 29 | 30 | #endif // UTIL_TYPES_EQUAL_H 31 | -------------------------------------------------------------------------------- /src/libfastms/util/vars_cuda.cuh: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef UTIL_CUDA_VARS_H 21 | #define UTIL_CUDA_VARS_H 22 | 23 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 24 | 25 | #include // min, max 26 | #include 27 | #include 28 | #include "image_access.h" 29 | 30 | 31 | 32 | __device__ __forceinline__ int cuda_x() { return threadIdx.x + blockDim.x * blockIdx.x; } 33 | __device__ __forceinline__ int cuda_y() { return threadIdx.y + blockDim.y * blockIdx.y; } 34 | 35 | 36 | __device__ __host__ __forceinline__ bool is_active(int x, int y, const Dim2D &dim) 37 | { 38 | return (x < dim.w && y < dim.h); 39 | } 40 | 41 | 42 | inline dim3 cuda_block_size(int w, int h) 43 | { 44 | dim3 block(128, 2, 1); 45 | block.x = std::min((int)block.x, w); 46 | block.y = std::min((int)block.y, w); 47 | return block; 48 | } 49 | 50 | 51 | inline dim3 cuda_grid_size(dim3 block, int w, int h) 52 | { 53 | return dim3((w + block.x - 1) / block.x, (h + block.y - 1) / block.y, 1); 54 | } 55 | 56 | 57 | 58 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 59 | 60 | #endif // UTIL_CUDA_VARS_H 61 | -------------------------------------------------------------------------------- /src/mex/fastms_mex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef DISABLE_MEX 21 | 22 | #include "mex.h" 23 | #include "mex_util.h" 24 | #include "solver/solver.h" 25 | 26 | 27 | 28 | Par parse_par(const mxArray *matrix) 29 | { 30 | Par par; 31 | matlab_get_scalar_field("lambda", par.lambda, matrix); 32 | matlab_get_scalar_field("alpha", par.alpha, matrix); 33 | matlab_get_scalar_field("temporal", par.temporal, matrix); 34 | matlab_get_scalar_field("iterations", par.iterations, matrix); 35 | matlab_get_scalar_field("stop_eps", par.stop_eps, matrix); 36 | matlab_get_scalar_field("stop_k", par.stop_k, matrix); 37 | matlab_get_scalar_field("adapt_params", par.adapt_params, matrix); 38 | matlab_get_scalar_field("weight", par.weight, matrix); 39 | matlab_get_scalar_field("use_double", par.use_double, matrix); 40 | matlab_get_scalar_field("engine", par.engine, matrix); 41 | matlab_get_scalar_field("edges", par.edges, matrix); 42 | matlab_get_scalar_field("verbose", par.verbose, matrix); 43 | return par; 44 | } 45 | 46 | 47 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 48 | { 49 | // 1st argument: input image 50 | // 2nd argument (optional): parameters 51 | if (!(nrhs == 1 || nrhs == 2)) { mexPrintf("Syntax: out_image = ms(in_image, par)\n"); return; } 52 | if (nlhs == 0) { return; } 53 | 54 | 55 | // get parameters 56 | Par par; 57 | if (nrhs >= 2) { par = parse_par(prhs[1]); } 58 | if (par.verbose) par.print(); 59 | 60 | 61 | // compute 62 | Solver solver; 63 | MatlabImage in_matlabimage(prhs[0]); 64 | MatlabImage *out_matlabimage = static_cast(solver.run(&in_matlabimage, par)); 65 | plhs[0] = out_matlabimage->get_matrix(); 66 | delete out_matlabimage; 67 | 68 | 69 | // set other outputs to an empty matrix 70 | for (int i = 1; i < nlhs; i++) { plhs[i] = MatlabImage::empty_matrix(); } 71 | } 72 | 73 | #endif // not DISABLE_MEX 74 | -------------------------------------------------------------------------------- /src/mex/mex_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastms. 3 | * 4 | * Copyright 2014 Evgeny Strekalovskiy (Technical University of Munich) 5 | * 6 | * fastms is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * fastms is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with fastms. If not, see . 18 | */ 19 | 20 | #ifndef MEX_MEX_UTIL_H 21 | #define MEX_MEX_UTIL_H 22 | 23 | #ifndef DISABLE_MEX 24 | 25 | #include "mex.h" 26 | #include "util/image.h" 27 | #include 28 | #include 29 | 30 | //#include "util/real.h" 31 | 32 | #if !defined(DISABLE_CUDA) && defined(__CUDACC__) 33 | #define HOST_DEVICE __host__ __device__ 34 | #define FORCEINLINE __forceinline__ 35 | #else 36 | #define HOST_DEVICE 37 | #define FORCEINLINE inline 38 | #endif // !defined(DISABLE_CUDA) && defined(__CUDACC__) 39 | 40 | 41 | 42 | template struct MatlabClass; 43 | template<> struct MatlabClass { static const int value = mxUINT8_CLASS; }; 44 | template<> struct MatlabClass { static const int value = mxSINGLE_CLASS; }; 45 | template<> struct MatlabClass { static const int value = mxDOUBLE_CLASS; }; 46 | 47 | 48 | class MatlabImage: public BaseImage 49 | { 50 | public: 51 | MatlabImage() : matrix(NULL) {} 52 | MatlabImage(const mxArray *matrix) : matrix(const_cast(matrix)) 53 | { 54 | if (!matrix) { mexPrintf("ERROR: matrix is NULL\n"); return; } 55 | if (mxIsSparse(matrix)) { mexPrintf("ERROR: matrix must be dense\n"); return; } 56 | 57 | int num_dims = mxGetNumberOfDimensions(matrix); 58 | const mwSize *matrix_dims = mxGetDimensions(matrix); 59 | dims.resize(num_dims); 60 | for (int i = 0; i < num_dims; i++) 61 | { 62 | dims[i] = matrix_dims[i]; 63 | } 64 | } 65 | MatlabImage(const std::vector &dims, mxClassID matrix_class) : matrix(NULL), dims(dims) 66 | { 67 | matrix = mxCreateNumericArray(dims.size(), dims.data(), matrix_class, mxREAL); 68 | } 69 | virtual ~MatlabImage() {} 70 | static mxArray* empty_matrix() { return empty_matrix(mxDOUBLE_CLASS); } 71 | static mxArray* empty_matrix(mxClassID matrix_class) 72 | { 73 | std::vector dims; 74 | MatlabImage matlab_image(dims, matrix_class); 75 | return matlab_image.get_matrix(); 76 | } 77 | 78 | virtual BaseImage* new_of_same_type_and_size() const { return new MatlabImage(get_dims(), get_class()); } 79 | virtual ArrayDim dim() const 80 | { 81 | ArrayDim d; 82 | d.w = (dims.size() > 1? (int)dims[1] : 1); 83 | d.h = (dims.size() > 0? (int)dims[0] : 0); 84 | size_t num_ch = 1; 85 | for (int i = 2; i < (int)dims.size(); i++) 86 | { 87 | num_ch *= dims[i]; 88 | } 89 | d.num_channels = num_ch; 90 | return d; 91 | } 92 | virtual void copy_from_layered(const ImageUntypedAccess &in) { copy_image(this->get_untyped_access(), in); } 93 | virtual void copy_to_layered(ImageUntypedAccess out) const { copy_image(out, this->get_untyped_access()); } 94 | 95 | mxArray* get_matrix() const { return matrix; } 96 | std::vector get_dims() const { return dims; } 97 | 98 | private: 99 | typedef ImageUntypedAccess image_untyped_access_t; 100 | image_untyped_access_t get_untyped_access() const 101 | { 102 | return image_untyped_access_t(get_data(), dim(), elem_kind(), true); // true = on_host 103 | } 104 | 105 | mxClassID get_class() const { return mxGetClassID(matrix); } 106 | void* get_data() const { return (void*)mxGetPr(matrix); } 107 | ElemKind elem_kind() const 108 | { 109 | mxClassID matlab_class = get_class(); 110 | switch (matlab_class) 111 | { 112 | case MatlabClass::value: { return elem_kind_uchar; } 113 | case MatlabClass::value: { return elem_kind_float; } 114 | case MatlabClass::value: { return elem_kind_double; } 115 | default: { std::cerr << "ERROR: MatlabImage::elem_kind(): Unexpected matlab class " << matlab_class << std::endl; return elem_kind_uchar; } 116 | } 117 | } 118 | 119 | mxArray *matrix; 120 | std::vector dims; 121 | }; 122 | 123 | 124 | template void set_var(double value, T &var); 125 | template<> void set_var(double value, float &var) { var = (float)value; } 126 | template<> void set_var(double value, double &var) { var = value; } 127 | template<> void set_var(double value, bool &var) { var = (value != 0.0); } 128 | template<> void set_var(double value, int &var) { var = (int)value; } 129 | 130 | 131 | template 132 | void matlab_get_scalar_field(std::string name, T &var, const mxArray* matrix) 133 | { 134 | if (!mxIsStruct(matrix)) 135 | { 136 | std::cerr << "ERROR: matlab_get_scalar_field(" << name.c_str() << "): matrix must be a struct" << std::endl; 137 | return; 138 | } 139 | int index = 0; 140 | const mxArray* matrix_field = mxGetField(matrix, index, name.c_str()); 141 | if (!matrix_field) 142 | { 143 | std::cout << "WARNING: matlab_get_scalar_field(" << name.c_str() << "): matrix does not contain this field" << std::endl; 144 | return; 145 | } 146 | 147 | if (mxIsSparse(matrix_field)) 148 | { 149 | std::cerr << "ERROR: matlab_get_scalar_field(" << name.c_str() << "): matrix field must be dense" << std::endl; 150 | return; 151 | } 152 | if (mxGetNumberOfDimensions(matrix_field) == 2 && (mxGetM(matrix_field) == 0 || mxGetN(matrix_field) == 0)) 153 | { 154 | return; 155 | } 156 | if (!(mxGetNumberOfDimensions(matrix_field) == 2 && 157 | mxGetM(matrix_field) == 1 && mxGetN(matrix_field) == 1 && 158 | !mxIsComplex(matrix_field))) 159 | { 160 | std::cerr << "ERROR: matlab_get_scalar_field(" << name.c_str() << "): matrix field must be a scalar"; 161 | std::cerr << " (#dims = " << mxGetNumberOfDimensions(matrix_field); 162 | std::cerr << ", " << mxGetM(matrix_field) << " x " << mxGetN(matrix_field); 163 | std::cerr << ", is_complex = " << (mxIsComplex(matrix_field)? "true" : "false"); 164 | std::cerr << std::endl; 165 | return; 166 | } 167 | 168 | double result = mxGetScalar(matrix_field); 169 | set_var(result, var); 170 | } 171 | 172 | 173 | 174 | #endif // not DISABLE_MEX 175 | 176 | #endif // MEX_MEX_UTIL_H 177 | --------------------------------------------------------------------------------