├── .gitignore
├── Example.png
├── LICENSE
├── Overview.png
├── Primatte
├── Makefile
├── Primatte.pro
├── Primatte.pro.user
├── algorithmprimatte.cpp
├── algorithmprimatte.h
├── alphalocator.cpp
├── alphalocator.h
├── application.cpp
├── application.h
├── averagebackgroundcolourlocators.cpp
├── averagebackgroundcolourlocators.h
├── boundingpolyhedron.cpp
├── boundingpolyhedron.h
├── coloursegmenters.cpp
├── coloursegmenters.h
├── fittingalgorithms.cpp
├── fittingalgorithms.h
├── ialgorithm.h
├── ialphalocator.h
├── iaveragebackgroundcolourlocator.h
├── icoloursegmenter.h
├── ifittingalgorithm.h
├── inputassembler.cpp
├── inputassembler.h
├── io.cpp
├── io.h
├── main.cpp
├── matrixd.cpp
├── matrixd.h
├── spherepolyhedron.cpp
└── spherepolyhedron.h
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | Primatte-build-*
2 |
3 | # Compiled Object files
4 | *.slo
5 | *.lo
6 | *.o
7 | *.obj
8 |
9 | # Precompiled Headers
10 | *.gch
11 | *.pch
12 |
13 | # Compiled Dynamic libraries
14 | *.so
15 | *.dylib
16 | *.dll
17 |
18 | # Fortran module files
19 | *.mod
20 |
21 | # Compiled Static libraries
22 | *.lai
23 | *.la
24 | *.a
25 | *.lib
26 |
27 | # Executables
28 | *.exe
29 | *.out
30 | *.app
31 |
--------------------------------------------------------------------------------
/Example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DreamingInfraviolet/EstimateImageMatting/6a80089dfa9b956e9a5baaac66789b3af26adec9/Example.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Anima
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DreamingInfraviolet/EstimateImageMatting/6a80089dfa9b956e9a5baaac66789b3af26adec9/Overview.png
--------------------------------------------------------------------------------
/Primatte/Makefile:
--------------------------------------------------------------------------------
1 | #############################################################################
2 | # Makefile for building: Part2
3 | # Generated by qmake (2.01a) (Qt 4.8.1) on: Mon Aug 24 13:43:33 2015
4 | # Project: Primatte.pro
5 | # Template: app
6 | # Command: /usr/bin/qmake-qt4 -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile Primatte.pro
7 | #############################################################################
8 |
9 | ####### Compiler, tools and options
10 |
11 | CC = gcc
12 | CXX = g++
13 | DEFINES = -DQT_WEBKIT -DQT_XML_LIB -DQT_OPENGL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
14 | CFLAGS = -pipe -g -Wall -W -D_REENTRANT $(DEFINES)
15 | CXXFLAGS = -pipe -std=c++11 -Wall -g -Wall -W -D_REENTRANT $(DEFINES)
16 | INCPATH = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtOpenGL -I/usr/include/qt4/QtXml -I/usr/include/qt4 -I/usr/include -I/usr/include/opencv -I/usr/X11R6/include -I.
17 | LINK = g++
18 | LFLAGS =
19 | LIBS = $(SUBLIBS) -L/usr/lib/x86_64-linux-gnu -L/usr/X11R6/lib -L/usr/lib -lqglviewer-qt4 -lGLU -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann -lQtXml -lQtOpenGL -lQtGui -lQtCore -lGL -lpthread
20 | AR = ar cqs
21 | RANLIB =
22 | QMAKE = /usr/bin/qmake-qt4
23 | TAR = tar -cf
24 | COMPRESS = gzip -9f
25 | COPY = cp -f
26 | SED = sed
27 | COPY_FILE = $(COPY)
28 | COPY_DIR = $(COPY) -r
29 | STRIP = strip
30 | INSTALL_FILE = install -m 644 -p
31 | INSTALL_DIR = $(COPY_DIR)
32 | INSTALL_PROGRAM = install -m 755 -p
33 | DEL_FILE = rm -f
34 | SYMLINK = ln -f -s
35 | DEL_DIR = rmdir
36 | MOVE = mv -f
37 | CHK_DIR_EXISTS= test -d
38 | MKDIR = mkdir -p
39 |
40 | ####### Output directory
41 |
42 | OBJECTS_DIR = ./
43 |
44 | ####### Files
45 |
46 | SOURCES = main.cpp \
47 | io.cpp \
48 | application.cpp \
49 | matrixd.cpp \
50 | boundingpolyhedron.cpp \
51 | coloursegmenters.cpp \
52 | inputassembler.cpp \
53 | algorithmprimatte.cpp \
54 | alphalocator.cpp \
55 | inputprocessing.cpp \
56 | fittingalgorithms.cpp \
57 | spherepolyhedron.cpp
58 | OBJECTS = main.o \
59 | io.o \
60 | application.o \
61 | matrixd.o \
62 | boundingpolyhedron.o \
63 | coloursegmenters.o \
64 | inputassembler.o \
65 | algorithmprimatte.o \
66 | alphalocator.o \
67 | inputprocessing.o \
68 | fittingalgorithms.o \
69 | spherepolyhedron.o
70 | DIST = /usr/share/qt4/mkspecs/common/unix.conf \
71 | /usr/share/qt4/mkspecs/common/linux.conf \
72 | /usr/share/qt4/mkspecs/common/gcc-base.conf \
73 | /usr/share/qt4/mkspecs/common/gcc-base-unix.conf \
74 | /usr/share/qt4/mkspecs/common/g++-base.conf \
75 | /usr/share/qt4/mkspecs/common/g++-unix.conf \
76 | /usr/share/qt4/mkspecs/qconfig.pri \
77 | /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \
78 | /usr/share/qt4/mkspecs/features/qt_functions.prf \
79 | /usr/share/qt4/mkspecs/features/qt_config.prf \
80 | /usr/share/qt4/mkspecs/features/exclusive_builds.prf \
81 | /usr/share/qt4/mkspecs/features/default_pre.prf \
82 | /usr/share/qt4/mkspecs/features/debug.prf \
83 | /usr/share/qt4/mkspecs/features/default_post.prf \
84 | /usr/share/qt4/mkspecs/features/link_pkgconfig.prf \
85 | /usr/share/qt4/mkspecs/features/declarative_debug.prf \
86 | /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf \
87 | /usr/share/qt4/mkspecs/features/warn_on.prf \
88 | /usr/share/qt4/mkspecs/features/qt.prf \
89 | /usr/share/qt4/mkspecs/features/unix/opengl.prf \
90 | /usr/share/qt4/mkspecs/features/unix/thread.prf \
91 | /usr/share/qt4/mkspecs/features/moc.prf \
92 | /usr/share/qt4/mkspecs/features/resources.prf \
93 | /usr/share/qt4/mkspecs/features/uic.prf \
94 | /usr/share/qt4/mkspecs/features/yacc.prf \
95 | /usr/share/qt4/mkspecs/features/lex.prf \
96 | /usr/share/qt4/mkspecs/features/include_source_dir.prf \
97 | Primatte.pro
98 | QMAKE_TARGET = Part2
99 | DESTDIR =
100 | TARGET = Part2
101 |
102 | first: all
103 | ####### Implicit rules
104 |
105 | .SUFFIXES: .o .c .cpp .cc .cxx .C
106 |
107 | .cpp.o:
108 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
109 |
110 | .cc.o:
111 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
112 |
113 | .cxx.o:
114 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
115 |
116 | .C.o:
117 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
118 |
119 | .c.o:
120 | $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
121 |
122 | ####### Build rules
123 |
124 | all: Makefile $(TARGET)
125 |
126 | $(TARGET): $(OBJECTS)
127 | $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
128 | { test -n "$(DESTDIR)" && DESTDIR="$(DESTDIR)" || DESTDIR=.; } && test $$(gdb --version | sed -e 's,[^0-9]\+\([0-9]\)\.\([0-9]\).*,\1\2,;q') -gt 72 && gdb --nx --batch --quiet -ex 'set confirm off' -ex "save gdb-index $$DESTDIR" -ex quit '$(TARGET)' && test -f $(TARGET).gdb-index && objcopy --add-section '.gdb_index=$(TARGET).gdb-index' --set-section-flags '.gdb_index=readonly' '$(TARGET)' '$(TARGET)' && rm -f $(TARGET).gdb-index || true
129 |
130 | Makefile: Primatte.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/unix.conf \
131 | /usr/share/qt4/mkspecs/common/linux.conf \
132 | /usr/share/qt4/mkspecs/common/gcc-base.conf \
133 | /usr/share/qt4/mkspecs/common/gcc-base-unix.conf \
134 | /usr/share/qt4/mkspecs/common/g++-base.conf \
135 | /usr/share/qt4/mkspecs/common/g++-unix.conf \
136 | /usr/share/qt4/mkspecs/qconfig.pri \
137 | /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \
138 | /usr/share/qt4/mkspecs/features/qt_functions.prf \
139 | /usr/share/qt4/mkspecs/features/qt_config.prf \
140 | /usr/share/qt4/mkspecs/features/exclusive_builds.prf \
141 | /usr/share/qt4/mkspecs/features/default_pre.prf \
142 | /usr/share/qt4/mkspecs/features/debug.prf \
143 | /usr/share/qt4/mkspecs/features/default_post.prf \
144 | /usr/share/qt4/mkspecs/features/link_pkgconfig.prf \
145 | /usr/share/qt4/mkspecs/features/declarative_debug.prf \
146 | /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf \
147 | /usr/share/qt4/mkspecs/features/warn_on.prf \
148 | /usr/share/qt4/mkspecs/features/qt.prf \
149 | /usr/share/qt4/mkspecs/features/unix/opengl.prf \
150 | /usr/share/qt4/mkspecs/features/unix/thread.prf \
151 | /usr/share/qt4/mkspecs/features/moc.prf \
152 | /usr/share/qt4/mkspecs/features/resources.prf \
153 | /usr/share/qt4/mkspecs/features/uic.prf \
154 | /usr/share/qt4/mkspecs/features/yacc.prf \
155 | /usr/share/qt4/mkspecs/features/lex.prf \
156 | /usr/share/qt4/mkspecs/features/include_source_dir.prf \
157 | /usr/lib/x86_64-linux-gnu/libqglviewer-qt4.prl \
158 | /usr/lib/x86_64-linux-gnu/libQtXml.prl \
159 | /usr/lib/x86_64-linux-gnu/libQtOpenGL.prl \
160 | /usr/lib/x86_64-linux-gnu/libQtGui.prl \
161 | /usr/lib/x86_64-linux-gnu/libQtCore.prl
162 | $(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile Primatte.pro
163 | /usr/share/qt4/mkspecs/common/unix.conf:
164 | /usr/share/qt4/mkspecs/common/linux.conf:
165 | /usr/share/qt4/mkspecs/common/gcc-base.conf:
166 | /usr/share/qt4/mkspecs/common/gcc-base-unix.conf:
167 | /usr/share/qt4/mkspecs/common/g++-base.conf:
168 | /usr/share/qt4/mkspecs/common/g++-unix.conf:
169 | /usr/share/qt4/mkspecs/qconfig.pri:
170 | /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri:
171 | /usr/share/qt4/mkspecs/features/qt_functions.prf:
172 | /usr/share/qt4/mkspecs/features/qt_config.prf:
173 | /usr/share/qt4/mkspecs/features/exclusive_builds.prf:
174 | /usr/share/qt4/mkspecs/features/default_pre.prf:
175 | /usr/share/qt4/mkspecs/features/debug.prf:
176 | /usr/share/qt4/mkspecs/features/default_post.prf:
177 | /usr/share/qt4/mkspecs/features/link_pkgconfig.prf:
178 | /usr/share/qt4/mkspecs/features/declarative_debug.prf:
179 | /usr/share/qt4/mkspecs/features/unix/gdb_dwarf_index.prf:
180 | /usr/share/qt4/mkspecs/features/warn_on.prf:
181 | /usr/share/qt4/mkspecs/features/qt.prf:
182 | /usr/share/qt4/mkspecs/features/unix/opengl.prf:
183 | /usr/share/qt4/mkspecs/features/unix/thread.prf:
184 | /usr/share/qt4/mkspecs/features/moc.prf:
185 | /usr/share/qt4/mkspecs/features/resources.prf:
186 | /usr/share/qt4/mkspecs/features/uic.prf:
187 | /usr/share/qt4/mkspecs/features/yacc.prf:
188 | /usr/share/qt4/mkspecs/features/lex.prf:
189 | /usr/share/qt4/mkspecs/features/include_source_dir.prf:
190 | /usr/lib/x86_64-linux-gnu/libqglviewer-qt4.prl:
191 | /usr/lib/x86_64-linux-gnu/libQtXml.prl:
192 | /usr/lib/x86_64-linux-gnu/libQtOpenGL.prl:
193 | /usr/lib/x86_64-linux-gnu/libQtGui.prl:
194 | /usr/lib/x86_64-linux-gnu/libQtCore.prl:
195 | qmake: FORCE
196 | @$(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ CONFIG+=debug CONFIG+=declarative_debug -o Makefile Primatte.pro
197 |
198 | dist:
199 | @$(CHK_DIR_EXISTS) .tmp/Part21.0.0 || $(MKDIR) .tmp/Part21.0.0
200 | $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/Part21.0.0/ && $(COPY_FILE) --parents io.h application.h matrixd.h boundingpolyhedron.h icoloursegmenter.h ifittingalgorithm.h coloursegmenters.h inputassembler.h IAlgorithm.h algorithmprimatte.h ialphalocator.h alphalocator.h inputprocessing.h fittingalgorithms.h spherepolyhedron.h .tmp/Part21.0.0/ && $(COPY_FILE) --parents main.cpp io.cpp application.cpp matrixd.cpp boundingpolyhedron.cpp coloursegmenters.cpp inputassembler.cpp algorithmprimatte.cpp alphalocator.cpp inputprocessing.cpp fittingalgorithms.cpp spherepolyhedron.cpp .tmp/Part21.0.0/ && (cd `dirname .tmp/Part21.0.0` && $(TAR) Part21.0.0.tar Part21.0.0 && $(COMPRESS) Part21.0.0.tar) && $(MOVE) `dirname .tmp/Part21.0.0`/Part21.0.0.tar.gz . && $(DEL_FILE) -r .tmp/Part21.0.0
201 |
202 |
203 | clean:compiler_clean
204 | -$(DEL_FILE) $(OBJECTS)
205 | -$(DEL_FILE) *~ core *.core
206 |
207 |
208 | ####### Sub-libraries
209 |
210 | distclean: clean
211 | -$(DEL_FILE) $(TARGET)
212 | -$(DEL_FILE) Makefile
213 |
214 |
215 | check: first
216 |
217 | mocclean: compiler_moc_header_clean compiler_moc_source_clean
218 |
219 | mocables: compiler_moc_header_make_all compiler_moc_source_make_all
220 |
221 | compiler_moc_header_make_all:
222 | compiler_moc_header_clean:
223 | compiler_rcc_make_all:
224 | compiler_rcc_clean:
225 | compiler_image_collection_make_all: qmake_image_collection.cpp
226 | compiler_image_collection_clean:
227 | -$(DEL_FILE) qmake_image_collection.cpp
228 | compiler_moc_source_make_all:
229 | compiler_moc_source_clean:
230 | compiler_uic_make_all:
231 | compiler_uic_clean:
232 | compiler_yacc_decl_make_all:
233 | compiler_yacc_decl_clean:
234 | compiler_yacc_impl_make_all:
235 | compiler_yacc_impl_clean:
236 | compiler_lex_make_all:
237 | compiler_lex_clean:
238 | compiler_clean:
239 |
240 | ####### Compile
241 |
242 | main.o: main.cpp application.h \
243 | inputassembler.h \
244 | inputprocessing.h \
245 | matrixd.h
246 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp
247 |
248 | io.o: io.cpp io.h
249 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o io.o io.cpp
250 |
251 | application.o: application.cpp application.h \
252 | inputassembler.h \
253 | inputprocessing.h \
254 | matrixd.h \
255 | fittingalgorithms.h \
256 | ifittingalgorithm.h \
257 | spherepolyhedron.h \
258 | io.h \
259 | coloursegmenters.h \
260 | icoloursegmenter.h \
261 | boundingpolyhedron.h \
262 | alphalocator.h \
263 | ialphalocator.h \
264 | algorithmprimatte.h \
265 | IAlgorithm.h
266 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o application.o application.cpp
267 |
268 | matrixd.o: matrixd.cpp matrixd.h
269 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o matrixd.o matrixd.cpp
270 |
271 | boundingpolyhedron.o: boundingpolyhedron.cpp boundingpolyhedron.h \
272 | matrixd.h \
273 | ifittingalgorithm.h \
274 | spherepolyhedron.h \
275 | application.h \
276 | inputassembler.h \
277 | inputprocessing.h \
278 | io.h
279 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o boundingpolyhedron.o boundingpolyhedron.cpp
280 |
281 | coloursegmenters.o: coloursegmenters.cpp coloursegmenters.h \
282 | icoloursegmenter.h \
283 | matrixd.h
284 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o coloursegmenters.o coloursegmenters.cpp
285 |
286 | inputassembler.o: inputassembler.cpp inputassembler.h \
287 | inputprocessing.h \
288 | matrixd.h \
289 | io.h
290 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o inputassembler.o inputassembler.cpp
291 |
292 | algorithmprimatte.o: algorithmprimatte.cpp algorithmprimatte.h \
293 | IAlgorithm.h \
294 | inputassembler.h \
295 | inputprocessing.h \
296 | matrixd.h \
297 | boundingpolyhedron.h \
298 | ifittingalgorithm.h \
299 | spherepolyhedron.h \
300 | application.h \
301 | ialphalocator.h \
302 | icoloursegmenter.h
303 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o algorithmprimatte.o algorithmprimatte.cpp
304 |
305 | alphalocator.o: alphalocator.cpp alphalocator.h \
306 | ialphalocator.h \
307 | boundingpolyhedron.h \
308 | matrixd.h \
309 | ifittingalgorithm.h \
310 | spherepolyhedron.h \
311 | application.h \
312 | inputassembler.h \
313 | inputprocessing.h \
314 | io.h
315 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o alphalocator.o alphalocator.cpp
316 |
317 | inputprocessing.o: inputprocessing.cpp inputprocessing.h \
318 | matrixd.h \
319 | io.h
320 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o inputprocessing.o inputprocessing.cpp
321 |
322 | fittingalgorithms.o: fittingalgorithms.cpp fittingalgorithms.h \
323 | ifittingalgorithm.h \
324 | spherepolyhedron.h \
325 | matrixd.h \
326 | application.h \
327 | inputassembler.h \
328 | inputprocessing.h \
329 | io.h
330 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o fittingalgorithms.o fittingalgorithms.cpp
331 |
332 | spherepolyhedron.o: spherepolyhedron.cpp spherepolyhedron.h \
333 | matrixd.h \
334 | application.h \
335 | inputassembler.h \
336 | inputprocessing.h \
337 | io.h
338 | $(CXX) -c $(CXXFLAGS) $(INCPATH) -o spherepolyhedron.o spherepolyhedron.cpp
339 |
340 | ####### Install
341 |
342 | install: FORCE
343 |
344 | uninstall: FORCE
345 |
346 | FORCE:
347 |
348 |
--------------------------------------------------------------------------------
/Primatte/Primatte.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 | CONFIG += console
3 | QT += opengl xml glviewer
4 |
5 | QT_CONFIG -= no-pkg-config
6 | CONFIG += link_pkgconfig
7 | PKGCONFIG += opencv
8 |
9 | QMAKE_CXXFLAGS += -std=c++0x -Wall
10 | INCLUDEPATH += /usr/include
11 | LIBS += -L/usr/lib
12 | LIBS += -lqglviewer-qt4 -lGLU
13 |
14 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
15 |
16 | TARGET = Part2
17 | TEMPLATE = app
18 |
19 |
20 | SOURCES += main.cpp \
21 | io.cpp \
22 | application.cpp \
23 | matrixd.cpp \
24 | boundingpolyhedron.cpp \
25 | coloursegmenters.cpp \
26 | inputassembler.cpp \
27 | algorithmprimatte.cpp \
28 | alphalocator.cpp \
29 | fittingalgorithms.cpp \
30 | spherepolyhedron.cpp \
31 | averagebackgroundcolourlocators.cpp
32 |
33 | HEADERS += \
34 | io.h \
35 | application.h \
36 | matrixd.h \
37 | icoloursegmenter.h \
38 | ifittingalgorithm.h \
39 | coloursegmenters.h \
40 | inputassembler.h \
41 | algorithmprimatte.h \
42 | ialphalocator.h \
43 | alphalocator.h \
44 | fittingalgorithms.h \
45 | spherepolyhedron.h \
46 | boundingpolyhedron.h \
47 | ialgorithm.h \
48 | averagebackgroundcolourlocators.h \
49 | iaveragebackgroundcolourlocator.h
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Primatte/Primatte.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ProjectExplorer.Project.ActiveTarget
7 | 0
8 |
9 |
10 | ProjectExplorer.Project.EditorSettings
11 |
12 | true
13 | false
14 |
15 | Cpp
16 |
17 | CppGlobal
18 |
19 |
20 |
21 | QmlJS
22 |
23 | QmlJSGlobal
24 |
25 |
26 | 2
27 | System
28 | false
29 | 4
30 | true
31 | 1
32 | true
33 | 0
34 | true
35 | 0
36 | 8
37 | true
38 | 1
39 | true
40 | true
41 | true
42 | false
43 |
44 |
45 |
46 | ProjectExplorer.Project.PluginSettings
47 |
48 |
49 |
50 | ProjectExplorer.Project.Target.0
51 |
52 | Desktop
53 | Desktop
54 | Qt4ProjectManager.Target.DesktopTarget
55 | 1
56 | 0
57 | 0
58 |
59 | ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit./usr/bin/gdb
60 |
61 |
62 | qmake
63 |
64 | QtProjectManager.QMakeBuildStep
65 | false
66 | true
67 |
68 | false
69 |
70 |
71 | Make
72 |
73 | Qt4ProjectManager.MakeStep
74 | false
75 |
76 |
77 |
78 | 2
79 | Build
80 |
81 | ProjectExplorer.BuildSteps.Build
82 |
83 |
84 |
85 | Make
86 |
87 | Qt4ProjectManager.MakeStep
88 | true
89 | clean
90 |
91 |
92 | 1
93 | Clean
94 |
95 | ProjectExplorer.BuildSteps.Clean
96 |
97 | 2
98 | false
99 |
100 | Qt 4.8.1 in PATH (System) Release
101 |
102 | Qt4ProjectManager.Qt4BuildConfiguration
103 | 0
104 | /lhome/vsereda/Linux/Primatte/Primatte-build-desktop-Qt_4_8_1_in_PATH__System__Release
105 | 1
106 | true
107 |
108 |
109 | ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit./usr/bin/gdb
110 |
111 |
112 | qmake
113 |
114 | QtProjectManager.QMakeBuildStep
115 | false
116 | true
117 |
118 | false
119 |
120 |
121 | Make
122 |
123 | Qt4ProjectManager.MakeStep
124 | false
125 |
126 |
127 |
128 | 2
129 | Build
130 |
131 | ProjectExplorer.BuildSteps.Build
132 |
133 |
134 |
135 | Make
136 |
137 | Qt4ProjectManager.MakeStep
138 | true
139 | clean
140 |
141 |
142 | 1
143 | Clean
144 |
145 | ProjectExplorer.BuildSteps.Clean
146 |
147 | 2
148 | false
149 |
150 | Qt 4.8.1 in PATH (System) Debug
151 |
152 | Qt4ProjectManager.Qt4BuildConfiguration
153 | 2
154 | /lhome/vsereda/Linux/Primatte/Primatte-build-desktop-Qt_4_8_1_in_PATH__System__Debug
155 | 1
156 | true
157 |
158 | 2
159 |
160 |
161 | 0
162 | Deploy
163 |
164 | ProjectExplorer.BuildSteps.Deploy
165 |
166 | 1
167 | No deployment
168 |
169 | ProjectExplorer.DefaultDeployConfiguration
170 |
171 | 1
172 |
173 | true
174 | true
175 |
176 |
177 | false
178 | false
179 | false
180 | false
181 | false
182 | false
183 | false
184 | false
185 | true
186 | true
187 | 0.01
188 | 0.01
189 | 10
190 | 10
191 | true
192 | true
193 | 25
194 | 25
195 |
196 |
197 | true
198 | true
199 | valgrind
200 | valgrind
201 |
202 | 0
203 | 1
204 | 2
205 | 3
206 | 4
207 | 5
208 | 6
209 | 7
210 | 8
211 | 9
212 | 10
213 | 11
214 | 12
215 | 13
216 | 14
217 |
218 |
219 | 0
220 | 1
221 | 2
222 | 3
223 | 4
224 | 5
225 | 6
226 | 7
227 | 8
228 | 9
229 | 10
230 | 11
231 | 12
232 | 13
233 | 14
234 |
235 | Primatte
236 |
237 | Qt4ProjectManager.Qt4RunConfiguration
238 | 2
239 |
240 | Primatte.pro
241 | false
242 | true
243 |
244 |
245 | 3768
246 | true
247 | false
248 | false
249 |
250 | 1
251 |
252 |
253 |
254 | ProjectExplorer.Project.TargetCount
255 | 1
256 |
257 |
258 | ProjectExplorer.Project.Updater.EnvironmentId
259 | {2527a1f2-1af4-40d9-a3dc-20297efa4de9}
260 |
261 |
262 | ProjectExplorer.Project.Updater.FileVersion
263 | 10
264 |
265 |
266 |
--------------------------------------------------------------------------------
/Primatte/algorithmprimatte.cpp:
--------------------------------------------------------------------------------
1 | #include "algorithmprimatte.h"
2 | #include "ialphalocator.h"
3 | #include "icoloursegmenter.h"
4 | #include "ifittingalgorithm.h"
5 | #include "inputassembler.h"
6 | #include
7 | #include "io.h"
8 |
9 |
10 | namespace anima
11 | {
12 | namespace alg
13 | {
14 | namespace primatte
15 | {
16 | AlgorithmPrimatte::AlgorithmPrimatte(AlgorithmPrimatteDesc desc)
17 | : mAnalysed(false)
18 | {
19 | //Validate desc
20 | if(!desc.segmenter)
21 | throw std::runtime_error("Null segmenter");
22 |
23 | if(!desc.alphaLocator)
24 | throw std::runtime_error("Null alpha locator");
25 |
26 | if(desc.innerPostShrinkingMultiplier < 0 ||
27 | desc.innerShrinkingMinDistance < 0 ||
28 | desc.innerShrinkingThreshold < 0 ||
29 | desc.outerExpandDelta < 0 ||
30 | desc.outerExpansionStartThreshold < 0 ||
31 | desc.outerScaleParameter <0)
32 | throw std::runtime_error("Algorithm parameter out of range");
33 |
34 | //Try constructing a bounding polyhedron to validate its descriptor
35 | BoundingPolyhedron(desc.boundingPolyhedronDesc);
36 |
37 | //Set desc
38 | mDesc = desc;
39 | }
40 |
41 | void AlgorithmPrimatte::analyse()
42 | {
43 | if(!mInput)
44 | throw std::runtime_error("Using algorithm with null input.");
45 |
46 | //Set up unit polyhedron
47 | BoundingPolyhedron unitPoly (mDesc.boundingPolyhedronDesc);
48 | mPolys[POLY_INNER] = unitPoly;
49 | mPolys[POLY_OUTER] = unitPoly;
50 |
51 | //Fit inner polyhedron around the background points
52 | mPolys[POLY_INNER].fitter()->shrink(
53 | mPolys[POLY_INNER],
54 | mDesc.segmenter->segment(
55 | mInput->backgroundPoints(),
56 | mInput->background(),
57 | mDesc.innerShrinkingThreshold).inner,
58 | mInput->background(),
59 | mDesc.innerShrinkingMinDistance);
60 |
61 | //Scale the inner polyhedron
62 | mPolys[POLY_INNER] = mPolys[POLY_INNER]*mDesc.innerPostShrinkingMultiplier;
63 |
64 | //Ensure that it is greater than the inner polyhedron
65 | float innerPolyhedronMaxSize = mPolys[POLY_INNER].findLargestRadius();
66 | float startRadius = std::max(innerPolyhedronMaxSize, mDesc.outerExpansionStartThreshold);
67 |
68 | //Expand the sphere from the starting radius towards startingRadius+expandDelta
69 | mPolys[POLY_OUTER].fitter()->expand(mPolys[POLY_OUTER],
70 | mInput->points(),
71 | mDesc.segmenter,
72 | mInput->background(),
73 | startRadius,
74 | startRadius+mDesc.outerExpandDelta);
75 |
76 |
77 | //Scale outer if wanted
78 | float maxInnerRadius = mPolys[POLY_INNER].findLargestRadius();
79 | float scale = mPolys[POLY_OUTER].radius() +
80 | (maxInnerRadius-mPolys[POLY_OUTER].radius())*
81 | (1.f-mDesc.outerScaleParameter);
82 | mPolys[POLY_OUTER] = mPolys[POLY_OUTER]*(scale/mPolys[POLY_OUTER].radius());
83 |
84 | mAnalysed = true;
85 | }
86 |
87 | cv::Mat AlgorithmPrimatte::computeAlphas() const
88 | {
89 | if(!mAnalysed)
90 | throw std::runtime_error("Trying to compute alphas with algorithm before input analysis.");
91 | return mDesc.alphaLocator->findAlphas(mPolys, POLY_COUNT, *mInput);
92 | }
93 |
94 | void AlgorithmPrimatte::debugDraw() const
95 | {
96 | for(int i = 0; i < POLY_COUNT; ++i)
97 | mPolys[i].debugDraw(math::vec3((float)((i+2)%4==0), (float)((i+2)%3==0), 0.f));
98 | }
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/Primatte/algorithmprimatte.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "ialgorithm.h"
3 | #include "boundingpolyhedron.h"
4 | #include "inputassembler.h"
5 |
6 | /** This class implements an algorithm inspired by primatte.
7 | Its main purpose is to combine all the other algorithms in the
8 | primatte namespace and provide a single interface.
9 | In it's current form, it's potentially a little unstable as I did not have the time
10 | (or the images) to test it fully. But it seems to work! */
11 | namespace anima
12 | {
13 | //Forward declaration.
14 | namespace ia
15 | {
16 | class InputAssembler;
17 | }
18 |
19 | namespace alg
20 | {
21 | namespace primatte
22 | {
23 | //Forward declaration.
24 | class IFittingAlgorithm;
25 | class IColourSegmenter;
26 | class IAlphaLocator;
27 |
28 | /** The algorithm descriptor to use when creating the algorithm.
29 | You must fill this in entirely and pass it to the constructor. */
30 | struct AlgorithmPrimatteDesc
31 | {
32 | //The following specify sub-algorithms to be used.
33 |
34 | /* The algorithm to use to group clusters of points together. */
35 | IColourSegmenter* segmenter;
36 |
37 | /* The locator used for alpha generation. */
38 | IAlphaLocator* alphaLocator;
39 |
40 | /* The bounding polyhedron descriptor. */
41 | BoundingPolyhedronDescriptor boundingPolyhedronDesc;
42 |
43 | //The following values specify the parameters used by the algorithm.
44 |
45 | //The parameter passed to the colour segmenter when segmenting the background
46 | //points for the inner polyhedron. The segmenter splits the points into Inner
47 | //and Outer, and the Inner points are wrapped around. Should be the approximate
48 | //radius of the sphere inside which the points should be marked as Inner,
49 | //but may be different if you use your own segmenter.
50 | float innerShrinkingThreshold;
51 |
52 | //The minimum size of the inner polyhedron after shrinking.
53 | //Values that are too low may yield in parts of the background being visible.
54 | float innerShrinkingMinDistance;
55 |
56 | //After shrinking, the inner polyhedron is scaled by this amount.
57 | float innerPostShrinkingMultiplier;
58 |
59 | //The foreground pixels are then segmented based on this parameter,
60 | //And the outer polyhedron is positioned around them before expansion.
61 | float outerExpansionStartThreshold;
62 |
63 | //The approximate amount the outer sphere should try to expand.
64 | float outerExpandDelta;
65 |
66 | //The amount the outer sphere should be scaled after expansion relative to
67 | //the inner sphere. It is made so that it never collides with the inner polyhedron,
68 | //such that a value of 0 = as close as possible to inner. A value of 1 = minimal scaling.
69 | //Note that it is relative to the final size of the inner polyhedron.
70 | float outerScaleParameter;
71 |
72 | };
73 |
74 | /** The primatte-inspired algorithm. */
75 | class AlgorithmPrimatte : public IAlgorithm
76 | {
77 | /* The internal sphere ennumerations.
78 | * Warning: Must be in inner->outer order.
79 | * When improving the algorithm, one may wish to use more spheres. */
80 | enum PolyId {POLY_INNER, POLY_OUTER, POLY_COUNT};
81 |
82 | /* The polyhedron objects in inner->outer order. */
83 | BoundingPolyhedron mPolys[POLY_COUNT];
84 |
85 | /* The algorithm descriptor. */
86 | AlgorithmPrimatteDesc mDesc;
87 |
88 | bool mAnalysed;
89 |
90 | public:
91 |
92 | /** Initialises the class, throwing an exception upon failure
93 | * (most commonly std::runtime_error) */
94 | AlgorithmPrimatte(AlgorithmPrimatteDesc desc);
95 |
96 | /** Prepares alpha computation for the given data set by analysing the input. */
97 | virtual void analyse();
98 |
99 | /** Computes the alphas for the given set of points in relation to the
100 | * previously supplied inputs. */
101 | virtual cv::Mat computeAlphas() const;
102 |
103 | /** Uses OpenGL to draw a representation of the internal polyhedrons. */
104 | virtual void debugDraw() const;
105 | };
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/Primatte/alphalocator.cpp:
--------------------------------------------------------------------------------
1 | #include "alphalocator.h"
2 | #include "io.h"
3 | #include "matrixd.h"
4 |
5 | using namespace anima::alg;
6 |
7 |
8 |
9 | namespace anima
10 | {
11 | namespace alg
12 | {
13 | namespace primatte
14 | {
15 | cv::Mat AlphaRayLocator::findAlphas(
16 | const BoundingPolyhedron* polyhedrons,
17 | const size_t polyhedronCount,
18 | const ia::InputAssembler& input) const
19 | {
20 | assert(polyhedronCount>1);
21 | START_TIMER(AlphaLocator);
22 |
23 | const cv::Mat& mat = input.mat();
24 | const unsigned r = input.mat().rows, c = input.mat().cols;
25 | const math::vec3 background = input.background();
26 |
27 | cv::Mat out;
28 | out.create(r, c, CV_32FC1);
29 |
30 | const SpherePolyhedron& outerPoly = polyhedrons[1];
31 | const SpherePolyhedron& innerPoly = polyhedrons[0];
32 |
33 | //For each point, send rays
34 | for (unsigned i = 0; i < r; ++i)
35 | {
36 | float* data = (float*)(mat.data + mat.step*i);
37 | float* dataOut = (float*)(out.data + out.step*i);
38 | for(unsigned j = 0; j < c; ++j)
39 | {
40 | math::vec3& point = *((math::vec3*)(data + j*3));
41 | float alpha;
42 |
43 | //If right in the middle
44 | if(background==point)
45 | alpha = 0;
46 | else
47 | {
48 | //Prepare vector
49 | const math::vec3 vector = point - background;
50 | const float vectorLen = vector.length();
51 | const math::vec3 vectorNorm = vector/vectorLen;
52 | const float distanceToPoint = point.distance(background);
53 |
54 | const float distanceToOuterPoly = outerPoly.findDistanceToPolyhedron(vectorNorm);
55 |
56 | //If inside outer poly, alpha < 1
57 | if(distanceToPoint < distanceToOuterPoly)
58 | {
59 | float distanceToInnerPoly = innerPoly.findDistanceToPolyhedron(vectorNorm);
60 |
61 | //If does not intersect with inner, fully inside
62 | if(distanceToPoint < distanceToInnerPoly)
63 | alpha = 0;
64 | else //interpolate between inner and outer
65 | alpha = (vectorLen - distanceToInnerPoly) /
66 | (distanceToOuterPoly - distanceToInnerPoly);
67 |
68 | }
69 | else //If intersects with middle, it's outside. Alpha = 1.
70 | alpha = 1;
71 | }
72 |
73 | *(dataOut+j) = alpha;
74 | }
75 | }
76 |
77 | END_TIMER(AlphaLocator);
78 |
79 | return out;
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Primatte/alphalocator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "ialphalocator.h"
3 |
4 | namespace anima
5 | {
6 | namespace alg
7 | {
8 | namespace primatte
9 | {
10 | /** Sends out rays to determine the alpha, interpolating between the two
11 | * spheres. It is done so that:
12 | * If outside outer sphere, alpha = 1
13 | * If inside inner sphere, alpha = 0
14 | * If in the middle, interpolate.
15 | * It expects that the bounding polyhedrons are sorted in
16 | * increasing order so that any ray sent is guaranteed that the inner
17 | * intersection is closer than the outer.
18 | * This particular algorithm requires at least two polyhedrons.
19 | * */
20 | class AlphaRayLocator : public IAlphaLocator
21 | {
22 | public:
23 | virtual cv::Mat findAlphas(
24 | const BoundingPolyhedron* polyhedrons,
25 | const size_t polyhedronCount,
26 | const ia::InputAssembler &input) const;
27 | };
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Primatte/application.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "application.h"
4 | #include "matrixd.h"
5 | #include "algorithmprimatte.h"
6 | #include "fittingalgorithms.h"
7 | #include "averagebackgroundcolourlocators.h"
8 | #include "coloursegmenters.h"
9 | #include "alphalocator.h"
10 | #include "io.h"
11 |
12 |
13 | Application::Application() :
14 | mInputAssembler(nullptr),
15 | mAlgorithm(nullptr),
16 | mFitter(nullptr),
17 | mSegmenter(nullptr),
18 | mAlphaLocator(nullptr),
19 | mBackgroundLocator(nullptr) {}
20 |
21 | Application::~Application()
22 | {
23 | delete mBackgroundLocator;
24 | delete mAlphaLocator;
25 | delete mSegmenter;
26 | delete mFitter;
27 | delete mAlgorithm;
28 | delete mInputAssembler;
29 | }
30 |
31 | void Application::timerEvent(QTimerEvent*)
32 | {
33 | update();
34 | }
35 |
36 | void Application::init()
37 | {
38 | try
39 | {
40 | using namespace anima::ia;
41 | using namespace anima::alg::primatte;
42 |
43 | //Restore QGLPreviewer state from last run, such as camera position, etc.
44 | restoreStateFromFile();
45 |
46 | //A scene radius of 1 has some clipping.
47 | this->setSceneRadius(1.5);
48 |
49 | //This makes things difficult to see and interferes with the pixel colours.
50 | glDisable(GL_LIGHTING);
51 |
52 | //Set fps (update every n milliseconds). 16.66... ~ 60fps
53 | mBasicTimer.start(16.66666666, this);
54 |
55 |
56 | Inform("Processing input");
57 |
58 | cv::Mat imageMat = cv::imread("test.jpg");
59 | cv::Mat backgroundMat = cv::imread("test_background.jpg");
60 | if(imageMat.data==nullptr || backgroundMat.data == nullptr)
61 | throw std::runtime_error("Could not load images");
62 |
63 |
64 | START_TIMER(WholeProgramTimer);
65 |
66 | ////////////////////////////////////////////////////////////////////////////
67 | ////////////////////////////// Input Stage /////////////////////////////////
68 | ////////////////////////////////////////////////////////////////////////////
69 |
70 | /* Locates the dominant background colour from the input background image mat. */
71 | mBackgroundLocator = new anima::ia::ABCL_BarycentreBased();
72 |
73 | //This descriptor is used to initialise the input assembler.
74 | InputAssemblerDescriptor iaDesc;
75 |
76 | //Set the background colour locator
77 | iaDesc.backgroundLocator = mBackgroundLocator;
78 |
79 | //Set the image source to be copied from.
80 | //The source mat is converted into floating point values.
81 | //8-bit, 16-bit and floating point formats are supported.
82 | //Expects a 3-component image.
83 | iaDesc.foregroundSource = &imageMat;
84 |
85 | //The background image.
86 | iaDesc.backgroundSource = &backgroundMat;
87 |
88 | //The 3D grid segment count to use for cleaning up duplicate input
89 | //points. Lower values require less memory and filter more aggressively.
90 | iaDesc.ipd.gridSize = 400;
91 |
92 | //The target colour space to convert to.
93 | //Currently can either be RGB, HSV or LAB.
94 | //HSV is unsuitable for blue due to wrap-around!
95 | iaDesc.targetColourspace = InputAssemblerDescriptor::ETCS_RGB;
96 |
97 | //Remove % of points randomly after cleanup to speed up computation.
98 | iaDesc.ipd.randomSimplify = false;
99 | iaDesc.ipd.randomSimplifyPercentage = 30.0;
100 |
101 | //Create the assembler object, load, and process the input.
102 | //An exception will be thrown in case of an error, most likely
103 | //a std::runtime_error.
104 | mInputAssembler = new InputAssembler(iaDesc);
105 |
106 | ////////////////////////////////////////////////////////////////////////////
107 | //////////////////////////// Algorithm Stage ///////////////////////////////
108 | ////////////////////////////////////////////////////////////////////////////
109 | Inform("Creating primatte algorithm");
110 |
111 | //Choose your algorithms:
112 |
113 | /* The fitting algorithm to use. The input is the number of binary iterations
114 | to perform, akin to a binary search algorithm iteration.
115 | 2 is a good number, as it's both accurate and doesn't fit TOO closely, which
116 | can lead to errors due to the sample points being simplified. */
117 | mFitter = new StableFitting(2);
118 |
119 | /* The segmenter algorithm to use. It splits the data points in two based on the parameters.
120 | The distance segmenter splits the input based on whether a point is inside/outside a sphere. */
121 | mSegmenter = new DistanceColourSegmenter();
122 |
123 | /* The alpha interpolation algorithm to use. It is used to compute the alpha for each pixel. */
124 | mAlphaLocator = new AlphaRayLocator();
125 |
126 | //Fill in the algorithm descriptor.
127 | AlgorithmPrimatteDesc algDesc;
128 |
129 | //The fitter algorithm to use.
130 | algDesc.boundingPolyhedronDesc.fitter = mFitter;
131 |
132 | //The number of phi and theta faces for the generated sphere.
133 | //Optimally, there is a ration of 2:1. 16*8 is a 128-faced sphere.
134 | algDesc.boundingPolyhedronDesc.phiFaces = 16;
135 | algDesc.boundingPolyhedronDesc.thetaFaces = 8;
136 |
137 | //The sphere is multiplied by this amount after creation to ensure no
138 | //accidental intersection with the points due to low mesh resolution.
139 | algDesc.boundingPolyhedronDesc.scaleMultiplier = 1.2f;
140 |
141 | //The segmenter splits the points into outer and inner points.
142 | algDesc.segmenter = mSegmenter;
143 |
144 | //The alpha locator is responsible for interpolating and generating the alpha.
145 | algDesc.alphaLocator = mAlphaLocator;
146 |
147 | //The parameter passed to the colour segmenter.
148 | //The inner background points returned are wrapped around.
149 | algDesc.innerShrinkingThreshold = 0.6f;
150 |
151 | //The distance of a shrunken inner vertex from the centre.
152 | algDesc.innerShrinkingMinDistance = 0.001f;
153 |
154 | //After shrinking the inner polyhedron is multiplied by this amount.
155 | algDesc.innerPostShrinkingMultiplier = 1.1f;
156 |
157 | //Passed to the segmenter when positioning outer sphere around inner points before expanding.
158 | //Essentially the start radius of the outer sphere.
159 | algDesc.outerExpansionStartThreshold = 0.15f;
160 |
161 | //The approximate amount the outer sphere should try to expand.
162 | algDesc.outerExpandDelta = 0.075f;
163 |
164 | //The amount the outer sphere should be scaled after expansion relative to
165 | //the inner sphere. It is made so that it never collides with the inner polyhedron,
166 | //such that a value of 0 = as close as possible to inner. A value of 1 = minimal scaling.
167 | //Note that it is relative to the final size of the inner polyhedron.
168 | algDesc.outerScaleParameter = 1.f;
169 |
170 | mAlgorithm = new AlgorithmPrimatte(algDesc);
171 |
172 | Inform("Analysing input");
173 | //Set the new input to be used.
174 | mAlgorithm->setInput(mInputAssembler);
175 |
176 | //Analyse the input. This is a performance-intensive operation.
177 | //In primatte this corresponds to polyhedron deformation.
178 | mAlgorithm->analyse();
179 |
180 |
181 | ////////////////////////////////////////////////////////////////////////////
182 | ///////////////////////// Get and preview result ///////////////////////////
183 | ////////////////////////////////////////////////////////////////////////////
184 |
185 |
186 | Inform("Applying results");
187 | //Apply the polyhedrae to the input image, and save the alpha to result.
188 | cv::Mat result = mAlgorithm->computeAlphas();
189 |
190 | END_TIMER(WholeProgramTimer);
191 |
192 | //Note: This is not part of the algorithm. It's just to preview the result.
193 |
194 | //Display the alpha image
195 | cv::namedWindow("Alpha", cv::WINDOW_AUTOSIZE);
196 | cv::imshow("Alpha", result);
197 |
198 | //Apply the alpha to the original image in order to preview it.
199 | cv::Mat af = imageMat.clone();
200 |
201 | //The background colour to blend with in BGR format.
202 | cv::Vec3f backgroundBlendColour(0,0,1);
203 | cv::Vec3f backgroundInImage(mInputAssembler->background().x,
204 | mInputAssembler->background().y,
205 | mInputAssembler->background().z);
206 |
207 | for(int r = 0; r < af.rows; ++r)
208 | for(int c = 0; c < af.cols; ++c)
209 | {
210 | cv::Vec3b& original = af.at(r,c);
211 | float alpha = result.at(r,c);
212 | cv::Vec3f originalf = original;
213 | originalf *= 1/255.f;
214 |
215 | //Cancel out original background colour from guessed alpha
216 | cv::Vec3f foreground = (originalf - backgroundInImage*(1 - alpha))*(alpha);
217 |
218 | original = (foreground*alpha + backgroundBlendColour*(1.f-alpha))*255;
219 | }
220 |
221 | cv::namedWindow( "AF", cv::WINDOW_AUTOSIZE );
222 | cv::imshow( "AF", af );
223 | }
224 | catch(std::runtime_error err)
225 | {
226 | //If a known error has occured:
227 | Error(err.what());
228 | this->hide();
229 | this->close();
230 | }
231 | catch(...)
232 | {
233 | //If an unknown exception happened:
234 | Error("Something happened");
235 | this->hide();
236 | this->close();
237 | }
238 | }
239 |
240 | //////////////////////////////////////////////////////////////////////////////
241 | /////////////////Below this, it's just for 3D previewing. ////////////////////
242 | //////////////////////////////////////////////////////////////////////////////
243 |
244 | /** This function takes in a normalised colour in linear colourspace and
245 | calls glColour3f with its gamma-corrected version. */
246 | void glColor3fSRGB(float x, float y, float z)
247 | {
248 | glColor3f(pow(x,2.2f),pow(y,2.2f),pow(z,2.2f));
249 | }
250 |
251 | void Application::draw()
252 | {
253 | if(this->isHidden())
254 | return;
255 |
256 | drawBackground();
257 |
258 | //Draw points
259 | glPointSize(5.0);
260 | glLineWidth(2);
261 | glBegin(GL_POINTS);
262 |
263 | //Background points
264 | for(auto it = mInputAssembler->backgroundPoints().begin(); it!=mInputAssembler->backgroundPoints().end(); ++it)
265 | {
266 | glColor3f(1,0,0);
267 | glVertex3f(it->x, it->y, it->z);
268 | }
269 |
270 | //Foreground points
271 | for(auto it = mInputAssembler->points().begin(); it!=mInputAssembler->points().end(); ++it)
272 | {
273 | auto c = mInputAssembler->debugGetPointColour(*it);
274 |
275 | //Swap components because the internal image is in BGR
276 | glColor3fSRGB(c.x,c.y,c.z);
277 |
278 | glVertex3f(it->x, it->y, it->z);
279 | }
280 | glEnd();
281 |
282 | //Draw background point
283 | if(mInputAssembler)
284 | {
285 | glColor3fSRGB(1,0,0);
286 | glPointSize(10.0);
287 | glBegin(GL_POINTS);
288 | auto b = mInputAssembler->background();
289 | glVertex3f(b.x,b.y,b.z);
290 | glEnd();
291 | }
292 |
293 | //Draw algorithm
294 | glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
295 | if(mAlgorithm)
296 | mAlgorithm->debugDraw();
297 | glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
298 |
299 | glPointSize(5.0);
300 | }
301 |
302 | void Application::drawBackground()
303 | {
304 | float c1r = 0.95, c1g = 0.95, c1b = 0.95;
305 | float c2r = 0.4, c2g = 0.6, c2b = 0.4;
306 |
307 | //Push
308 | glMatrixMode(GL_PROJECTION);
309 | glPushMatrix();
310 | glLoadIdentity();
311 | glMatrixMode(GL_MODELVIEW);
312 | glPushMatrix();
313 | glLoadIdentity();
314 |
315 | //Draw
316 | glBegin(GL_QUADS);
317 | //c1
318 | glColor3fSRGB(c1r,c1g,c1b);
319 | glVertex2f(1.0, 1.0);
320 | glVertex2f(-1.0,1.0);
321 | //c2
322 | glColor3fSRGB(c2r,c2g,c2b);
323 | glVertex2f(-1.0,-1.0);
324 | glVertex2f(1.0, -1.0);
325 | glEnd();
326 |
327 | //Pop
328 | glPopMatrix();
329 | glMatrixMode(GL_MODELVIEW);
330 | glPopMatrix();
331 | glMatrixMode(GL_PROJECTION);
332 | glPopMatrix();
333 | glClear(GL_DEPTH_BUFFER_BIT);
334 | }
335 |
336 | QString Application::helpString() const
337 | {
338 | QString text("S i m p l e V i e w e r
");
339 | text += "Use the mouse to move the camera around the object. ";
340 | text += "You can respectively revolve around, zoom and translate with the three mouse buttons. ";
341 | text += "Left and middle buttons pressed together rotate around the camera view direction axis
";
342 | text += "Pressing Alt and one of the function keys (F1..F12) defines a camera keyFrame. ";
343 | text += "Simply press the function key again to restore it. Several keyFrames define a ";
344 | text += "camera path. Paths are saved when you quit the application and restored at next start.
";
345 | text += "Press F to display the frame rate, A for the world axis, ";
346 | text += "Alt+Return for full screen mode and Control+S to save a snapshot. ";
347 | text += "See the Keyboard tab in this window for a complete shortcut list.
";
348 | text += "Double clicks automates single click actions: A left button double click aligns the closer axis with the camera (if close enough). ";
349 | text += "A middle button double click fits the zoom of the camera and the right button re-centers the scene.
";
350 | text += "A left button double click while holding right button pressed defines the camera Revolve Around Point. ";
351 | text += "See the Mouse tab and the documentation web pages for details.
";
352 | text += "Press Escape to exit the Application.";
353 | return text;
354 | }
355 |
--------------------------------------------------------------------------------
/Primatte/application.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | //Forward declarations
6 | namespace anima
7 | {
8 | namespace alg
9 | {
10 | class IAlgorithm;
11 |
12 | namespace primatte
13 | {
14 | class IColourSegmenter;
15 | class IFittingAlgorithm;
16 | class IAlphaLocator;
17 | }
18 | }
19 | namespace ia
20 | {
21 | class InputAssembler;
22 | class IAverageBackgroundColourLocator;
23 | }
24 | }
25 |
26 | /** The main application class. It is to be replaced in the future by a proper
27 | * driver. Currently it reads the input from a file called "test.bmp" and
28 | * supplies it to the algorithm, which in itself is a general system.
29 | */
30 | class Application: public QGLViewer
31 | {
32 | public:
33 | /** Initialises variables to null. */
34 | Application();
35 |
36 | /** Deletes internal pointers. */
37 | ~Application();
38 |
39 | /** Draws a preview of the scene. */
40 | virtual void draw();
41 |
42 | /** Draws the background plane. Used by draw(). */
43 | void drawBackground();
44 |
45 | /** Gathers input and runs the algorithm. */
46 | virtual void init();
47 |
48 | /** Used by qglviewer to provide a help string during preview. */
49 | virtual QString helpString() const;
50 |
51 | /* The input data structure. */
52 | anima::ia::InputAssembler* mInputAssembler;
53 |
54 | /* The currently used algorithm (only primatte available). */
55 | anima::alg::IAlgorithm* mAlgorithm;
56 |
57 | //Subalgorithms:
58 |
59 | /* The fitting algorithm to use. */
60 | anima::alg::primatte::IFittingAlgorithm* mFitter;
61 |
62 | /* The segmenter algorithm to use. */
63 | anima::alg::primatte::IColourSegmenter* mSegmenter;
64 |
65 | /* The alpha interpolation algorithm to use. */
66 | anima::alg::primatte::IAlphaLocator* mAlphaLocator;
67 |
68 | /* Finds the dominant background colour. */
69 | anima::ia::IAverageBackgroundColourLocator* mBackgroundLocator;
70 |
71 | /* Handles debug preview fps. */
72 | QBasicTimer mBasicTimer;
73 |
74 | /** Called on every timer tick: updates the frame. */
75 | void timerEvent(QTimerEvent*);
76 |
77 | };
78 |
--------------------------------------------------------------------------------
/Primatte/averagebackgroundcolourlocators.cpp:
--------------------------------------------------------------------------------
1 | #include "averagebackgroundcolourlocators.h"
2 | #include "io.h"
3 |
4 | namespace anima
5 | {
6 | namespace ia
7 | {
8 | math::vec3 ABCL_BarycentreBased::findColour(const cv::Mat& mat) const
9 | {
10 | int r = mat.rows, c = mat.cols, s = mat.step;
11 |
12 | math::vec3 background;
13 |
14 | for (int i = 0; i < r; ++i)
15 | {
16 | float* data = (float*)(mat.data + s*i);
17 |
18 | for(int j = 0; j < c; ++j)
19 | {
20 | math::vec3& v = *((math::vec3*)(data + j*3));
21 | background+=v;
22 | }
23 | }
24 |
25 | background/=r*c;
26 | return background;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Primatte/averagebackgroundcolourlocators.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "iaveragebackgroundcolourlocator.h"
3 |
4 | namespace anima
5 | {
6 | namespace ia
7 | {
8 | /** Chooses the average background colour as the barycentre of all points. */
9 | class ABCL_BarycentreBased : public IAverageBackgroundColourLocator
10 | {
11 | public:
12 | virtual math::vec3 findColour(const cv::Mat& mat) const;
13 |
14 | };
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Primatte/boundingpolyhedron.cpp:
--------------------------------------------------------------------------------
1 | #include "boundingpolyhedron.h"
2 | #include "io.h"
3 | #include "stdlib.h"
4 | #include
5 | #include
6 | #include "ifittingalgorithm.h"
7 |
8 | namespace anima
9 | {
10 | namespace alg
11 | {
12 | namespace primatte
13 | {
14 | BoundingPolyhedron::BoundingPolyhedron(BoundingPolyhedronDescriptor desc)
15 | : SpherePolyhedron(desc.phiFaces, desc.thetaFaces)
16 | {
17 | if(desc.fitter==nullptr)
18 | throw std::runtime_error("Null fitter");
19 |
20 | if(desc.scaleMultiplier < 0)
21 | throw std::runtime_error("Negative bounding polyhedron scale multiplier");
22 |
23 | mDesc = desc;
24 |
25 | mInitialised = true;
26 | }
27 |
28 | //Adapted from http://stackoverflow.com/a/24818473
29 | std::pair calculateBoundSphere(const std::vector& vertices)
30 | {
31 | math::vec3 center = vertices[0];
32 | float radius = 0.0001f;
33 | float len, alpha, alphaSq;
34 |
35 | for (int i = 0; i < 2; i++)
36 | {
37 | for (auto it = vertices.begin(); it != vertices.end(); it++)
38 | {
39 | math::vec3 pos = *it;
40 | math::vec3 diff = pos - center;
41 | len = diff.length();
42 | if (len > radius)
43 | {
44 | alpha = len / radius;
45 | alphaSq = alpha * alpha;
46 | radius = 0.5f * (alpha + 1 / alpha) * radius;
47 | center =(center * (1 + 1 / alphaSq)+ pos*(1 - 1 / alphaSq)) * 0.5f;
48 | }
49 | }
50 | }
51 |
52 | for (auto it = vertices.begin(); it != vertices.end(); it++)
53 | {
54 | math::vec3 diff = *it - center;
55 | len = diff.length();
56 | if (len > radius)
57 | {
58 | radius = (radius + len) / 2.0f;
59 | center = center + diff * ((len - radius) / len);
60 | }
61 | }
62 |
63 | return std::make_pair(center, radius);
64 | }
65 |
66 |
67 | void BoundingPolyhedron::positionAround(const math::vec3 desiredCentre, const std::vector& points)
68 | {
69 | if(!mInitialised)
70 | throw::std::runtime_error("Using uninitialised bounding polyhedron");
71 |
72 | if(points.size()==0)
73 | return;
74 |
75 | auto bounding = calculateBoundSphere(points);
76 |
77 | float radius = (bounding.second + desiredCentre.distance(bounding.first))*mDesc.scaleMultiplier;
78 | setCentreAndRadius(desiredCentre, radius);
79 | }
80 |
81 | BoundingPolyhedron BoundingPolyhedron::operator * (const float scale)
82 | {
83 | BoundingPolyhedron out = *this;
84 | for(auto it = out.mVertices.begin(); it!=out.mVertices.end(); ++it)
85 | *it = (*it-mCentre)*scale+mCentre;
86 | out.mRadius *= scale;
87 | return out;
88 | }
89 |
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Primatte/boundingpolyhedron.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "matrixd.h"
3 | #include "spherepolyhedron.h"
4 |
5 | /** A polyhedron object that's capable of wrapping itself around a set of points. */
6 | namespace anima
7 | {
8 | namespace alg
9 | {
10 | namespace primatte
11 | {
12 | class IFittingAlgorithm;
13 |
14 | /** The descriptor used to create the polyhedron. */
15 | struct BoundingPolyhedronDescriptor
16 | {
17 | /* Number of faces around the up axis to have. Must be > 3 */
18 | int phiFaces;
19 |
20 | /* The number of horizontal faces to have. Must be > 2 */
21 | int thetaFaces;
22 |
23 | /* The polyhedron is scaled by this factor after being positioned. Must be positive. */
24 | float scaleMultiplier;
25 |
26 | /* The fitting algorithm to use to fit the polyhedron around the points. */
27 | IFittingAlgorithm* fitter;
28 | };
29 |
30 | class BoundingPolyhedron : public SpherePolyhedron
31 | {
32 | private:
33 | /* The descriptor object. */
34 | BoundingPolyhedronDescriptor mDesc;
35 |
36 | /* Indicates whether the polyhedron is initialised.
37 | * Only initialised polyhedrons may be used after creation. */
38 | bool mInitialised;
39 |
40 | public:
41 | /** Constructs an uninitialised object. */
42 | BoundingPolyhedron() : mInitialised(false) {}
43 |
44 | /** Constructs the object from the descriptor. */
45 | BoundingPolyhedron(BoundingPolyhedronDescriptor desc);
46 |
47 | /** Positions the polyhedral sphere around the points,
48 | * only using linear transformations.
49 | * @param points The points around which to position the
50 | polyhedron.
51 | */
52 | void positionAround(const math::vec3 desiredCentre, const std::vector& points);
53 |
54 | IFittingAlgorithm* fitter() { return mDesc.fitter; }
55 |
56 | /** Returns a copy of the polyhedron scaled around the centre */
57 | BoundingPolyhedron operator * (const float scale);
58 | };
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Primatte/coloursegmenters.cpp:
--------------------------------------------------------------------------------
1 | #include "coloursegmenters.h"
2 | #include "io.h"
3 | namespace anima
4 | {
5 | namespace alg
6 | {
7 | namespace primatte
8 | {
9 | SegmenterResult DistanceColourSegmenter::segment(const std::vector &points,
10 | const math::vec3 reference,
11 | float approximateRadius) const
12 | {
13 | SegmenterResult out;
14 |
15 | float radiusSquared = approximateRadius*approximateRadius;
16 |
17 | for(auto it = points.begin(); it!=points.end(); ++it)
18 | {
19 | if(reference.distanceSquared(*it) <= radiusSquared)
20 | out.inner.push_back(*it);
21 | else
22 | out.outer.push_back(*it);
23 | }
24 | return out;
25 | }
26 |
27 |
28 | // std::pair,std::vector >
29 | // DistanceColourSegmenter::segment(const std::vector& points,
30 | // const math::vec3 background,
31 | // float approximateRadius) const
32 | // {
33 | // std::vector outer, inner;
34 |
35 | // float radiusSquared = approximateRadius*approximateRadius;
36 |
37 | // for(auto it = points.begin(); it!=points.end(); ++it)
38 | // {
39 | // if(background.distanceSquared(*it) <= radiusSquared)
40 | // inner.push_back(*it);
41 | // else
42 | // outer.push_back(*it);
43 | // }
44 | // return std::make_pair(outer, inner);
45 | // }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Primatte/coloursegmenters.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "icoloursegmenter.h"
3 |
4 | /* A series of classes implementing the IColourSegmenter interface. */
5 |
6 | namespace anima
7 | {
8 | namespace alg
9 | {
10 | namespace primatte
11 | {
12 | /** This class segments colours according to distance,
13 | * cutting off the points that are too far away. */
14 | class DistanceColourSegmenter : public IColourSegmenter
15 | {
16 | public:
17 | virtual SegmenterResult segment(const std::vector& points,
18 | const math::vec3 reference,
19 | float approximateRadius) const;
20 | };
21 |
22 | // class DistanceColourSegmenter : public IColourSegmenter
23 | // {
24 | // virtual std::pair,std::vector >
25 | // segment(const std::vector& points,
26 | // const math::vec3 background,
27 | // float approximateRadius) const;
28 | // };
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Primatte/fittingalgorithms.cpp:
--------------------------------------------------------------------------------
1 | #include "fittingalgorithms.h"
2 | #include "io.h"
3 | #include "icoloursegmenter.h"
4 |
5 | namespace anima
6 | {
7 | namespace alg
8 | {
9 | namespace primatte
10 | {
11 | unsigned StableFitting::countPointsInside(const std::vector& points, BoundingPolyhedron& poly)
12 | {
13 | int pointsInside = 0;
14 | for(auto itPoint = points.begin(); itPoint != points.end(); ++itPoint)
15 | {
16 | //If intersects
17 | math::vec3 vector = *itPoint - poly.centre();
18 | float vectorLen = vector.length();
19 | math::vec3 vectorNorm = vector/vectorLen;
20 |
21 | if(poly.findDistanceToPolyhedron(vectorNorm) >= vectorLen)
22 | ++pointsInside;
23 | }
24 | return pointsInside;
25 | }
26 |
27 | void StableFitting::shrink(BoundingPolyhedron& poly,
28 | const std::vector& points,
29 | math::vec3 backgroundPoint,
30 | float minimumDistance) const
31 | {
32 | START_TIMER(Shrinking);
33 |
34 | poly.positionAround(backgroundPoint, points);
35 |
36 | float step = poly.radius()/2.f;
37 |
38 | float minDistanceSquared = minimumDistance*minimumDistance;
39 |
40 | int originalPointsInside = countPointsInside(points, poly);
41 |
42 | for(int iIteration = 0; iIteration < mNoOfIterations; ++iIteration)
43 | {
44 | float stepSquared = step*step;
45 |
46 | for(auto vertex = poly.mVertices.rbegin(); vertex!=poly.mVertices.rend(); ++vertex)
47 | {
48 | //If too close, or move distance too great
49 | const float distanceCentreToVertex = poly.centre().distanceSquared(*vertex);
50 | if(distanceCentreToVertex < minDistanceSquared || distanceCentreToVertex < stepSquared)
51 | continue;
52 |
53 | math::vec3 moveNormal = (poly.centre() - *vertex).normalize();
54 | const math::vec3 vec = moveNormal*step;
55 |
56 | //Move
57 | *vertex += vec;
58 |
59 | int newPointsInside = countPointsInside(points, poly);
60 |
61 | //Move back if movement violates rule
62 | if(newPointsInside& points, IColourSegmenter* segmenter,
74 | math::vec3 backgroundPoint, float startRadius, float endRadius) const
75 | {
76 |
77 | START_TIMER(Expanding);
78 |
79 | auto innerouter = segmenter->segment(points, backgroundPoint, startRadius);
80 |
81 | //Indicates whether a vertex was unable to move at least once due to outer points.
82 | std::vector didVertexEncounterResistance;
83 | didVertexEncounterResistance.resize(poly.mVertices.size(), false);
84 |
85 | //Position the polygon around the inner points.
86 | poly.positionAround(backgroundPoint, innerouter.inner);
87 |
88 | //Make a copy that is to be scaled.
89 | //We need a copy to deal with the case where no resistance is met.
90 | BoundingPolyhedron newPoly = poly;
91 |
92 | //The starting step is set to be half way between the start and end distance.
93 | float step = (endRadius-startRadius)/2.f;
94 |
95 | //Count number of points outside for later reference.
96 | int originalPointsOutside = innerouter.outer.size()-countPointsInside(innerouter.outer, newPoly);
97 |
98 | //Iterate...
99 | for(int iIteration = 0; iIteration < mNoOfIterations; ++iIteration)
100 | {
101 | //Try moving each vertex outwards
102 | for(size_t iVertex = 0; iVertex < newPoly.mVertices.size(); ++iVertex)
103 | {
104 | //Find movement vector
105 | math::vec3 moveNormal = (newPoly.mVertices[iVertex]-newPoly.centre()).normalize();
106 | const math::vec3 vec = moveNormal*step;
107 |
108 | //Move
109 | newPoly.mVertices[iVertex] += vec;
110 |
111 | //Find the number of points now outside after movement.
112 | int newPointsOutside = innerouter.outer.size()-countPointsInside(innerouter.outer, newPoly);
113 |
114 | //If there are now less points outside, we have gone through something. Move back and mark resistance.
115 | if(newPointsOutside < originalPointsOutside)
116 | {
117 | newPoly.mVertices[iVertex] -= vec;
118 | didVertexEncounterResistance[iVertex] = true;
119 | }
120 | }
121 |
122 | //halve the step and try again.
123 | step *= 0.5f;
124 | }
125 |
126 | //The idea here is that if a vertex did not encounter any resistance while moving,
127 | //Move it by the maximin movement of the vertices that _did_ encounter resistance.
128 |
129 | //You might try replacing maximum with mode, etc. (mean gave really low deltas)
130 |
131 | //Find max movement of vertices that found resistance:
132 | float maxMovement = poly.mVertices[0].distance(newPoly.mVertices[0]);
133 | for(size_t i = 1; i < didVertexEncounterResistance.size(); ++i)
134 | maxMovement = std::max(maxMovement,
135 | poly.mVertices[i].distance(newPoly.mVertices[i]));
136 |
137 |
138 |
139 | //If a vertex found resistance, keep it. Otherwise, restore it and move by the average.
140 | for(size_t i = 0; i < didVertexEncounterResistance.size(); ++i)
141 | if(didVertexEncounterResistance[i])
142 | poly.mVertices[i] = newPoly.mVertices[i];
143 | else
144 | poly.mVertices[i] = poly.mVertices[i]+(newPoly.mVertices[i]-poly.mVertices[i]).normalize()*maxMovement;
145 |
146 | END_TIMER(Expanding);
147 | }
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Primatte/fittingalgorithms.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "ifittingalgorithm.h"
3 |
4 | /*
5 | * Various polyhedron fitting algorithms implementing the IFittingAlgorithm interface.
6 | */
7 | namespace anima
8 | {
9 | namespace alg
10 | {
11 | namespace primatte
12 | {
13 | /** Use exact fitting by trying to move points inside/outside while possible.
14 | Points are guaranteed to not go through the polyhedron.
15 | An alternative to try out might be to allow for a certain number of points to be ignored,
16 | reducing outlier effect. */
17 | class StableFitting : public IFittingAlgorithm
18 | {
19 | //Number of iterations to perform.
20 | int mNoOfIterations;
21 |
22 | /** Counts the number of points from the points vector that are inside the bounding polyhedron. */
23 | static unsigned countPointsInside(const std::vector& points, BoundingPolyhedron& poly);
24 |
25 | public:
26 |
27 | StableFitting(int numberOfIterations) : mNoOfIterations(numberOfIterations){}
28 |
29 | virtual void shrink(BoundingPolyhedron& poly, const std::vector& points, math::vec3 backgroundPoint, float minimumDistance) const;
30 | virtual void expand(BoundingPolyhedron& poly, const std::vector& points, IColourSegmenter* segmenter, math::vec3 backgroundPoint, float startingRadius, float maximumRadius) const;
31 | }; //End of class
32 |
33 | /** Does nothing */
34 | class NoFitting : public IFittingAlgorithm
35 | {
36 | public:
37 | virtual void shrink(BoundingPolyhedron&, const std::vector&, math::vec3, float) const {}
38 | virtual void expand(BoundingPolyhedron&, const std::vector&, IColourSegmenter*, math::vec3, float, float) const {}
39 | }; //End of class
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Primatte/ialgorithm.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include "inputassembler.h"
5 |
6 | namespace anima
7 | {
8 | namespace alg
9 | {
10 | /** An abstract class that defines the basic functionality required by an algorithm.
11 | * Deviates towards an abstract class by implementing basic functionality for convenience. */
12 | class IAlgorithm
13 | {
14 | protected:
15 |
16 | const ia::InputAssembler* mInput;
17 | public:
18 |
19 | /** Trivial virtual destructor */
20 | virtual ~IAlgorithm() {}
21 |
22 | /** Sets the current input. */
23 | virtual void setInput(const ia::InputAssembler* input)
24 | {
25 | mInput = input;
26 | }
27 |
28 | /** Prepares alpha computation for the given data set. Needed for debug draw.
29 | * Example activity might be collapsing polyhedrons around the input points.
30 | Must set mPrepared=when done. */
31 | virtual void analyse() = 0;
32 |
33 | /** Computes the alpha for the internal input.*/
34 | virtual cv::Mat computeAlphas() const = 0;
35 |
36 | /** Draws a 3D representation of the algorithm. */
37 | virtual void debugDraw() const = 0;
38 | };
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Primatte/ialphalocator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "boundingpolyhedron.h"
3 | #include
4 | #include
5 | #include "inputassembler.h"
6 |
7 | /**
8 | * Given n polyhedrons, a background centre point and a list of points,
9 | * return a vector of alphas corresponding to the list of points
10 | * in relation to the background point.
11 | */
12 |
13 | namespace anima
14 | {
15 | namespace alg
16 | {
17 | namespace primatte
18 | {
19 | class IAlphaLocator
20 | {
21 | public:
22 |
23 | virtual ~IAlphaLocator(){}
24 |
25 | /** Calculates the alpha for a set of points.
26 | * @param polyhedrons The polyhedrons usd by primatte
27 | ordered from inner to outer.
28 | * @param polyhedronCount The number of polyhedrons.
29 | * @param input The initialised input structure.
30 | */
31 | virtual cv::Mat findAlphas(
32 | const BoundingPolyhedron* polyhedrons,
33 | const size_t polyhedronCount,
34 | const ia::InputAssembler &input) const = 0;
35 | };
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Primatte/iaveragebackgroundcolourlocator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "matrixd.h"
4 | /** Given an F32 mat of background colours, this class must calculate
5 | * the most dominant colour and return it.
6 | */
7 |
8 | namespace anima
9 | {
10 | namespace ia
11 | {
12 | class IAverageBackgroundColourLocator
13 | {
14 | public:
15 | virtual ~IAverageBackgroundColourLocator(){}
16 | virtual math::vec3 findColour(const cv::Mat& mat) const = 0;
17 | };
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Primatte/icoloursegmenter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "matrixd.h"
3 | #include
4 | /**
5 | * Given a vector of points, this class must return a subset of those points.
6 | * based on their distance from a background point.
7 | * It essentially choose the points against which the polyhedrons must be fitted.
8 | */
9 |
10 | namespace anima
11 | {
12 | namespace alg
13 | {
14 | namespace primatte
15 | {
16 | struct SegmenterResult
17 | {
18 | //The points chosen to be outside.
19 | std::vector outer;
20 |
21 | //The points chosen to be inside.
22 | std::vector inner;
23 |
24 | //The union of these two constitutes the input points to the segmenter.
25 | };
26 |
27 |
28 | class IColourSegmenter
29 | {
30 | public:
31 |
32 | virtual ~IColourSegmenter(){}
33 |
34 | /** Computes the subset.
35 | * @param points The points the subset of which is to be found.
36 | * @param background The point around which to find the subset.
37 | * @param approximateRadius Loosely-defined cut-off point.
38 | */
39 | virtual SegmenterResult segment(const std::vector& points,
40 | const math::vec3 background,
41 | float approximateRadius) const = 0;
42 | };
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Primatte/ifittingalgorithm.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "boundingpolyhedron.h"
3 | #include "matrixd.h"
4 |
5 | /** An interface defining the functionality needed by an algorithm that
6 | * fits a polyhedron (that's assumed to be around the points) tightly
7 | * around some points.
8 | * IMPORTANT: The algorithm must guarantee that any vertex moved is moved
9 | * on a line between it and the centre of the polyhedron.
10 | * This is the requirement for fast triangle-ray intersections.
11 | */
12 | namespace anima
13 | {
14 | namespace alg
15 | {
16 | namespace primatte
17 | {
18 | class IColourSegmenter;
19 |
20 | class IFittingAlgorithm
21 | {
22 | public:
23 | virtual ~IFittingAlgorithm(){}
24 |
25 | /** Fits the polyhedron around the points.
26 | * @param poly The polyhedron to be shrunk.
27 | * @param points The points around which to shrink.
28 | * @param minimumDistance The minimum distance of a vertex to the centre.
29 | */
30 | virtual void shrink(BoundingPolyhedron& poly, const std::vector& points, math::vec3 backgroundPoint,
31 | float minimumDistance) const = 0;
32 |
33 | /** Fits the polyhedron around the points.
34 | * @param poly The polyhedron to be expanded.
35 | * @param points The points inside which to expand.
36 | * @param segmenter The segmenter to use when determining inner/outer points before expansion.
37 | * @param maximumDistance The maximum distance of a vertex from the centre.
38 | */
39 | virtual void expand(BoundingPolyhedron& poly, const std::vector& points, IColourSegmenter* segmenter,
40 | math::vec3 backgroundPoint, float startingRadius, float maximumRadius) const = 0;
41 | };
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Primatte/inputassembler.cpp:
--------------------------------------------------------------------------------
1 | #include "inputassembler.h"
2 | #include "matrixd.h"
3 | #include "io.h"
4 | #include
5 | #include
6 | #include "iaveragebackgroundcolourlocator.h"
7 |
8 | namespace anima
9 | {
10 | namespace ia
11 | {
12 | std::vector RemoveDuplicatesWithGrid(const cv::Mat& mat, unsigned gridSize)
13 | {
14 | START_TIMER(CleaningWithGrid);
15 |
16 | assert(mat.type() == CV_32FC3);
17 | const unsigned r = mat.rows, c = mat.cols;
18 |
19 | std::vector points;
20 | points.reserve(r*c/50);
21 |
22 | const unsigned gridCubed = gridSize*gridSize*gridSize;
23 | const unsigned gridSizeMinusOne = gridSize-1;
24 |
25 | bool* grid = new(std::nothrow) bool[gridCubed]();
26 |
27 | if(!grid)
28 | throw std::runtime_error("Unable to allocate 3D grid for input processing");
29 |
30 | for (unsigned i = 0; i < r; ++i)
31 | {
32 | float* data = (float*)(mat.data + mat.step*i);
33 | for(unsigned j = 0; j < c; ++j)
34 | {
35 | math::vec3& p = *((math::vec3*)(data + j*3));
36 | math::vec3i pi(p.x*gridSize,p.y*gridSize,p.z*gridSize);
37 | if(unsigned(pi.x) >= gridSize)
38 | pi.x = gridSizeMinusOne;
39 | if(unsigned(pi.y) >= gridSize)
40 | pi.y = gridSizeMinusOne;
41 | if(unsigned(pi.z) >= gridSize)
42 | pi.z = gridSizeMinusOne;
43 |
44 | bool& b = grid[pi.x + gridSize*(pi.y + gridSize*pi.z)];
45 | if (!b)
46 | {
47 | b = true;
48 | points.push_back(p);
49 | }
50 | }
51 | }
52 |
53 | delete[] grid;
54 |
55 | END_TIMER(CleaningWithGrid);
56 |
57 | return points;
58 | }
59 |
60 | void RandomSimplify(std::vector* points, float percentageToRemove)
61 | {
62 | START_TIMER(RandomSimplifying);
63 | size_t initialSize = points->size();
64 |
65 | std::random_device rd;
66 | std::mt19937 random(rd());
67 | std::shuffle(points->begin(), points->end(), random);
68 |
69 | points->erase(points->begin()+(int)(points->size()*(1.f-percentageToRemove/100.f)), points->end());
70 |
71 | Inform("" + ToString(points->size()/float(initialSize)*100) + "% of points remain (" +
72 | ToString(points->size()) + "/" + ToString(initialSize)+")");
73 |
74 | END_TIMER(RandomSimplifying);
75 | }
76 |
77 | float InputAssembler::normalisationMultiplier(int cvCode)
78 | {
79 | switch(cvCode)
80 | {
81 | case CV_8UC3:
82 | return 1.0/255.0;
83 | case CV_16UC3:
84 | return 1.0/65535.0;
85 | case CV_32FC3:
86 | return 1.0;
87 | default:
88 | throw std::runtime_error("Unknown format in input assember at line " + ToString(__LINE__));
89 | }
90 | assert(0);
91 | }
92 |
93 | InputAssembler::InputAssembler(InputAssemblerDescriptor& desc)
94 | {
95 | START_TIMER(ProcessingInput);
96 | //Convert the input into 3 component float mat.
97 | if(desc.foregroundSource == nullptr)
98 | throw std::runtime_error("Null source foreground Mat");
99 |
100 | if(desc.backgroundSource == nullptr)
101 | throw std::runtime_error("Null source background mat");
102 |
103 | if(desc.backgroundLocator == nullptr)
104 | throw std::runtime_error("Null background colour locator");
105 |
106 | if(!desc.ipd.validate())
107 | throw std::runtime_error("Could not validate input processor.");
108 |
109 | if(desc.foregroundSource->cols*desc.foregroundSource->rows==0)
110 | throw std::runtime_error("Empty foreground source.");
111 |
112 | if(desc.backgroundSource->cols*desc.backgroundSource->rows==0)
113 | throw std::runtime_error("Empty background source.");
114 |
115 |
116 | desc.foregroundSource->convertTo(mForegroundF, CV_32FC3,
117 | normalisationMultiplier(desc.foregroundSource->type()));
118 | desc.backgroundSource->convertTo(mBackgroundF, CV_32FC3,
119 | normalisationMultiplier(desc.backgroundSource->type()));
120 |
121 | //Convert everything to the appropriate colour space:
122 | mColourSpace = desc.targetColourspace;
123 |
124 | switch(desc.targetColourspace)
125 | {
126 | case InputAssemblerDescriptor::ETCS_RGB:
127 | break;
128 | case InputAssemblerDescriptor::ETCS_HSV:
129 | cv::cvtColor(mForegroundF, mForegroundF, CV_RGB2HSV);
130 | cv::cvtColor(mBackgroundF, mBackgroundF, CV_RGB2HSV);
131 |
132 | //Normalise hue:
133 | for (int i = 0; i < mForegroundF.rows; ++i)
134 | {
135 | float* data = (float*)(mForegroundF.data + mForegroundF.step*i);
136 | for(int j = 0; j < mForegroundF.cols; ++j)
137 | *(data + j*3)/=360.f;
138 | }
139 | for (int i = 0; i < mBackgroundF.rows; ++i)
140 | {
141 | float* data = (float*)(mBackgroundF.data + mBackgroundF.step*i);
142 | for(int j = 0; j < mBackgroundF.cols; ++j)
143 | *(data + j*3)/=360.f;
144 | }
145 | break;
146 | case InputAssemblerDescriptor::ETCS_LAB:
147 | cv::cvtColor(mForegroundF, mForegroundF, CV_RGB2Lab);
148 | cv::cvtColor(mBackgroundF, mBackgroundF, CV_RGB2Lab);
149 |
150 | //Get into proper range
151 | for (int i = 0; i < mForegroundF.rows; ++i)
152 | {
153 | float* data = (float*)(mForegroundF.data + mForegroundF.step*i);
154 | for(int j = 0; j < mForegroundF.cols; ++j)
155 | {
156 | math::vec3& p = *((math::vec3*)(data + j*3));
157 | p = math::vec3(p.x, (p.y+127.f), (p.z+127.f))/254.f;
158 | }
159 | }
160 | for (int i = 0; i < mBackgroundF.rows; ++i)
161 | {
162 | float* data = (float*)(mBackgroundF.data + mBackgroundF.step*i);
163 | for(int j = 0; j < mBackgroundF.cols; ++j)
164 | {
165 | math::vec3& p = *((math::vec3*)(data + j*3));
166 | p = math::vec3(p.x, (p.y+127.f), (p.z+127.f))/254.f;
167 | }
168 | }
169 | break;
170 | }
171 |
172 | //Convert mat to vector, and clean:
173 | mPoints = RemoveDuplicatesWithGrid(mForegroundF, desc.ipd.gridSize);
174 | mBackgroundPoints = RemoveDuplicatesWithGrid(mBackgroundF, desc.ipd.gridSize);
175 |
176 | //Find dominant background colour:
177 | mBackground = desc.backgroundLocator->findColour(mBackgroundF);
178 |
179 | //Simplify randomly if needed:
180 | if(desc.ipd.randomSimplify)
181 | {
182 | RandomSimplify(&mPoints, desc.ipd.randomSimplifyPercentage);
183 | RandomSimplify(&mBackgroundPoints, desc.ipd.randomSimplifyPercentage);
184 | }
185 |
186 | END_TIMER(ProcessingInput);
187 | }
188 |
189 | cv::Point3f InputAssembler::debugGetPointColour(math::vec3 p) const
190 | {
191 | switch(mColourSpace)
192 | {
193 | case InputAssemblerDescriptor::ETCS_RGB:
194 | break;
195 | case InputAssemblerDescriptor::ETCS_HSV:
196 | {
197 | p.x *= 360.f;
198 | cv::Mat mat(1,1,CV_32FC3, &p.x);
199 | cv::cvtColor(mat, mat, CV_HSV2BGR);
200 | }
201 | break;
202 | case InputAssemblerDescriptor::ETCS_LAB:
203 | {
204 | p = math::vec3(p.x*254.f,
205 | p.y*254.f - 127.f,
206 | p.z*254.f - 127.f);
207 |
208 | cv::Mat mat(1,1,CV_32FC3, &p.x);
209 | cv::cvtColor(mat, mat, CV_Lab2BGR);
210 | }
211 | break;
212 | default:
213 | assert(0);
214 | }
215 |
216 | return cv::Point3f(p.z,p.y,p.x);
217 | }
218 |
219 | const std::vector& InputAssembler::backgroundPoints() const
220 | {
221 | return mBackgroundPoints;
222 | }
223 |
224 | const std::vector& InputAssembler::points() const
225 | {
226 | return mPoints;
227 | }
228 |
229 | const cv::Mat& InputAssembler::mat() const
230 | {
231 | return mForegroundF;
232 | }
233 |
234 | math::vec3 InputAssembler::background() const
235 | {
236 | return mBackground;
237 | }
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/Primatte/inputassembler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include "matrixd.h"
6 |
7 | /**
8 | * This class is responsible for taking an InputAssemblerDescriptor object,
9 | * and load+store the corresponding data.
10 | * */
11 |
12 | namespace anima
13 | {
14 | namespace ia
15 | {
16 | class IAverageBackgroundColourLocator;
17 |
18 | /** The descriptor of the input data/source. */
19 | struct InputAssemblerDescriptor
20 | {
21 | enum TargetColourspace {ETCS_RGB, ETCS_HSV, ETCS_LAB};
22 |
23 | /** The colour space to which the input will be converted. */
24 | TargetColourspace targetColourspace;
25 |
26 | IAverageBackgroundColourLocator* backgroundLocator;
27 |
28 | /** Set the image source to be copied from.
29 | The source mat is converted into floating point rgb values.
30 | 8-bit, 16-bit and floating point formats are supported.
31 | Expects a 3-component image. */
32 | const cv::Mat* foregroundSource;
33 |
34 | const cv::Mat* backgroundSource;
35 |
36 | /** The input processing descriptor, setting out pixel cleaning options. */
37 | struct InputCleanupDescriptor
38 | {
39 | /** Wheter to remove points at random. */
40 | bool randomSimplify;
41 |
42 | /** Percentage of points to remove randomly. */
43 | float randomSimplifyPercentage;
44 |
45 | /** Used for early stage pre-processing where only one point is kept per 3D grid box. */
46 | unsigned gridSize;
47 |
48 | bool validate()
49 | {
50 | if(randomSimplifyPercentage < 0 ||
51 | randomSimplifyPercentage > 100)
52 | return false;
53 | else
54 | return true;
55 | }
56 | } ipd;
57 |
58 | InputAssemblerDescriptor()
59 | {
60 | memset(this, 0, sizeof(*this));
61 | }
62 | };
63 |
64 | /** The input assembler class. */
65 | class InputAssembler
66 | {
67 | cv::Mat mForegroundF, mBackgroundF;
68 | std::vector mPoints, mBackgroundPoints;
69 | math::vec3 mBackground;
70 | InputAssemblerDescriptor::TargetColourspace mColourSpace;
71 |
72 | /** Returns the normalisation multiplier for a CV code
73 | CV_8UC3, CV_UC16C3 and CV_32FC3 supported.*/
74 | static float normalisationMultiplier(int cvCode);
75 | public:
76 |
77 | /** Initialises the input, throwing an exception if failed. */
78 | InputAssembler(InputAssemblerDescriptor& desc);
79 |
80 | /** Returns the internal points. */
81 | const std::vector& points() const;
82 |
83 | /** Returns the background points. */
84 | const std::vector& backgroundPoints() const;
85 |
86 | /** Returns the internal floating point image. */
87 | const cv::Mat& mat() const;
88 |
89 | /** Returns the most dominant background point in the correct colour space. */
90 | math::vec3 background() const;
91 |
92 | //Converts from internal colour space to rgb
93 | cv::Point3f debugGetPointColour(math::vec3 p) const;
94 | };
95 |
96 |
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Primatte/io.cpp:
--------------------------------------------------------------------------------
1 | #include "io.h"
2 | #include
3 |
4 | void Error(const std::string& msg)
5 | {
6 | std::cerr << "ERROR: " << msg << "\n";
7 | }
8 |
9 | void Warning(const std::string& msg)
10 | {
11 | std::cout << "Warning: " << msg << "\n";
12 | }
13 |
14 | void Inform(const std::string& msg)
15 | {
16 | std::cout << ":- " << msg << "\n";
17 | }
18 |
--------------------------------------------------------------------------------
/Primatte/io.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | /**
6 | * A series of function to help with basic input and output.
7 | * */
8 |
9 | /** Prints the given error message */
10 | void Error(const std::string& msg);
11 |
12 | /** Prints the given warning message. */
13 | void Warning(const std::string& msg);
14 |
15 | /** Prints the given information message. */
16 | void Inform(const std::string& msg);
17 |
18 | /** Converts the input to a string. */
19 | template
20 | std::string ToString(const T t)
21 | {
22 | std::ostringstream ss;
23 | ss << t;
24 | return ss.str();
25 | }
26 |
27 | /* Timer macros. Usage:
28 | * '''
29 | * START_TIMER(myFunkyTimer);
30 | * doHeavyCode();
31 | * END_TIMER(myFunkyTimer);
32 | * '''
33 | */
34 |
35 | #include
36 |
37 | #define START_TIMER(t) auto t = std::chrono::system_clock::now();
38 |
39 | #define END_TIMER(t) {Inform("Stopping timer: "#t + std::string(" : ") + \
40 | ToString(std::chrono::duration_cast(std::chrono::system_clock::now() - t).count()));}
41 |
--------------------------------------------------------------------------------
/Primatte/main.cpp:
--------------------------------------------------------------------------------
1 | #include "application.h"
2 | #include
3 |
4 | int main(int argc, char** argv)
5 | {
6 | // Read command lines arguments.
7 | QApplication application(argc,argv);
8 |
9 | // Instantiate the viewer.
10 | Application viewer;
11 |
12 | viewer.setWindowTitle("Preview");
13 |
14 | // Make the viewer window visible on screen.
15 | viewer.show();
16 |
17 | // Run main loop.
18 | return application.exec();
19 | }
20 |
--------------------------------------------------------------------------------
/Primatte/matrixd.cpp:
--------------------------------------------------------------------------------
1 | #include "matrixd.h"
2 | #include
3 |
4 | namespace math
5 | {
6 | template T dot(const tmp::_vec2& v1, const tmp::_vec2& v2)
7 | {
8 | return v1.x*v2.x + v1.y*v2.y;
9 | }
10 |
11 | template T dot(const tmp::_vec3& v1, const tmp::_vec3& v2)
12 | {
13 | return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
14 | }
15 |
16 | template T dot(const tmp::_vec4& v1, const tmp::_vec4& v2)
17 | {
18 | return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w;
19 | }
20 |
21 | template tmp::_vec3 cross(const tmp::_vec3& v1, const tmp::_vec3& v2)
22 | {
23 | return tmp::_vec3(v1.y*v2.z - v1.z*v2.y,
24 | v1.z*v2.x - v1.x*v2.z,
25 | v1.x*v2.y - v1.y*v2.x);
26 | }
27 |
28 | namespace tmp
29 | {
30 | static const matReal matScalarOne(1);
31 | static const matReal matScalarNull(0);
32 | static const matReal matScalarTwo(2);
33 |
34 | template _vec2::_vec2()
35 | {
36 | reset();
37 | }
38 |
39 | template _vec2::_vec2(const T x_, const T y_)
40 | {
41 | x = x_;
42 | y = y_;
43 | }
44 |
45 | template _vec2::_vec2(const T n)
46 | {
47 | x = n;
48 | y = n;
49 | }
50 |
51 | template matReal _vec2::angle() const
52 | {
53 | return matReal(std::atan2(y, x));
54 | }
55 |
56 | template T _vec2::lengthSquared() const
57 | {
58 | return x*x + y*y;
59 | }
60 |
61 | template matReal _vec2::length() const
62 | {
63 | return matReal(std::sqrt(x*x + y*y));
64 | }
65 |
66 | template matReal _vec2::proj(const _vec2& v) const
67 | {
68 | return math::dot(*this, v/v.length());
69 | }
70 |
71 | template matReal _vec2::distance(const _vec2& v) const
72 | {
73 | return matReal(std::sqrt((x - v.x)*(x - v.x) + (y - v.y)*(y - v.y)));
74 | }
75 |
76 | template T _vec2::distanceSquared(const _vec2& v) const
77 | {
78 | return (x - v.x)*(x - v.x) + (y - v.y)*(y - v.y);
79 | }
80 |
81 | template _vec2 _vec2::operator * (const T n) const
82 | {
83 | return _vec2(x*n, y*n);
84 | }
85 |
86 | template _vec2 _vec2::operator / (const T n) const
87 | {
88 | return _vec2(x / n, y / n);
89 | }
90 |
91 | template _vec2 _vec2::operator + (const T n) const
92 | {
93 | return _vec2(x + n, y + n);
94 | }
95 |
96 | template _vec2 _vec2::operator - (const T n) const
97 | {
98 | return _vec2(x - n, y - n);
99 | }
100 |
101 | template void _vec2::operator *= (const T n)
102 | {
103 | x *= n;
104 | y *= n;
105 | }
106 |
107 | template void _vec2::operator /= (const T n)
108 | {
109 | x /= n;
110 | y /= n;
111 | }
112 |
113 | template void _vec2::operator += (const T n)
114 | {
115 | x += n;
116 | y += n;
117 | }
118 |
119 | template void _vec2::operator -= (const T n)
120 | {
121 | x -= n;
122 | y -= n;
123 | }
124 |
125 | template bool _vec2::operator == (const _vec2& vec) const
126 | {
127 | return x == vec.x && y == vec.y;
128 | }
129 |
130 | template bool _vec2::operator == (T f) const
131 | {
132 | return x == f && y == f;
133 | }
134 |
135 | template bool _vec2::operator != (const _vec2& vec) const
136 | {
137 | return x != vec.x || y != vec.y;
138 | }
139 |
140 | template bool _vec2::operator != (T f) const
141 | {
142 | return x != f || y != f;
143 | }
144 |
145 | template _vec2& _vec2::normalize()
146 | {
147 | const matReal len = length();
148 | if(len==0)
149 | *this = _vec2(0);
150 | else
151 | {
152 | const matReal lenDivisor = matScalarOne / len;
153 | x = T(x * lenDivisor);
154 | y = T(y * lenDivisor);
155 | }
156 | return *this;
157 | }
158 |
159 | template _vec2 _vec2::operator + (const _vec2& vec) const
160 | {
161 | return _vec2(x + vec.x, y + vec.y);
162 | }
163 |
164 | template _vec2 _vec2::operator - (const _vec2& vec) const
165 | {
166 | return _vec2(x - vec.x, y - vec.y);
167 | }
168 |
169 | template _vec2 _vec2::operator * (const _vec2& vec) const
170 | {
171 | return _vec2(x*vec.x, y*vec.y);
172 | }
173 |
174 | template _vec2 _vec2::operator / (const _vec2& vec) const
175 | {
176 | return _vec2(x / vec.x, y / vec.y);
177 | }
178 |
179 | template void _vec2::operator += (const _vec2& vec)
180 | {
181 | x += vec.x;
182 | y += vec.y;
183 | }
184 |
185 | template void _vec2::operator -= (const _vec2& vec)
186 | {
187 | x -= vec.x;
188 | y -= vec.y;
189 | }
190 |
191 | template void _vec2::operator *= (const _vec2& vec)
192 | {
193 | x *= vec.x;
194 | y *= vec.y;
195 | }
196 |
197 | template void _vec2::operator /= (const _vec2& vec)
198 | {
199 | x /= vec.x;
200 | y /= vec.y;
201 | }
202 |
203 | template _vec2 _vec2::xy() const { return _vec2(x, y); }
204 | template _vec2 _vec2::yx() const { return _vec2(y, x); }
205 |
206 | template void _vec2::reset()
207 | {
208 | x = 0;
209 | y = 0;
210 | }
211 |
212 | template bool _vec2::operator < (const _vec2& vec) const
213 | {
214 | if (x==vec.x)
215 | return y bool _vec2::operator <= (const _vec2& vec) const
221 | {
222 | return *this < vec || *this==vec;
223 | }
224 |
225 | template bool _vec2::operator > (const _vec2& vec) const
226 | {
227 | if (x==vec.x)
228 | return y>vec.y;
229 | else
230 | return x > vec.x;
231 | }
232 |
233 | template bool _vec2::operator >= (const _vec2& vec) const
234 | {
235 | return *this > vec || *this==vec;
236 | }
237 |
238 | template _vec2 _vec2::operator % (const T n) const
239 | {
240 | return _vec2(x%n, y%n);
241 | }
242 |
243 | template void _vec2::operator %= (const T n)
244 | {
245 | x%=n;
246 | y%=n;
247 | }
248 |
249 | template _vec2 _vec2::operator % (const _vec2& vec) const
250 | {
251 | return _vec2(x%vec.x, y%vec.y);
252 | }
253 |
254 | template void _vec2::operator %= (const _vec2& vec)
255 | {
256 | x%=vec.x;
257 | y%=vec.y;
258 | }
259 |
260 |
261 | template<> _vec2 _vec2::operator % (const float n) const
262 | {
263 | return _vec2((float)fmod(x,n),(float)fmod(y,n));
264 | }
265 |
266 | template<> void _vec2::operator %= (const float n)
267 | {
268 | x = (float)fmod(x,n);
269 | y = (float)fmod(y,n);
270 | }
271 |
272 | template<> _vec2 _vec2::operator % (const _vec2& vec) const
273 | {
274 | return _vec2((float)fmod(x,vec.x), (float)fmod(y,vec.y));
275 | }
276 |
277 | template<> void _vec2::operator %= (const _vec2& vec)
278 | {
279 | x = (float)fmod(x,vec.x);
280 | y = (float)fmod(y,vec.y);
281 | }
282 |
283 |
284 | template<> _vec2 _vec2::operator % (const double n) const
285 | {
286 | return _vec2((double)fmod(x,n),(double)fmod(y,n));
287 | }
288 |
289 | template<> void _vec2::operator %= (const double n)
290 | {
291 | x = (double)fmod(x,n);
292 | y = (double)fmod(y,n);
293 | }
294 |
295 | template<> _vec2 _vec2::operator % (const _vec2& vec) const
296 | {
297 | return _vec2((double)fmod(x,vec.x), (double)fmod(y,vec.y));
298 | }
299 |
300 | template<> void _vec2::operator %= (const _vec2& vec)
301 | {
302 | x = (double)fmod(x,vec.x);
303 | y = (double)fmod(y,vec.y);
304 | }
305 |
306 |
307 | template _vec3::_vec3()
308 | {
309 | reset();
310 | }
311 |
312 | template _vec3::_vec3(const T x_, const T y_, const T z_)
313 | {
314 | x = x_;
315 | y = y_;
316 | z = z_;
317 | }
318 |
319 | template _vec3::_vec3(const _vec2& v, const T f)
320 | {
321 | x = v.x;
322 | y = v.y;
323 | z = f;
324 | }
325 |
326 | template _vec3::_vec3(const T f, const _vec2& v)
327 | {
328 | x = f;
329 | y = v.x;
330 | z = v.y;
331 | }
332 |
333 | template _vec3::_vec3(const T f)
334 | {
335 | x = f;
336 | y = f;
337 | z = f;
338 | }
339 |
340 | template T _vec3::lengthSquared() const
341 | {
342 | return x*x + y*y + z*z;
343 | }
344 |
345 | template matReal _vec3::length() const
346 | {
347 | return matReal(std::sqrt(x*x + y*y + z*z));
348 | }
349 |
350 | template matReal _vec3::distance(const _vec3& v) const
351 | {
352 | return matReal(std::sqrt((x - v.x)*(x - v.x) + (y - v.y)*(y - v.y) + (z - v.z)*(z - v.z)));
353 | }
354 |
355 | template T _vec3::distanceSquared(const _vec3& v) const
356 | {
357 | return (x - v.x)*(x - v.x) + (y - v.y)*(y - v.y) + (z - v.z)*(z - v.z);
358 | }
359 |
360 | template matReal _vec3::proj(const _vec3& v) const
361 | {
362 | return math::dot(*this, v/v.length());
363 | }
364 |
365 | template _vec3 _vec3::operator * (const T n) const
366 | {
367 | return _vec3(x*n, y*n, z*n);
368 | }
369 |
370 | template _vec3