-
Notifications
You must be signed in to change notification settings - Fork 5
/
RotateImage.m
353 lines (285 loc) · 9.28 KB
/
RotateImage.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
function[Image] = RotateImage(Image, degrees)
% RotateImage - Rotates an image by X degrees
%
% Image_Rotated = RotateImage(Image, degrees)
%
% Rotates an image by the angle degrees in the
% CCW direction. Degrees may be any number.
% The function will put degrees in the range 0
% to 360 degrees and then into a range of -45 to 45
% degrees after performing elementary 90 degree rotations.
%
% The rotation performed is the 3 Pass Separable rotation
% using FFT-based methods to perform the skews. Aliased spectral
% components are masked after EACH skew using the MaskImage function.
%
% Normal Rotation
%
% |x'| = | cos(a) -sin(a) ||x|
% |y'| | sin(a) cos(a) ||y|
%
% 3 Pass Rotation
%
% |x'| = | 1 -tan(a/2) || 1 0 || 1 -tan(a/2) ||x|
% |y'| | 0 1 || sin(a) 1 || 0 1 ||y|
%
% This function pads images during the rotation process. Images
% can be non-square, but odd dimensions will cause incorrect padding
% Therefore an error is returned, if a dimension is odd.
%
% Dimensions need not be powers of 2 and will not necessarily be padded
% to a power of 2. The Matlab fft functions are capable of non-power of 2
% transforms.
%
% Note: The results often display some Gibbs ringing.
%
% Example:
%
% load mri
% img = double( squeeze(D(:,:,1,16)) );
% img_rot = real( RotateImage(img,45) );
% figure;
% subplot(1,2,1); imagesc(img,[0 88]); axis image;
% subplot(1,2,2); imagesc(img_rot,[0 88]); axis image;
%
%************************************************************************
%* (c) Copyright 1998 *
%* Biomathematics Resource *
%* Mayo Foundation *
%************************************************************************
%
% 11/22/98 Implemented by Edward Brian Welch, [email protected]
%
% NOTE:
% This function is partially vectorized (only single loops,
% no double loops) to gain some benefit in speed. The tradeoff
% is that more memory is required to hold the large matrices.
% It would be possible to completely vectorize certain parts
% of the mfile, but that would require large amounts of memory
% and would also make the code less readable.
[xdim ydim] = size(Image);
if mod(xdim,2)==1 | mod(ydim,2)==1,
error('RotateImage() can only rotate images with even dimensions.');
end
% Determine type of image to return
if isreal(Image),
real_flag = 1;
else
real_flag = 0;
end
% Put degrees into the range [0,360]
while degrees<0,
degrees = degrees + 360;
end
while degrees>360,
degrees = degrees - 360;
end
% Count number of elementary 90 degree rotations
% to put rotation into range [-45,45]
count=0;
while degrees>45,
degrees = degrees - 90;
count = count + 1;
end
Image = rot90(Image, count);
% Calculate Trigonometric Values
% Not Necessary in Matlab implementation to Negate degrees
% so that CCW rotations are positive
theta = (degrees/360)*2*pi;
sin_theta = sin(theta);
negtan_thetadiv2 = -tan(theta/2);
%---------------------------
% FIRST SKEW
% |x1| = | 1 -tan(a/2) ||x|
% |y1| = | 0 1 ||y|
%---------------------------
% Pad image rows to double the row size
Image2 = zeros(2*xdim,ydim);
Image2( (xdim/2+1):(xdim/2+xdim),:)=Image;
% Forward FFT image rows
Image2 = fft(Image2, 2*xdim, 1);
% Calculate image's center coordinates
xno = (2*xdim-1)/2;
yno = (ydim-1)/2;
% Prepare to use the Fourier Shift Theorem
% f(x-deltax) <=> exp(-j*2*pi*deltax*k/N)*F(k)
% Initialize constant part of the exponent
% expression. The skew is row dependent.
cons1 = (-2.0*pi/(2*xdim))*negtan_thetadiv2;
% Calculate k values (Nyquist is at x=xno)
k_array = zeros((2*xdim),1);
for x=1:(2*xdim),
if (x-1)<=xno,
k_array(x) = (x-1);
else
k_array(x) = (x-1-2*xdim);
end
end
for y=1:ydim,
% Skew dependent part of expression
cons2 = cons1 * (y-1-yno);
% Calculate the angles
angle_array = cons2*k_array;
% Rotate the complex numbers by those angles
sin_ang = sin(angle_array);
cos_ang = cos(angle_array);
newr = real(Image2(:,y)).*cos_ang - imag(Image2(:,y)).*sin_ang;
newi = real(Image2(:,y)).*sin_ang + imag(Image2(:,y)).*cos_ang;
Image2(:,y) = newr + newi*i;
end
%---------------------------
% SECOND SKEW
% |x2| = | 1 0 ||x1|
% |y2| = | sin(a) 1 ||y1|
%---------------------------
% Pad the image columns in hybrid space
Image22 = zeros(2*xdim, 2*ydim);
Image22(:,(ydim/2+1):(ydim/2+ydim) )=Image2;
% Perform a Forward FFT on the image columns
Image22 = fft(Image22, 2*ydim, 2);
% Mask aliased components from SKEW 1
Image22 = fftshift(Image22);
Image22 = MaskImage( Image22, 1, 0, negtan_thetadiv2, 1);
Image22 = fftshift(Image22);
% Inverse FFT the image rows
Image22 = ifft(Image22, 2*xdim, 1);
% Calculate image's center coordinates
xno = (2*xdim-1)/2;
yno = (2*ydim-1)/2;
% Initialize constant part of the exponent
% expression. The skew is column dependent.
cons1 = (-2.0*pi/(2*ydim))*sin_theta;
% Calculate k values (Nyquist is at y=yno)
k_array = zeros(1,(2*ydim));
for y=1:(2*ydim),
if (y-1)<=yno,
k_array(y) = (y-1);
else
k_array(y) = (y-1-2*ydim);
end
end
for x=1:(2*xdim),
% Skew dependent part of expression
cons2 = cons1 * (x-1-xno);
% Calculate the angles
angle_array = cons2*k_array;
% Rotate the complex numbers by those angles
sin_ang = sin(angle_array);
cos_ang = cos(angle_array);
newr = real(Image22(x,:)).*cos_ang - imag(Image22(x,:)).*sin_ang;
newi = real(Image22(x,:)).*sin_ang + imag(Image22(x,:)).*cos_ang;
Image22(x,:) = newr + newi*i;
end
%---------------------------
% THIRD SKEW
% |x3| = | 1 -tan(a/2) ||x2|
% |y3| = | 0 1 ||y2|
%---------------------------
% Forward FFT image rows
Image22 = fft(Image22, 2*xdim, 1);
% Mask aliased components from SKEW 2
Image22 = fftshift(Image22);
Image22 = MaskImage( Image22, 1, sin_theta, 0, 1);
Image22 = fftshift(Image22);
% Inverse FFT the image columns
Image22 = ifft(Image22, 2*ydim, 2);
% Crop image columns
Image2 = Image22(:,(ydim/2+1):(ydim/2+ydim) );
% Calculate image's center coordinates
xno = (2*xdim-1)/2;
yno = (ydim-1)/2;
% Initialize constant part of the exponent
% expression. The skew is row dependent.
cons1 = (-2.0*pi/(2*xdim))*negtan_thetadiv2;
% Calculate k values (Nyquist is at x=xno)
k_array = zeros((2*xdim),1);
for x=1:(2*xdim),
if (x-1)<=xno,
k_array(x) = (x-1);
else
k_array(x) = (x-1-2*xdim);
end
end
for y=1:ydim,
% Skew dependent part of expression
cons2 = cons1 * (y-1-yno);
% Calculate the angles
angle_array = cons2*k_array;
% Rotate the complex numbers by those angles
sin_ang = sin(angle_array);
cos_ang = cos(angle_array);
newr = real(Image2(:,y)).*cos_ang - imag(Image2(:,y)).*sin_ang;
newi = real(Image2(:,y)).*sin_ang + imag(Image2(:,y)).*cos_ang;
Image2(:,y) = newr + newi*i;
end
% Forward FFT the image columns
Image2 = fft(Image2, ydim, 2);
% Mask aliased components from SKEW 3
% The /2.0 factor is there because columns have been cropped in half
Image2 = fftshift(Image2);
Image2 = MaskImage( Image2, 1, 0, negtan_thetadiv2/2.0, 1);
Image2 = fftshift(Image2);
% Inverse 2D FFT the image
Image2 = ifft2(Image2);
% Crop the rows to obtain final result
Image = Image2( (xdim/2+1):(xdim/2+xdim),:) ;
% Return a Real image if original Image was Real
if real_flag==1,
Image = real(Image);
end
%
% Image_Masked = MaskImage(Image, a, b, c, d)
%
% Masks an image according to the (x,y) coordinate
% transform matrix: |x'| = | a b | * |x|
% |y'| | c d | |y|
%
% (x,y) positions that become (x',y') outside the boundary
% of the original image will be set to 0.
%
% The masking is softened at the edges by a convolution.
%
%
%************************************************************************
%* (c) Copyright 1998 *
%* Biomathematics Resource *
%* Mayo Foundation *
%************************************************************************
%
% 11/22/98 Implemented by Edward Brian Welch, [email protected]
%
function[Image] = MaskImage(Image, a, b, c, d)
% NOTE:
% This function is highly vectorized (no loops)
% to gain some benefit in speed. The tradeoff is that
% more memory is required to hold the large matrices
[xdim ydim] = size(Image);
% Calculate center of the image
xno = (xdim-1)/2;
yno = (ydim-1)/2;
x_values = 1:1:xdim;
x_values = x_values - 1 - xno;
x_mat = repmat(x_values',1,ydim);
y_values = 1:1:ydim;
y_values = y_values - 1 - yno;
y_mat = repmat(y_values,xdim,1);
% Calculate new x values for this column
new_x_mat = a*x_mat + b*y_mat;
% Calculate new y values for this column
new_y_mat = c*x_mat + d*y_mat;
% Points whos x or y position is greater than
% absolute value of xno or yno respectively
% should be masked (set to zero).
new_x_mat = abs(new_x_mat) - xno;
new_y_mat = abs(new_y_mat) - yno;
% Only valid points will have a non-zero value after
% the operation below
new_x_mat = sign(new_x_mat)-1;
new_y_mat = sign(new_y_mat)-1;
% ANDing the matrices shows good points
mask = new_x_mat & new_y_mat;
% Soften mask edges
Nx=ceil(xdim*.2);
Ny=ceil(ydim*.2);
mask = conv2(mask,ones(Nx,Ny)/(Nx*Ny),'same');
Image = Image.*mask;