Skip to content

Commit 3a0ac49

Browse files
Merge pull request #99 from mickaelseznec/master
Fix for #97: handle correctly flow rotations
2 parents 79894dc + 7012a0a commit 3a0ac49

File tree

2 files changed

+17
-10
lines changed

2 files changed

+17
-10
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,10 @@ rotate: x,y,theta -> (x*cos(theta)-x*sin(theta), y*cos(theta), x*sin(theta))
145145
```
146146

147147
#### Rotation applied on img2
148-
We consider the angle `theta` small enough to linearize `cos(theta)` to 1 and `sin(theta)` to `theta` .
148+
Let us consider a rotation by the angle `theta` from the image center.
149149

150-
x flow map ( `flow[:,:,0]` ) will get a shift proportional to distance from center horizontal axis `j-h/2`
151-
152-
y flow map ( `flow[:,:,1]` ) will get a shift proportional to distance from center vertical axis `i-w/2`
150+
We must tranform each flow vector based on the coordinates where it lands. On each coordinate `(i, j)`, we have:
153151
```
154-
\for_all i,j flow[i,j] += theta*(j-h/2), theta*(i-w/2)
152+
flow[i, j, 0] += (cos(theta) - 1) * (j - w/2 + flow[i, j, 0]) + sin(theta) * (i - h/2 + flow[i, j, 1])
153+
flow[i, j, 1] += -sin(theta) * (j - w/2 + flow[i, j, 0]) + (cos(theta) - 1) * (i - h/2 + flow[i, j, 1])
155154
```

flow_transforms.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class RandomRotate(object):
167167
angle: max angle of the rotation
168168
interpolation order: Default: 2 (bilinear)
169169
reshape: Default: false. If set to true, image size will be set to keep every pixel in the image.
170-
diff_angle: Default: 0. Must stay less than 10 degrees, or linear approximation of flowmap will be off.
170+
diff_angle: Default: 0.
171171
"""
172172

173173
def __init__(self, angle, diff_angle=0, order=2, reshape=False):
@@ -182,14 +182,22 @@ def __call__(self, inputs,target):
182182
angle1 = applied_angle - diff/2
183183
angle2 = applied_angle + diff/2
184184
angle1_rad = angle1*np.pi/180
185+
diff_rad = diff*np.pi/180
185186

186187
h, w, _ = target.shape
187188

188-
def rotate_flow(i,j,k):
189-
return -k*(j-w/2)*(diff*np.pi/180) + (1-k)*(i-h/2)*(diff*np.pi/180)
189+
warped_coords = np.mgrid[:w, :h].T + target
190+
warped_coords -= np.array([w / 2, h / 2])
190191

191-
rotate_flow_map = np.fromfunction(rotate_flow, target.shape)
192-
target += rotate_flow_map
192+
warped_coords_rot = np.zeros_like(target)
193+
194+
warped_coords_rot[..., 0] = \
195+
(np.cos(diff_rad) - 1) * warped_coords[..., 0] + np.sin(diff_rad) * warped_coords[..., 1]
196+
197+
warped_coords_rot[..., 1] = \
198+
-np.sin(diff_rad) * warped_coords[..., 0] + (np.cos(diff_rad) - 1) * warped_coords[..., 1]
199+
200+
target += warped_coords_rot
193201

194202
inputs[0] = ndimage.interpolation.rotate(inputs[0], angle1, reshape=self.reshape, order=self.order)
195203
inputs[1] = ndimage.interpolation.rotate(inputs[1], angle2, reshape=self.reshape, order=self.order)

0 commit comments

Comments
 (0)