├── .gitignore ├── Makefile ├── README.md ├── arap.cpp ├── arap.o ├── assets ├── baymax.jpg ├── calvin-hobbes.jpg ├── calvin.png ├── krtek.png ├── ratatouille.png ├── sullivan.jpg ├── taz.jpg ├── taz_moved.jpg ├── taz_small.jpg └── tomandjerry.png ├── classes ├── Application.py ├── Box.py ├── CWrapper.py ├── Grid.py ├── ImageHelper.py ├── Point.py ├── __init__.py └── __pycache__ │ ├── Application.cpython-34.pyc │ ├── Box.cpython-34.pyc │ ├── CWrapper.cpython-34.pyc │ ├── Grid.cpython-34.pyc │ ├── ImageHelper.cpython-34.pyc │ ├── Point.cpython-34.pyc │ └── __init__.cpython-34.pyc ├── libarap.dll ├── main.py └── reports ├── presentation ├── pic │ ├── LogoCVUT.pdf │ ├── results │ │ ├── calvin-hobbes1.png │ │ ├── calvin-hobbes2.png │ │ ├── calvin1.png │ │ ├── calvin2.png │ │ ├── krtek1.png │ │ ├── krtek2.png │ │ ├── ratatouille1.png │ │ └── ratatouille2.png │ ├── taz_back.jpg │ ├── taz_bilin.jpg │ ├── taz_initial.jpg │ ├── taz_moved.jpg │ ├── taz_rigid.jpg │ ├── taz_rigid_detail.jpg │ └── taz_round.jpg ├── presentation.pdf └── presentation.tex └── report ├── mybib.bib ├── pic ├── results │ ├── calvin-hobbes1.png │ ├── calvin-hobbes2.png │ ├── calvin1.png │ ├── calvin2.png │ ├── krtek1.png │ ├── krtek2.png │ ├── ratatouille1.png │ └── ratatouille2.png ├── taz_back.jpg ├── taz_bilin.jpg ├── taz_initial.jpg ├── taz_mask.png ├── taz_moved.jpg ├── taz_rigid.jpg ├── taz_rigid_detail.jpg └── taz_round.jpg ├── report.bbl └── report.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __pycache__ 3 | classes/__pycache__ 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX=g++ 2 | OPT = -O3 3 | 4 | CXXFLAGS = $(INCLUDE_FLAG) $(OPT) 5 | 6 | all: project 7 | 8 | project: arap.cpp 9 | $(CXX) -c -o arap.o $< 10 | $(CXX) -shared -o libarap.dll arap.o $(LIB_FLAGS) 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This was a semestral project for a Digital Image Processing class at CTU, in summer semester 2014/2015. 2 | 3 | The goal was to implement as-rigid-as-possible real-time image deformation based on following papers: 4 | * http://dcgi.felk.cvut.cz/home/sykorad/deform.html 5 | * http://dl.acm.org/citation.cfm?id=1141920 6 | 7 | In reports folder of this repository are included presentation and final report, both written in Slovak but including images of achieved results. 8 | 9 | #### Implementation 10 | Application was implemented in Python 3.4 64bit with computationally extensive parts written in C. Python libraries used were: numpy, Pillow and TkInter. 11 | 12 | For compilation of the library there's a very very minimal makefile added. Application wasn't tested on anything else but Windows 7 64bit. 13 | 14 | For starting application use main.py, in which there's a hardcoded path to image. 15 | 16 | For adding and moving control point use left mouse button, for removing use right mouse button. 17 | 18 | #### Examples of results 19 | ![Calvin initial](https://raw.githubusercontent.com/tfedor/dzo-arap/master/reports/presentation/pic/results/calvin1.png) 20 | ![Calvin deformed](https://raw.githubusercontent.com/tfedor/dzo-arap/master/reports/presentation/pic/results/calvin2.png) 21 | 22 | ![Calvin & Hobbes initial](https://raw.githubusercontent.com/tfedor/dzo-arap/master/reports/presentation/pic/results/calvin-hobbes1.png) 23 | ![Calvin & Hobbes deformed](https://raw.githubusercontent.com/tfedor/dzo-arap/master/reports/presentation/pic/results/calvin-hobbes2.png) 24 | -------------------------------------------------------------------------------- /arap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define R (0) 11 | #define G (1) 12 | #define B (2) 13 | 14 | using namespace std; 15 | 16 | extern "C" void compute_mask(bool * mask, char * orig, int width, int height, int tolerance) { 17 | 18 | int empty_r = orig[0]&255; 19 | int empty_g = orig[1]&255; 20 | int empty_b = orig[2]&255; 21 | 22 | // bounds 23 | int lo_r = empty_r - tolerance; 24 | int lo_g = empty_g - tolerance; 25 | int lo_b = empty_b - tolerance; 26 | 27 | int up_r = empty_r + tolerance; 28 | int up_g = empty_g + tolerance; 29 | int up_b = empty_b + tolerance; 30 | 31 | // queue 32 | queue queue_x; 33 | queue queue_y; 34 | 35 | queue_x.push(0); 36 | queue_y.push(0); 37 | 38 | // closed 39 | bool ** closed = new bool*[height]; 40 | for (int i=0; i= width || y < 0 || y >= height) { continue; } 54 | if (closed[y][x]) {continue;} 55 | closed[y][x] = true; 56 | 57 | int px_r = orig[(y*width + x)*3 + R] & 255; 58 | int px_g = orig[(y*width + x)*3 + G] & 255; 59 | int px_b = orig[(y*width + x)*3 + B] & 255; 60 | 61 | bool foreground = (px_r < lo_r || px_r > up_r 62 | || px_g < lo_g || px_g > up_g 63 | || px_b < lo_b || px_b > up_b); 64 | if (!foreground) { 65 | mask[y*width+x] = false; 66 | 67 | queue_x.push(x-1); queue_y.push(y); 68 | queue_x.push(x+1); queue_y.push(y); 69 | queue_x.push(x); queue_y.push(y-1); 70 | queue_x.push(x); queue_y.push(y+1); 71 | } 72 | } 73 | } 74 | 75 | /**/ 76 | 77 | extern "C" void clear(char * orig, char * data, int width, int height) { 78 | 79 | char r = orig[0]&255; 80 | char g = orig[1]&255; 81 | char b = orig[2]&255; 82 | 83 | for (int i=0; i &left, std::map &right, int x, int y) { 104 | if (left.count(y) > 0) { 105 | if (x < left[y]) { 106 | left[y] = x; 107 | } else if (right[y] < x) { 108 | right[y] = x; 109 | } 110 | } else { 111 | left[y] = x; 112 | right[y] = x; 113 | } 114 | } 115 | void points(std::map &left, std::map &right, bool swap, int x0, int y0, int x1, int y1) { 116 | 117 | if (swap) { 118 | std::swap(x0, y0); 119 | std::swap(x1, y1); 120 | } 121 | 122 | int dx = abs(x1-x0); 123 | int dy = abs(y1-y0); 124 | 125 | if (x0 > x1) { 126 | std::swap(x0, x1); 127 | std::swap(y0, y1); 128 | } 129 | 130 | if (y1 < y0) { 131 | y0 = -y0; 132 | y1 = -y1; 133 | } 134 | 135 | int D = 2*dy - dx; 136 | 137 | // add 138 | if (swap) { 139 | store(left, right, abs(y0), abs(x0)); 140 | } else { 141 | store(left, right, abs(x0), abs(y0)); 142 | } 143 | 144 | int y = y0; 145 | for (int x=x0+1; x 0) { 148 | y += 1; 149 | D -= 2*dx; 150 | } 151 | 152 | // add 153 | if (swap) { 154 | store(left, right, abs(y), abs(x)); 155 | } else { 156 | store(left, right, abs(x), abs(y)); 157 | } 158 | } 159 | } 160 | extern "C" void rasterize(int * corners, std::map &left, std::map &right) { 161 | /* 162 | Bresenham's line 163 | http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm 164 | */ 165 | 166 | for (int i=0; i<4; i++) { 167 | int x0 = corners[2*i]; 168 | int y0 = corners[2*i + 1]; 169 | int x1 = corners[(2*i+ 2) % 8]; 170 | int y1 = corners[(2*i+ 3) % 8]; 171 | 172 | int dx = abs(x1-x0); 173 | int dy = abs(y1-y0); 174 | 175 | points(left, right, (dx <= dy), x0, y0, x1, y1); 176 | } 177 | } 178 | 179 | // 180 | extern "C" void project(double * homography, bool * mask, char * orig, char * data, int width, int height, int * corners) { 181 | 182 | std::map left; 183 | std::map right; 184 | rasterize(corners, left, right); 185 | 186 | int max_index = height*width*3; 187 | 188 | std::map::iterator it; 189 | 190 | for (it = left.begin(); it != left.end(); ++it) { 191 | int y = it->first; 192 | int x_left = it->second; 193 | int x_right = right[y]; 194 | 195 | for (int x=x_left; x<=x_right; x++) { 196 | 197 | float rx, ry; 198 | dot(homography, (float)x, (float)y, rx, ry); 199 | 200 | // 201 | int lft = floor(rx); 202 | int rgt = lft+1; 203 | 204 | int top = floor(ry); 205 | int btm = top+1; 206 | 207 | int data_index = (y*width + x)*3; 208 | 209 | if (lft >= 0 && rgt < width && top >= 0 && btm < height) { 210 | if (!mask[(int)round(ry)*width + (int)round(rx)]) { 211 | // data[data_index + R] = 255; 212 | // data[data_index + G] = 0; 213 | // data[data_index + B] = 0; 214 | continue; 215 | } 216 | 217 | float coefX = rx-(float)lft; 218 | float coefY = ry-(float)top; 219 | 220 | //std::cout << ry << " " << top << "=" << coefY << std::endl; 221 | //std::cout << coefX << " " << coefY << std::endl; 222 | 223 | float tl = (1.f-coefX)*(1.f-coefY); 224 | float tr = coefX*(1.f-coefY); 225 | float bl = (1.f-coefX)*coefY; 226 | float br = coefX*coefY; 227 | 228 | for (int c=0; c<3; c++) { 229 | float clr = tl*((int)round(orig[(top*width + lft)*3 + c])&255) 230 | + tr*((int)round(orig[(top*width + rgt)*3 + c])&255) 231 | + bl*((int)round(orig[(btm*width + lft)*3 + c])&255) 232 | + br*((int)round(orig[(btm*width + rgt)*3 + c])&255); 233 | data[data_index + c] = ((int)clr)&255; 234 | } 235 | } else { 236 | //data[data_index + R] = 255; 237 | //data[data_index + G] = 0; 238 | //data[data_index + B] = 255; 239 | } 240 | } 241 | } 242 | } 243 | 244 | -------------------------------------------------------------------------------- /arap.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/arap.o -------------------------------------------------------------------------------- /assets/baymax.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/baymax.jpg -------------------------------------------------------------------------------- /assets/calvin-hobbes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/calvin-hobbes.jpg -------------------------------------------------------------------------------- /assets/calvin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/calvin.png -------------------------------------------------------------------------------- /assets/krtek.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/krtek.png -------------------------------------------------------------------------------- /assets/ratatouille.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/ratatouille.png -------------------------------------------------------------------------------- /assets/sullivan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/sullivan.jpg -------------------------------------------------------------------------------- /assets/taz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/taz.jpg -------------------------------------------------------------------------------- /assets/taz_moved.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/taz_moved.jpg -------------------------------------------------------------------------------- /assets/taz_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/taz_small.jpg -------------------------------------------------------------------------------- /assets/tomandjerry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/assets/tomandjerry.png -------------------------------------------------------------------------------- /classes/Application.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from datetime import datetime 3 | 4 | from classes.ImageHelper import ImageHelper 5 | from classes.Grid import Grid 6 | from classes.CWrapper import CWrapper 7 | 8 | 9 | class Application: 10 | 11 | def __init__(self, path): 12 | self._cw = CWrapper() 13 | 14 | self._window = tk.Tk() 15 | 16 | self._grid = None 17 | self._image = None 18 | self.load_image(path) 19 | 20 | self._canvas = tk.Canvas(self._window, width=self._image.width, height=self._image.height) 21 | self._canvas.pack() 22 | 23 | self._image.canvas = self._canvas 24 | 25 | self._active_handle = -1 26 | self._loop = None 27 | self._t_last = 0 28 | 29 | def load_image(self, path): 30 | self._image = ImageHelper(self._cw, path) 31 | 32 | def bind(self, event, fn): 33 | self._canvas.bind(event, fn) 34 | 35 | def run(self): 36 | self._grid = Grid(self._cw, self._image) 37 | self._image.draw() 38 | self._grid.draw() 39 | 40 | self._run_once() 41 | 42 | self._window.mainloop() 43 | 44 | def _run_once(self): 45 | 46 | self._grid.regularize() 47 | 48 | dt = datetime.now() 49 | delta = dt.timestamp()-self._t_last 50 | if 0 < delta > 0.03: # 0.03 - 30 FPS 51 | 52 | # dt = datetime.now() 53 | # t1 = dt.timestamp() 54 | 55 | self._grid.project() 56 | 57 | #dt = datetime.now() 58 | # print(dt.timestamp()-t1) 59 | 60 | self._image.draw() 61 | self._grid.draw() 62 | 63 | dt = datetime.now() 64 | self._t_last = dt.timestamp() 65 | 66 | self._loop = self._window.after(1, self._run_once) 67 | 68 | def select_handle(self, e): 69 | handle_id = self._image.select_handle(e.x, e.y) 70 | 71 | if handle_id == -1: 72 | handle_id = self._image.create_handle(e.x, e.y) 73 | if handle_id != -1: 74 | if not self._grid.create_control_point(handle_id, e.x, e.y): 75 | self._image.remove_handle(handle_id) 76 | return False 77 | else: 78 | return False 79 | 80 | self._active_handle = handle_id 81 | return True 82 | 83 | def deselect_handle(self, e): 84 | self._active_handle = -1 85 | 86 | def remove_handle(self, e): 87 | handle_id = self._image.select_handle(e.x, e.y) 88 | if handle_id != -1: 89 | self._grid.remove_control_point(handle_id) 90 | self._image.remove_handle(handle_id) 91 | 92 | def move_handle(self, e): 93 | if self._active_handle != -1: 94 | self._image.move_handle(self._active_handle, e.x, e.y) 95 | self._grid.set_control_target(self._active_handle, e.x, e.y) 96 | -------------------------------------------------------------------------------- /classes/Box.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | 4 | from classes.Point import Point 5 | 6 | 7 | class Box(): 8 | """ Represents one box in a grid layed over image""" 9 | 10 | def __init__(self, cw, b_tl, b_tr, b_br, b_bl): 11 | """ 12 | :param cw: CWrapper object 13 | :param b_tl: top-left point of a box 14 | :param b_tr: top-right point of a box 15 | :param b_br: bottom-right point of a box 16 | :param b_bl: bottom-left point of a box 17 | """ 18 | 19 | self._cw = cw 20 | self.boundary = [b_tl, b_tr, b_br, b_bl] 21 | 22 | # box fitted into boundaries 23 | self._rigid = [b_tl.copy(), b_tr.copy(), b_br.copy(), b_bl.copy()] 24 | 25 | self.boundary[0].link(self._rigid[0]) 26 | self.boundary[1].link(self._rigid[1]) 27 | self.boundary[2].link(self._rigid[2]) 28 | self.boundary[3].link(self._rigid[3]) 29 | 30 | # homography matrices 31 | self.H = None 32 | 33 | H_A = [] 34 | H_B = [None]*8 35 | for s in self._rigid: 36 | H_A.append([s.ix, s.iy, 1, 0, 0, 0, None, None]) 37 | H_A.append([0, 0, 0, s.ix, s.iy, 1, None, None]) 38 | 39 | self.H_A = np.array(H_A) 40 | self.H_B = np.array(H_B) 41 | 42 | # centroids cache 43 | self._qc = Point(0, 0) # target centroid 44 | self._pc = Point(0, 0) # source centroid, same during whole object live 45 | self.compute_source_centroid() 46 | 47 | def has_point(self, x, y): 48 | """ 49 | Checks whether given coordinates are inside of this box's bounding box 50 | :return: boolean 51 | """ 52 | 53 | xs = [p.x for p in self.boundary] 54 | ys = [p.y for p in self.boundary] 55 | 56 | return min(xs) <= x <= max(xs) and min(ys) <= y <= max(ys) 57 | 58 | def get_closest_boundary(self, x, y): 59 | """ Get closest boundary Point to given position """ 60 | min_ = -1 61 | closest = None 62 | for b in self.boundary: 63 | dist = abs(b.x - x) + abs(b.y - y) 64 | if min_ == -1 or dist < min_: 65 | min_ = dist 66 | closest = b 67 | return closest 68 | 69 | def draw(self, canvas, rigid=True): 70 | """ 71 | :param rigid: whether to draw rigid box fitted into current boundaries. Default True. 72 | """ 73 | 74 | if rigid: 75 | canvas.create_line(self._rigid[0].coor, self._rigid[1].coor, fill="blue", tag="GRID") 76 | canvas.create_line(self._rigid[1].coor, self._rigid[2].coor, fill="blue", tag="GRID") 77 | canvas.create_line(self._rigid[2].coor, self._rigid[3].coor, fill="blue", tag="GRID") 78 | canvas.create_line(self._rigid[3].coor, self._rigid[0].coor, fill="blue", tag="GRID") 79 | 80 | canvas.create_line(self.boundary[0].coor, self.boundary[1].coor, fill="red", tag="GRID") 81 | canvas.create_line(self.boundary[1].coor, self.boundary[2].coor, fill="red", tag="GRID") 82 | canvas.create_line(self.boundary[2].coor, self.boundary[3].coor, fill="red", tag="GRID") 83 | canvas.create_line(self.boundary[3].coor, self.boundary[0].coor, fill="red", tag="GRID") 84 | 85 | def compute_source_centroid(self): 86 | w = self.boundary[0].weight + self.boundary[1].weight + self.boundary[2].weight + self.boundary[3].weight 87 | self._pc.x = (self.boundary[0].weight * self._rigid[0].ix 88 | + self.boundary[1].weight * self._rigid[1].ix 89 | + self.boundary[2].weight * self._rigid[2].ix 90 | + self.boundary[3].weight * self._rigid[3].ix) / w 91 | self._pc.y = (self.boundary[0].weight * self._rigid[0].iy 92 | + self.boundary[1].weight * self._rigid[1].iy 93 | + self.boundary[2].weight * self._rigid[2].iy 94 | + self.boundary[3].weight * self._rigid[3].iy) / w 95 | 96 | def compute_target_centroid(self): 97 | w = self.boundary[0].weight + self.boundary[1].weight + self.boundary[2].weight + self.boundary[3].weight 98 | self._qc.x = (self.boundary[0].weight * self.boundary[0].x 99 | + self.boundary[1].weight * self.boundary[1].x 100 | + self.boundary[2].weight * self.boundary[2].x 101 | + self.boundary[3].weight * self.boundary[3].x) / w 102 | self._qc.y = (self.boundary[0].weight * self.boundary[0].y 103 | + self.boundary[1].weight * self.boundary[1].y 104 | + self.boundary[2].weight * self.boundary[2].y 105 | + self.boundary[3].weight * self.boundary[3].y) / w 106 | 107 | def fit(self): 108 | """ 109 | Computes the best rotation and translation of the associated rigid box to minimize distance to boundaries 110 | """ 111 | 112 | self.compute_target_centroid() 113 | 114 | rotation = [[0, 0], [0, 0]] 115 | 116 | for i in range(0, 4): 117 | 118 | p_roof_x = self._rigid[i].ix - self._pc.x 119 | p_roof_y = self._rigid[i].iy - self._pc.y 120 | 121 | q_roof_x = self.boundary[i].x - self._qc.x 122 | q_roof_y = self.boundary[i].y - self._qc.y 123 | 124 | weight = self.boundary[i].weight 125 | pq_x = p_roof_x * q_roof_x 126 | pq_y = p_roof_y * q_roof_y 127 | pq_xy = p_roof_x * q_roof_y 128 | pq_yx = p_roof_y * q_roof_x 129 | rotation[0][0] += weight * (pq_x + pq_y) 130 | rotation[0][1] += weight * (pq_xy - pq_yx) 131 | rotation[1][0] += weight * (pq_yx - pq_xy) 132 | 133 | # mi_1 += self.boundary[i].weight * (pq_x + pq_y) 134 | # mi_2 += self.boundary[i].weight * (pq_yx - pq_xy) 135 | 136 | self._rigid[i].x = p_roof_x 137 | self._rigid[i].y = p_roof_y 138 | 139 | mi = 1 / math.sqrt(rotation[0][0]**2 + rotation[1][0]**2) 140 | 141 | rotation[0][0] *= mi 142 | rotation[0][1] *= mi 143 | rotation[1][0] *= mi 144 | rotation[1][1] = rotation[0][0] 145 | 146 | for i, point in enumerate(self._rigid): 147 | self._rigid[i].rotate(rotation).translate(self._qc) 148 | 149 | def _homography(self): 150 | """ 151 | Computes inverse homography. 152 | Source is initial position of the box, target is current boundary. 153 | """ 154 | 155 | for i in range(0, 4): 156 | s = self._rigid[i] 157 | t = self.boundary[i] 158 | self.H_A[2*i][6] = -s.ix*t.x 159 | self.H_A[2*i][7] = -s.iy*t.x 160 | 161 | self.H_A[2*i+1][6] = -s.ix*t.y 162 | self.H_A[2*i+1][7] = -s.iy*t.y 163 | 164 | self.H_B[2*i] = t.x 165 | self.H_B[2*i+1] = t.y 166 | 167 | h = np.linalg.solve(self.H_A, self.H_B) 168 | self.H = np.linalg.inv(np.array([[h[0], h[1], h[2]], 169 | [h[3], h[4], h[5]], 170 | [h[6], h[7], 1]])) 171 | 172 | def project(self, image): 173 | """ Projects image to current boundaries """ 174 | 175 | self._homography() 176 | 177 | vert = np.array([(int(round(p.x)), int(round(p.y))) for p in self.boundary]) 178 | self._cw.project(self.H.ctypes, image.cmask, image.corig, image.cdata, image.width, image.height, vert.ctypes) 179 | 180 | -------------------------------------------------------------------------------- /classes/CWrapper.py: -------------------------------------------------------------------------------- 1 | import ctypes as c 2 | 3 | 4 | class CWrapper: 5 | """ Wrapper for C functions """ 6 | 7 | def __init__(self): 8 | self._lib = c.cdll.libarap 9 | 10 | def mask(self, mask, orig, width, height, tolerance): 11 | self._lib.compute_mask(mask.data, orig.data, width, height, tolerance) 12 | 13 | def clear(self, orig, data, width, height): 14 | self._lib.clear(orig.data, data.data_as(c.POINTER(c.c_char)), width, height) 15 | 16 | def project(self, homography, mask, orig, data, width, height, corners): 17 | 18 | self._lib.project( 19 | homography.data, 20 | mask.data, 21 | orig.data, 22 | data.data, 23 | width, 24 | height, 25 | corners.data 26 | ) 27 | -------------------------------------------------------------------------------- /classes/Grid.py: -------------------------------------------------------------------------------- 1 | import math 2 | from classes.Point import Point 3 | from classes.Box import Box 4 | 5 | 6 | class Grid: 7 | """ 8 | Creates and manipulates grid of Boxes over the image, 9 | forces As Rigid As Possible image deformation 10 | via regularization and redraws the image 11 | """ 12 | 13 | BOX_SIZE = 32 14 | CONTROL_WEIGHT = 100000 15 | 16 | iter = 0 17 | id = None 18 | 19 | def __init__(self, cw, image): 20 | 21 | self.visible = False 22 | 23 | self.cw = cw 24 | 25 | self._image = image 26 | self._points = {} 27 | self._boxes = [] 28 | 29 | immask = self._image.mask 30 | 31 | # find borders of image 32 | top = self._border(immask) 33 | btm = self._image.height - self._border(immask[::-1]) 34 | lft = self._border(immask.T) 35 | rgt = self._image.width - self._border(immask.T[::-1]) 36 | 37 | width = rgt-lft 38 | height = btm-top 39 | 40 | box_count = (int(math.ceil(width/self.BOX_SIZE)), int(math.ceil(height/self.BOX_SIZE))) 41 | box_x = lft - int((box_count[0] * self.BOX_SIZE - width) / 2) 42 | box_y = top - int((box_count[1] * self.BOX_SIZE - height) / 2) 43 | 44 | # create Boxes over image 45 | for y in range(box_y, btm, self.BOX_SIZE): 46 | for x in range(box_x, rgt, self.BOX_SIZE): 47 | if -1 != self._border(immask[y:y+self.BOX_SIZE:1, x:x+self.BOX_SIZE:1]): 48 | if x < 0 or x + self.BOX_SIZE > self._image.width \ 49 | or y < 0 or y + self.BOX_SIZE > self._image.height: 50 | continue 51 | 52 | self._boxes.append( 53 | Box( 54 | self.cw, 55 | self._add_point(x, y), 56 | self._add_point(x+self.BOX_SIZE, y), 57 | self._add_point(x+self.BOX_SIZE, y+self.BOX_SIZE), 58 | self._add_point(x, y+self.BOX_SIZE) 59 | ) 60 | ) 61 | 62 | """ 63 | Control points setup 64 | key: Handle ID from ImageHelper 65 | item: [point ref, (x, y target coordinates), (x, y offset of grid Point from handle)] 66 | """ 67 | self._controls = {} 68 | 69 | def _border(self, mask): 70 | """ 71 | Finds the first row of the mask which contains foreground pixel. 72 | :return: row number in which the first foreground pixel was found, -1 if all pixels are empty 73 | """ 74 | fg = 0 75 | stop = False 76 | for row in mask: 77 | i = 0 78 | for sign in row: 79 | if sign: 80 | stop = True 81 | break 82 | i += 1 83 | if stop: 84 | break 85 | fg += 1 86 | 87 | if not stop: 88 | return -1 89 | return fg 90 | 91 | def _add_point(self, x, y): 92 | """ 93 | Creates new Point at given coordinate if it does not already exist 94 | :return: Point at given coordinates 95 | """ 96 | if y in self._points: 97 | if x not in self._points[y]: 98 | self._points[y][x] = Point(x, y) 99 | else: 100 | self._points[y] = {} 101 | self._points[y][x] = Point(x, y) 102 | 103 | return self._points[y][x] 104 | 105 | def _reset_weights(self): 106 | """ 107 | Set weight of each vertex in grid to 1. 108 | """ 109 | for y in self._points: 110 | for x in self._points[y]: 111 | self._points[y][x].weight = 1 112 | 113 | def _update_weights(self): 114 | """ 115 | Update weights of grid's vertices, respecting the structure of grid, i.e. run BFS from all control points. 116 | """ 117 | self._reset_weights() 118 | 119 | queue = [] 120 | for handle_id in self._controls: 121 | control_x = self._controls[handle_id][0].ix 122 | control_y = self._controls[handle_id][0].iy 123 | weight = self.CONTROL_WEIGHT 124 | 125 | queue.append((control_x, control_y, weight)) 126 | 127 | size = self.BOX_SIZE 128 | d = [(-size, 0), (size, 0), (0, -size), (0, size)] 129 | 130 | while len(queue) != 0: 131 | x, y, w = queue.pop() 132 | 133 | if self._points[y][x].weight < w: 134 | continue 135 | 136 | self._points[y][x].weight = self._points[y][x].weight 137 | 138 | for dx, dy in d: 139 | nbr_x = x+dx 140 | nbr_y = y+dy 141 | nbr_w = w-self.BOX_SIZE**2 142 | if nbr_w > 1 \ 143 | and nbr_y in self._points and nbr_x in self._points[nbr_y]: 144 | queue.append((nbr_x, nbr_y, nbr_w)) 145 | 146 | for box in self._boxes: 147 | box.compute_source_centroid() 148 | 149 | def create_control_point(self, handle_id, x, y): 150 | """ 151 | Creates control point if position is inside of grid and updates weights of grid's vertices. 152 | :return: boolean 153 | """ 154 | for box in self._boxes: 155 | if box.has_point(x, y): 156 | 157 | control = box.get_closest_boundary(x, y) 158 | control.weight = self.CONTROL_WEIGHT 159 | 160 | self._controls[handle_id] = [control, (control.x, control.y), (control.x - x, control.y - y)] 161 | 162 | self._update_weights() 163 | return True 164 | 165 | return False 166 | 167 | def remove_control_point(self, handle_id): 168 | if handle_id in self._controls: 169 | del self._controls[handle_id] 170 | self._update_weights() 171 | 172 | def set_control_target(self, handle_id, x, y): 173 | """ Change target of control point if exists """ 174 | dx, dy = self._controls[handle_id][2] 175 | self._controls[handle_id][1] = (x+dx, y+dy) 176 | 177 | def draw(self): 178 | """ 179 | Visualize grid 180 | """ 181 | self._image.canvas.delete("GRID") 182 | 183 | if self.visible: 184 | for box in self._boxes: 185 | box.draw(self._image.canvas, True) 186 | 187 | def regularize(self): 188 | """ 189 | Regularize grid to preserve As Rigid As Possible deformation 190 | """ 191 | for handle_id in self._controls: 192 | control = self._controls[handle_id] 193 | control[0].x = control[1][0] 194 | control[0].y = control[1][1] 195 | 196 | for box in self._boxes: 197 | box.fit() 198 | 199 | for y in self._points: 200 | for x in self._points[y]: 201 | self._points[y][x].average_linked() 202 | 203 | def project(self): 204 | """ 205 | Create projection of current state 206 | Image data are properly updated 207 | """ 208 | 209 | self.cw.clear(self._image.corig, self._image.cdata, self._image.width, self._image.height) 210 | 211 | for box in self._boxes: 212 | box.project(self._image) 213 | -------------------------------------------------------------------------------- /classes/ImageHelper.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from PIL import Image, ImageTk 3 | 4 | 5 | class ImageHelper: 6 | """ 7 | Manipulates directly with image. 8 | Ensures it's loading, updating and redrawing as well as provides info about loaded image. 9 | """ 10 | 11 | """ radius of visual representation of control point """ 12 | HANDLE_RADIUS = 5 13 | 14 | def __init__(self, cw, path): 15 | self.cw = cw 16 | self._canvas = None 17 | 18 | self._im_obj = Image.open(path) 19 | self._tk_obj = ImageTk.PhotoImage(self._im_obj) # keeping reference for image to load 20 | 21 | self._size = self._im_obj.size 22 | self._pos = (self.width/2, self.height/2) 23 | 24 | self._orig = np.array(self._im_obj) # original data of the image immediately after load 25 | self._data = np.array(self._im_obj) # current data of the image to draw 26 | 27 | self._mask = None 28 | self._compute_mask() 29 | 30 | self._handles = set() 31 | 32 | @property 33 | def canvas(self): 34 | return self._canvas 35 | 36 | @canvas.setter 37 | def canvas(self, canvas): 38 | self._canvas = canvas 39 | 40 | @property 41 | def width(self): 42 | return self._size[0] 43 | 44 | @property 45 | def height(self): 46 | return self._size[1] 47 | 48 | @property 49 | def mask(self): 50 | return self._mask 51 | 52 | @property 53 | def cmask(self): 54 | """ 55 | :return: Object for communicating with C interface for image mask 56 | """ 57 | return self._mask.ctypes 58 | 59 | @property 60 | def cdata(self): 61 | """ 62 | :return: Object for communicating with C interface for current image data 63 | """ 64 | return self._data.ctypes 65 | 66 | @property 67 | def corig(self): 68 | """ 69 | :return: Object for communicating with C interface for data of original image 70 | """ 71 | return self._orig.ctypes 72 | 73 | def _compute_mask(self): 74 | """ Compute mask of image - foreground is True, background is False """ 75 | self._mask = np.full((self.height, self.width), True, dtype=np.bool) 76 | self.cw.mask(self.cmask, self.corig, self.width, self.height, 10) 77 | 78 | def _update(self): 79 | """ Create new image from current data """ 80 | self._im_obj = Image.fromarray(self._data) # putdata(self._data) 81 | self._tk_obj = ImageTk.PhotoImage(self._im_obj) # need to keep reference for image to load 82 | 83 | def draw(self): 84 | """ Redraw image from associated data """ 85 | self._update() 86 | 87 | self._canvas.delete("IMAGE") 88 | self._canvas.create_image(self._pos, image=self._tk_obj, tag="IMAGE") 89 | 90 | for h in self._handles: 91 | self._canvas.tag_raise(h) 92 | 93 | return True 94 | 95 | def create_handle(self, x, y): 96 | """ 97 | Creates handle at given position if it doesn't exist yet 98 | :return: Handle ID or -1 if creation failed due to overlap with existing one 99 | """ 100 | bbox = (x-self.HANDLE_RADIUS, y-self.HANDLE_RADIUS, x+self.HANDLE_RADIUS, y+self.HANDLE_RADIUS) 101 | 102 | overlap = self._canvas.find_overlapping(bbox[0], bbox[1], bbox[2], bbox[3]) 103 | for obj_id in overlap: 104 | if obj_id in self._handles: 105 | return -1 106 | 107 | handle_id = self._canvas.create_oval(bbox, fill="blue", outline="blue", tag="HANDLE") 108 | self._handles.add(handle_id) 109 | return handle_id 110 | 111 | def select_handle(self, x, y): 112 | """ 113 | Checks if there is handle at given position 114 | :return: Handle ID if handle at position exists, -1 otherwise 115 | """ 116 | overlap = self._canvas.find_overlapping(x, y, x, y) 117 | for obj_id in overlap: 118 | if obj_id in self._handles: 119 | return obj_id 120 | 121 | return -1 122 | 123 | def move_handle(self, handle_id, x, y): 124 | """ Change position of given handle """ 125 | bbox = (x-self.HANDLE_RADIUS, y-self.HANDLE_RADIUS, x+self.HANDLE_RADIUS, y+self.HANDLE_RADIUS) 126 | self._canvas.coords(handle_id, bbox) 127 | 128 | def remove_handle(self, handle_id): 129 | """ Removes handle """ 130 | self._canvas.delete(handle_id) 131 | self._handles.remove(handle_id) 132 | -------------------------------------------------------------------------------- /classes/Point.py: -------------------------------------------------------------------------------- 1 | class Point(): 2 | """ Point of Grid (i.e. embedding lattice) of the image """ 3 | 4 | def __init__(self, x, y, w=1): 5 | """ 6 | :param x: x-coordinate 7 | :param y: y-coordinate 8 | :param w: weight 9 | """ 10 | 11 | self._pos = [x, y] 12 | self._init = (x, y) # intial state of point, doesn't need to be mutable 13 | self._linked = [] 14 | self._link_cnt = 0 15 | self.weight = w 16 | 17 | def reset(self): 18 | self._pos[0] = self._init[0] 19 | self._pos[1] = self._init[1] 20 | 21 | @property 22 | def x(self): 23 | return self._pos[0] 24 | 25 | @property 26 | def ix(self): 27 | return self._init[0] 28 | 29 | @x.setter 30 | def x(self, value): 31 | self._pos[0] = value 32 | 33 | @property 34 | def y(self): 35 | return self._pos[1] 36 | 37 | @property 38 | def iy(self): 39 | return self._init[1] 40 | 41 | @y.setter 42 | def y(self, value): 43 | self._pos[1] = value 44 | 45 | @property 46 | def coor(self): 47 | return self._pos[0], self._pos[1] 48 | 49 | def copy(self): 50 | return Point(self.x, self.y, self.weight) 51 | 52 | def sub(self, point): 53 | self.x -= point.x 54 | self.y -= point.y 55 | return self 56 | 57 | def rotate(self, rotation): 58 | x = rotation[0][0] * self.x + rotation[1][0] * self.y 59 | y = rotation[0][1] * self.x + rotation[1][1] * self.y 60 | self.x = x 61 | self.y = y 62 | return self 63 | 64 | def translate(self, translation): 65 | self.x += translation.x 66 | self.y += translation.y 67 | return self 68 | 69 | def link(self, other): 70 | """ Link another point """ 71 | self._linked.append(other) 72 | self._link_cnt += 1 73 | 74 | def average_linked(self): 75 | x = 0 76 | y = 0 77 | for point in self._linked: 78 | x += point.x 79 | y += point.y 80 | x /= self._link_cnt 81 | y /= self._link_cnt 82 | 83 | self.x = x 84 | self.y = y 85 | 86 | def __eq__(self, other): 87 | return self.x == other.x and self.y == other.y 88 | 89 | def __ne__(self, other): 90 | return not self.__eq__(other) 91 | -------------------------------------------------------------------------------- /classes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__init__.py -------------------------------------------------------------------------------- /classes/__pycache__/Application.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__pycache__/Application.cpython-34.pyc -------------------------------------------------------------------------------- /classes/__pycache__/Box.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__pycache__/Box.cpython-34.pyc -------------------------------------------------------------------------------- /classes/__pycache__/CWrapper.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__pycache__/CWrapper.cpython-34.pyc -------------------------------------------------------------------------------- /classes/__pycache__/Grid.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__pycache__/Grid.cpython-34.pyc -------------------------------------------------------------------------------- /classes/__pycache__/ImageHelper.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__pycache__/ImageHelper.cpython-34.pyc -------------------------------------------------------------------------------- /classes/__pycache__/Point.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__pycache__/Point.cpython-34.pyc -------------------------------------------------------------------------------- /classes/__pycache__/__init__.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/classes/__pycache__/__init__.cpython-34.pyc -------------------------------------------------------------------------------- /libarap.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/libarap.dll -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from classes.Application import Application 2 | 3 | app = Application("assets/taz.jpg") 4 | 5 | app.bind("", app.select_handle) 6 | app.bind("", app.deselect_handle) 7 | app.bind("", app.remove_handle) 8 | app.bind("", app.move_handle) 9 | 10 | app.run() 11 | 12 | -------------------------------------------------------------------------------- /reports/presentation/pic/LogoCVUT.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/LogoCVUT.pdf -------------------------------------------------------------------------------- /reports/presentation/pic/results/calvin-hobbes1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/calvin-hobbes1.png -------------------------------------------------------------------------------- /reports/presentation/pic/results/calvin-hobbes2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/calvin-hobbes2.png -------------------------------------------------------------------------------- /reports/presentation/pic/results/calvin1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/calvin1.png -------------------------------------------------------------------------------- /reports/presentation/pic/results/calvin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/calvin2.png -------------------------------------------------------------------------------- /reports/presentation/pic/results/krtek1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/krtek1.png -------------------------------------------------------------------------------- /reports/presentation/pic/results/krtek2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/krtek2.png -------------------------------------------------------------------------------- /reports/presentation/pic/results/ratatouille1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/ratatouille1.png -------------------------------------------------------------------------------- /reports/presentation/pic/results/ratatouille2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/results/ratatouille2.png -------------------------------------------------------------------------------- /reports/presentation/pic/taz_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/taz_back.jpg -------------------------------------------------------------------------------- /reports/presentation/pic/taz_bilin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/taz_bilin.jpg -------------------------------------------------------------------------------- /reports/presentation/pic/taz_initial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/taz_initial.jpg -------------------------------------------------------------------------------- /reports/presentation/pic/taz_moved.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/taz_moved.jpg -------------------------------------------------------------------------------- /reports/presentation/pic/taz_rigid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/taz_rigid.jpg -------------------------------------------------------------------------------- /reports/presentation/pic/taz_rigid_detail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/taz_rigid_detail.jpg -------------------------------------------------------------------------------- /reports/presentation/pic/taz_round.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/pic/taz_round.jpg -------------------------------------------------------------------------------- /reports/presentation/presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/presentation/presentation.pdf -------------------------------------------------------------------------------- /reports/presentation/presentation.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper]{beamer} 2 | % 3 | % Josef Hlavac & Tomas Zahradnicky (21.10.2010) 4 | % 5 | %\usepackage{pgfpages} 6 | %\pgfpagesuselayout{4 on 1}[a4paper,border shrink=5mm,landscape] 7 | %\pgfpagesuselayout{resize}[a4paper,border shrink=5mm,landscape] 8 | %\usepackage[czech]{babel} 9 | \usepackage[utf8]{inputenc} 10 | \usepackage{color} 11 | \usetheme{Boadilla} 12 | \useinnertheme{circles} 13 | \usepackage{subfigure} 14 | \usepackage[czech,slovak,english]{babel}%\useinnertheme{rounded} 15 | %\useinnertheme{rectangles} 16 | %\useinnertheme{balls} 17 | % 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | \newcommand\FirstName{Tomáš} 20 | \newcommand\FirstNameAbbreviated{T} 21 | \newcommand\LastName{Fedor} 22 | \newcommand\Email{fedortom@fit.cvut.cz} 23 | \newcommand\Faculty{Fakulta Informačních Technologií} 24 | \newcommand\University{České vysoké učení technické v Praze} 25 | \newcommand\FacultyAndUniversityAbbr{FIT ČVUT} 26 | 27 | \author[\FirstNameAbbreviated. \LastName]{\FirstName{} \LastName} 28 | \title[ARAP]{N-bodová deformácia obrazu využitím deformačného modelu ARAP} 29 | \titlegraphic{\includegraphics[width=1.5cm]{pic/LogoCVUT.pdf}} 30 | \institute[\FacultyAndUniversityAbbr]{\\ \Faculty\\ \University} 31 | \date{\today} 32 | % 33 | \begin{document} 34 | 35 | \begin{frame} 36 | \titlepage 37 | \end{frame} 38 | 39 | \section*{Obsah} 40 | \begin{frame}[allowframebreaks] 41 | \frametitle{Obsah} 42 | \tableofcontents 43 | \end{frame} 44 | 45 | \section{Algoritmus} 46 | 47 | \subsection{Program} 48 | \begin{frame} 49 | \frametitle{Program} 50 | \begin{itemize} 51 | \item Definovanie mriežky 52 | \item Opakuj: 53 | \begin{itemize} 54 | \item Nastavenie cieľovej polohy 55 | \item Regularizácia mriežky 56 | \item Prekreslenie obrázku 57 | \end{itemize} 58 | \end{itemize} 59 | \end{frame} 60 | 61 | \subsection{Embedding Lattice} 62 | \begin{frame} 63 | \frametitle{Embedding Lattice} 64 | \begin{itemize} 65 | \item nájdenie obsahu 66 | \item prekrytie maticou 67 | \begin{itemize} 68 | \item prepojené štvorce 69 | \item každý štvorec drží informáciu o pôvodnom stave 70 | \end{itemize} 71 | \item kontrolné body sa mapujú na vrcholy matice 72 | 73 | \begin{figure} 74 | \centering 75 | \includegraphics[height=0.5\textheight,keepaspectratio]{pic/taz_initial.jpg} 76 | \end{figure} 77 | \end{itemize} 78 | \end{frame} 79 | 80 | \subsection{Regularizácia} 81 | \begin{frame} 82 | \frametitle{Regularizácia} 83 | \begin{itemize} 84 | \item zabezpečuje ARAP deformáciu 85 | \item minimalizácia vzdialenosti pôvodného štvorca k novému tvaru 86 | 87 | \begin{block}{Optimálna rotácia} 88 | \begin{displaymath} 89 | \mathbf{R^*} = \frac{1}{\mu} 90 | \sum_i\left( 91 | \begin{array}{c} 92 | \mathbf{\hat{p}}_i \\ 93 | \mathbf{\hat{p}}^\bot_i 94 | \end{array} 95 | \right) 96 | \left( 97 | \mathbf{\hat{q}}^T_i \, \mathbf{\hat{q}}^{\bot T}_i 98 | \right) 99 | \end{displaymath} 100 | 101 | \begin{displaymath} 102 | \mathbf{\mu} = \sqrt{ 103 | \left(\sum_i\ 104 | \mathbf{\hat{q}}_i 105 | \mathbf{\hat{p}}^T_i 106 | \right)^2 107 | + 108 | \left(\sum_i\ 109 | \mathbf{\hat{q}}_i 110 | \mathbf{\hat{p}}^{\bot T}_i 111 | \right)^2 112 | } 113 | \end{displaymath} 114 | 115 | \(\bot\) značí kolmý vektor 116 | \end{block} 117 | 118 | \begin{block}{Optimálna translácia} 119 | \begin{displaymath} 120 | \mathbf{t^*}^T = \mathbf{p}^T_c - \mathbf{R^*} \cdot \mathbf{q}^T_c 121 | \end{displaymath} 122 | \end{block} 123 | 124 | \end{itemize} 125 | \end{frame} 126 | 127 | \begin{frame} 128 | \frametitle{Regularizácia 2} 129 | \begin{itemize} 130 | \item body matice sa spriemerujú 131 | \item iteratívne sa matica snaží dostať k cieľovej polohe 132 | \end{itemize} 133 | 134 | \begin{figure} 135 | \centering 136 | \includegraphics[height=0.5\textheight,keepaspectratio]{pic/taz_rigid.jpg} 137 | \includegraphics[height=0.5\textheight,keepaspectratio]{pic/taz_rigid_detail.jpg} 138 | \end{figure} 139 | \end{frame} 140 | 141 | \begin{frame} 142 | \frametitle{Regularizácia 3} 143 | \begin{itemize} 144 | \item po odstránení kontrolných bodov sa vráti do pôvodnej polohy až na globálnu rotáciu a posun 145 | \end{itemize} 146 | 147 | \begin{figure} 148 | \centering 149 | \includegraphics[height=0.5\textheight,keepaspectratio]{pic/taz_moved.jpg} 150 | \includegraphics[height=0.5\textheight,keepaspectratio]{pic/taz_back.jpg} 151 | \end{figure} 152 | \end{frame} 153 | 154 | \subsection{Prekreslenie} 155 | \begin{frame} 156 | \frametitle{Prekreslenie obrázku} 157 | \begin{itemize} 158 | \item homografia pre každý štvorec nového tvaru 159 | \item inverzná homografia 160 | \item najbližší pixel vs. bilineárna interpolácia 161 | \end{itemize} 162 | 163 | \begin{figure} 164 | \centering 165 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/taz_round.jpg} 166 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/taz_bilin.jpg} 167 | \end{figure} 168 | \end{frame} 169 | 170 | \section{Implementácia} 171 | \begin{frame} 172 | \frametitle{Implementácia} 173 | \begin{itemize} 174 | \item Python 175 | \begin{itemize} 176 | \item TkInter - GUI 177 | \item numpy - matematika 178 | \end{itemize} 179 | \item C - pre výpočetne zložité časti 180 | \end{itemize} 181 | \end{frame} 182 | 183 | \section{Príklady} 184 | 185 | \subsection{Krtek} 186 | \begin{frame} 187 | \frametitle{Krtek} 188 | \begin{figure} 189 | \centering 190 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/krtek1} 191 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/krtek2} 192 | \end{figure} 193 | \end{frame} 194 | 195 | \subsection{Calvin \& Hobbes} 196 | \begin{frame} 197 | \frametitle{Calvin \& Hobbes 1} 198 | \begin{figure} 199 | \centering 200 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/calvin1} 201 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/calvin2} 202 | \end{figure} 203 | \end{frame} 204 | 205 | \begin{frame} 206 | \frametitle{Calvin \& Hobbes 2} 207 | \begin{figure} 208 | \centering 209 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/calvin-hobbes1} 210 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/calvin-hobbes2} 211 | \end{figure} 212 | \end{frame} 213 | 214 | \subsection{Ratatouille} 215 | \begin{frame} 216 | \frametitle{Ratatouille} 217 | \begin{figure} 218 | \centering 219 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/ratatouille1} 220 | \includegraphics[width=0.5\textwidth,keepaspectratio]{pic/results/ratatouille2} 221 | \end{figure} 222 | \end{frame} 223 | 224 | \begin{frame} 225 | \vspace*{\fill} 226 | \begin{center} 227 | \Large Ďakujem za pozornosť 228 | \end{center} 229 | \vfill 230 | \end{frame} 231 | 232 | \end{document} 233 | 234 | -------------------------------------------------------------------------------- /reports/report/mybib.bib: -------------------------------------------------------------------------------- 1 | @InProceedings{Sykora09-NPAR, 2 | author = "Daniel S\'{y}kora and John Dingliana and Steven Collins", 3 | title = "As-rigid-as-possible Image Registration for Hand-drawn Cartoon Animations", 4 | booktitle = "Proceedings of International Symposium on Non-photorealistic Animation and Rendering", 5 | pages = "25--33", 6 | year = "2009", 7 | } 8 | 9 | @inproceedings{Schaefer:2006:IDU:1179352.1141920, 10 | author = {Schaefer, Scott and McPhail, Travis and Warren, Joe}, 11 | title = {Image Deformation Using Moving Least Squares}, 12 | booktitle = {ACM SIGGRAPH 2006 Papers}, 13 | series = {SIGGRAPH '06}, 14 | year = {2006}, 15 | isbn = {1-59593-364-6}, 16 | location = {Boston, Massachusetts}, 17 | pages = {533--540}, 18 | numpages = {8}, 19 | url = {http://doi.acm.org/10.1145/1179352.1141920}, 20 | doi = {10.1145/1179352.1141920}, 21 | acmid = {1141920}, 22 | publisher = {ACM}, 23 | address = {New York, NY, USA}, 24 | keywords = {deformations, moving least squares, rigid transformations}, 25 | } -------------------------------------------------------------------------------- /reports/report/pic/results/calvin-hobbes1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/calvin-hobbes1.png -------------------------------------------------------------------------------- /reports/report/pic/results/calvin-hobbes2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/calvin-hobbes2.png -------------------------------------------------------------------------------- /reports/report/pic/results/calvin1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/calvin1.png -------------------------------------------------------------------------------- /reports/report/pic/results/calvin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/calvin2.png -------------------------------------------------------------------------------- /reports/report/pic/results/krtek1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/krtek1.png -------------------------------------------------------------------------------- /reports/report/pic/results/krtek2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/krtek2.png -------------------------------------------------------------------------------- /reports/report/pic/results/ratatouille1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/ratatouille1.png -------------------------------------------------------------------------------- /reports/report/pic/results/ratatouille2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/results/ratatouille2.png -------------------------------------------------------------------------------- /reports/report/pic/taz_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_back.jpg -------------------------------------------------------------------------------- /reports/report/pic/taz_bilin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_bilin.jpg -------------------------------------------------------------------------------- /reports/report/pic/taz_initial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_initial.jpg -------------------------------------------------------------------------------- /reports/report/pic/taz_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_mask.png -------------------------------------------------------------------------------- /reports/report/pic/taz_moved.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_moved.jpg -------------------------------------------------------------------------------- /reports/report/pic/taz_rigid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_rigid.jpg -------------------------------------------------------------------------------- /reports/report/pic/taz_rigid_detail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_rigid_detail.jpg -------------------------------------------------------------------------------- /reports/report/pic/taz_round.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/pic/taz_round.jpg -------------------------------------------------------------------------------- /reports/report/report.bbl: -------------------------------------------------------------------------------- 1 | \begin{thebibliography}{1} 2 | 3 | \bibitem{Schaefer:2006:IDU:1179352.1141920} 4 | Scott Schaefer, Travis McPhail, and Joe Warren. 5 | \newblock Image deformation using moving least squares. 6 | \newblock In {\em ACM SIGGRAPH 2006 Papers}, SIGGRAPH '06, pages 533--540, New 7 | York, NY, USA, 2006. ACM. 8 | 9 | \bibitem{Sykora09-NPAR} 10 | Daniel S\'{y}kora, John Dingliana, and Steven Collins. 11 | \newblock As-rigid-as-possible image registration for hand-drawn cartoon 12 | animations. 13 | \newblock In {\em Proceedings of International Symposium on Non-photorealistic 14 | Animation and Rendering}, pages 25--33, 2009. 15 | 16 | \end{thebibliography} 17 | -------------------------------------------------------------------------------- /reports/report/report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tfedor/dzo-arap/c18159f91617f4e8be84b81bfb213f5899be2f72/reports/report/report.pdf --------------------------------------------------------------------------------