Coverage for python/lsst/obs/subaru/strayLight/waveletCompression.py : 9%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# ybackground
2# Copyright (C) 2017 Sogo Mineo
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
17"""
18CDF 9/7 wavelet transformation
20See
21 T.800: JPEG2000 image coding system: Core coding system
22 https://www.itu.int/rec/T-REC-T.800
23 OpenJPEG
24 https://github.com/uclouvain/openjpeg
25"""
27import numpy
29import itertools
31# From Table F.4 in ITU-T Rec. T.800
32# Definition of lifting parameters for the 9-7 irreversible filter
33alpha = -1.586134342059924
34beta = -0.052980118572961
35gamma = 0.882911075530934
36delta = 0.443506852043971
38# "K" determines the normalization of biorthogonal filters.
39# JPEG2000 uses the normalization:
40# H(0) = \sum_i h[i] = 1, \tilde{H}(0) = \sum_i \tilde{h}[i] = 2
41# where h is the analysis low-pass filter, and \tilde{h} is the synthesis low-pass filter.
42# The value K = 1.230174104914001 is for this normalization.
43#
44# We use the normalization:
45# H(0) = \sqrt{2}, \tilde{H}(0) = \sqrt{2}.
46# For this normalization, K must be the following value.
47K = 0.86986445162477855
50def cdf_9_7(data, level):
51 """
52 Multi-dimensional forward wavelet transformation
53 with the Cohen-Daubechies-Feauveau wavelet 9/7
55 @param data (numpy.ndarray)
56 N-dimensional array (N >= 1). This array will be *destroyed*.
57 If you want `data` kept, copy it before calling this function:
58 cdf_9_7(numpy.copy(data), level)
60 @param level (int or tuple)
61 Level of wavelet analysis.
62 If a tuple is given, its length must agree with the rank of `data`,
63 and level[i] is to be the level for the i-th axis.
65 @return (numpy.ndarray)
66 Result of multiresolution analysis.
67 """
68 data = numpy.asarray(data, dtype=float)
69 if numpy.asarray(level, dtype=int).shape == ():
70 level = itertools.repeat(level)
72 for axis, lev in zip(range(len(data.shape)), level):
73 data = cdf_9_7_1d(data, lev, axis)
75 return data
78def cdf_9_7_1d(data, level, axis=0):
79 """
80 One-dimensional forward wavelet transformation.
82 @param data (numpy.ndarray)
83 N-dimensional array (N >= 1). This array will be *destroyed*.
85 @param level (int)
86 Level of wavelet analysis.
88 @param axis (int)
90 @return (numpy.ndarray)
91 Result of multiresolution analysis.
92 """
93 data = numpy.asarray(data, dtype=float)
94 data = numpy.swapaxes(data, 0, axis)
95 size = len(data)
97 for i in range(level):
98 data[:size] = _cdf_9_7_1d_level1(data[:size])
99 size = (size + 1)//2
101 return numpy.swapaxes(data, 0, axis)
104def _cdf_9_7_1d_level1(data):
105 """
106 Level 1 one-dimensional forward wavelet transformation.
107 The 0th axis is used in the transformation.
109 @param data (numpy.ndarray)
110 N-dimensional array (N >= 1). This array will be *destroyed*.
112 @return (numpy.ndarray)
113 Result of transformation.
114 """
115 size = len(data)
116 if size <= 1:
117 return data
119 isEven = (size % 2 == 0)
121 # From equations (F-11) in ITU-T Rec. T.800
123 # predict (1)
124 data[1:-1:2] += alpha * (data[0:-2:2] + data[2::2])
125 if isEven:
126 data[-1] += 2*alpha * data[-2]
128 # update (1)
129 data[0] += 2*beta * data[1]
130 data[2:-1:2] += beta * (data[1:-2:2] + data[3::2])
131 if not isEven:
132 data[-1] += 2*beta * data[-2]
134 # predict (2)
135 data[1:-1:2] += gamma * (data[0:-2:2] + data[2::2])
136 if isEven:
137 data[-1] += 2*gamma * data[-2]
139 # update (2)
140 data[0] += 2*delta * data[1]
141 data[2:-1:2] += delta * (data[1:-2:2] + data[3::2])
142 if not isEven:
143 data[-1] += 2*delta * data[-2]
145 # de-interleave
146 scaling_size = (size + 1) // 2
147 ret = numpy.empty_like(data)
148 ret[:scaling_size] = (1/K) * data[0::2]
149 ret[scaling_size:] = K * data[1::2]
151 return ret
154def icdf_9_7(data, level):
155 """
156 Multi-dimensional backword wavelet transformation
157 with the Cohen-Daubechies-Feauveau wavelet 9/7
159 @param data (numpy.ndarray)
160 N-dimensional array (N >= 1). This array will be *destroyed*.
161 If you want `data` kept, copy it before calling this function:
162 icdf_9_7(numpy.copy(data), level)
164 @param level (int or tuple)
165 Level of wavelet analysis.
166 If a tuple is given, its length must agree with the rank of `data`,
167 and level[i] is to be the level for the i-th axis.
169 @return (numpy.ndarray)
170 Result of multiresolution synthesis.
171 """
172 data = numpy.asarray(data, dtype=float)
173 if numpy.asarray(level, dtype=int).shape == ():
174 level = itertools.repeat(level)
176 for axis, lev in zip(range(len(data.shape)), level):
177 data = icdf_9_7_1d(data, lev, axis)
179 return data
182def icdf_9_7_1d(data, level, axis=0):
183 """
184 One-dimensional backword wavelet transformation.
185 The 0th axis is used in the transformation.
187 @param data (numpy.ndarray)
188 N-dimensional array (N >= 1). This array will be *destroyed*.
190 @param level (int)
191 Level of wavelet analysis.
193 @param axis (int)
195 @return (numpy.ndarray)
196 Result of multiresolution synthesis.
197 """
198 data = numpy.asarray(data, dtype=float)
199 data = numpy.swapaxes(data, 0, axis)
200 size = len(data)
201 sizes = []
202 for i in range(level):
203 sizes.append(size)
204 size = (size + 1) // 2
206 for size in reversed(sizes):
207 data[:size] = _icdf_9_7_1d_level1(data[:size])
209 return numpy.swapaxes(data, 0, axis)
212def _icdf_9_7_1d_level1(data):
213 """
214 Level 1 one-dimensional backword wavelet transformation.
215 The 0th axis is used in the transformation.
217 @param data (numpy.ndarray)
218 N-dimensional array (N >= 1). This array will be *destroyed*.
220 @return (numpy.ndarray)
221 Result of transformation.
222 """
223 size = len(data)
224 if size <= 1:
225 return data
227 isEven = (size % 2 == 0)
229 # interleave
230 scaling_size = (size + 1) // 2
231 ret = data
232 data = numpy.empty_like(ret)
233 data[0::2] = K * ret[:scaling_size]
234 data[1::2] = (1/K) * ret[scaling_size:]
236 # From equations (F-7) in ITU-T Rec. T.800
238 # update (2)
239 data[0] -= 2*delta * data[1]
240 data[2:-1:2] -= delta * (data[1:-2:2] + data[3::2])
241 if not isEven:
242 data[-1] -= 2*delta * data[-2]
244 # predict (2)
245 data[1:-1:2] -= gamma * (data[0:-2:2] + data[2::2])
246 if isEven:
247 data[-1] -= 2*gamma * data[-2]
249 # update (1)
250 data[0] -= 2*beta * data[1]
251 data[2:-1:2] -= beta * (data[1:-2:2] + data[3::2])
252 if not isEven:
253 data[-1] -= 2*beta * data[-2]
255 # predict (1)
256 data[1:-1:2] -= alpha * (data[0:-2:2] + data[2::2])
257 if isEven:
258 data[-1] -= 2*alpha * data[-2]
260 return data
263def periodic_cdf_9_7_1d(data, level, axis=0):
264 """
265 One-dimensional forward wavelet transformation.
267 @param data (numpy.ndarray)
268 N-dimensional array (N >= 1). This array will be *destroyed*.
269 The size of this data must be divisible by 2**level.
271 @param level (int)
272 Level of wavelet analysis.
274 @param axis (int)
276 @return (numpy.ndarray)
277 Result of multiresolution analysis.
278 """
279 data = numpy.asarray(data, dtype=float)
280 data = numpy.swapaxes(data, 0, axis)
281 size = len(data)
283 if size % (2**level) != 0:
284 raise ValueError("Size must be divisible by 2**level.")
286 for i in range(level):
287 data[:size] = _periodic_cdf_9_7_1d_level1(data[:size])
288 size = (size + 1) // 2
290 return numpy.swapaxes(data, 0, axis)
293def _periodic_cdf_9_7_1d_level1(data):
294 """
295 Level 1 one-dimensional forward wavelet transformation.
296 The 0th axis is used in the transformation.
298 @param data (numpy.ndarray)
299 N-dimensional array (N >= 1). This array will be *destroyed*.
301 @return (numpy.ndarray)
302 Result of transformation.
303 """
304 size = len(data)
305 if size <= 1:
306 return data
308 assert(size % 2 == 0)
310 # From equations (F-11) in ITU-T Rec. T.800
312 # predict (1)
313 data[1:-1:2] += alpha * (data[0:-2:2] + data[2::2])
314 data[-1] += alpha * (data[0] + data[-2])
316 # update (1)
317 data[0] += beta * (data[1] + data[-1])
318 data[2:-1:2] += beta * (data[1:-2:2] + data[3::2])
320 # predict (2)
321 data[1:-1:2] += gamma * (data[0:-2:2] + data[2::2])
322 data[-1] += gamma * (data[0] + data[-2])
324 # update (2)
325 data[0] += delta * (data[1] + data[-1])
326 data[2:-1:2] += delta * (data[1:-2:2] + data[3::2])
328 # de-interleave
329 scaling_size = (size + 1) // 2
330 ret = numpy.empty_like(data)
331 ret[:scaling_size] = (1/K) * data[0::2]
332 ret[scaling_size:] = K * data[1::2]
334 return ret
337def periodic_icdf_9_7_1d(data, level, axis=0):
338 """
339 One-dimensional backword wavelet transformation.
341 @param data (numpy.ndarray)
342 N-dimensional array (N >= 1). This array will be *destroyed*.
343 The size of this data must be divisible by 2**level.
345 @param level (int)
346 Level of wavelet analysis.
348 @param axis (int)
350 @return (numpy.ndarray)
351 Result of multiresolution synthesis.
352 """
353 data = numpy.asarray(data, dtype=float)
354 data = numpy.swapaxes(data, 0, axis)
355 size = len(data)
357 if size % (2**level) != 0:
358 raise ValueError("Size must be divisible by 2**level.")
360 sizes = []
361 for i in range(level):
362 sizes.append(size)
363 size = (size + 1) // 2
365 for size in reversed(sizes):
366 data[:size] = _periodic_icdf_9_7_1d_level1(data[:size])
368 return numpy.swapaxes(data, 0, axis)
371def _periodic_icdf_9_7_1d_level1(data):
372 """
373 Level 1 one-dimensional backword wavelet transformation.
374 The 0th axis is used in the transformation.
376 @param data (numpy.ndarray)
377 N-dimensional array (N >= 1). This array will be *destroyed*.
379 @return (numpy.ndarray)
380 Result of transformation.
381 """
382 size = len(data)
383 if size <= 1:
384 return data
386 assert(size % 2 == 0)
388 # interleave
389 scaling_size = (size + 1) // 2
390 ret = data
391 data = numpy.empty_like(ret)
392 data[0::2] = K * ret[:scaling_size]
393 data[1::2] = (1/K) * ret[scaling_size:]
395 # From equations (F-7) in ITU-T Rec. T.800
397 # update (2)
398 data[0] -= delta * (data[1] + data[-1])
399 data[2:-1:2] -= delta * (data[1:-2:2] + data[3::2])
401 # predict (2)
402 data[1:-1:2] -= gamma * (data[0:-2:2] + data[2::2])
403 data[-1] -= gamma * (data[0] + data[-2])
405 # update (1)
406 data[0] -= beta * (data[1] + data[-1])
407 data[2:-1:2] -= beta * (data[1:-2:2] + data[3::2])
409 # predict (1)
410 data[1:-1:2] -= alpha * (data[0:-2:2] + data[2::2])
411 data[-1] -= alpha * (data[0] + data[-2])
413 return data
416def scaled_size(size, level):
417 """
418 Get the size of the level-n average portion
419 (as opposed to the detail portion).
420 @param size (int or tuple of int)
421 Size of the original vector
422 @param level (int or tuple of int)
423 Level of wavelet transformation
424 """
425 size = numpy.asarray(size, dtype=int)
426 level = numpy.asarray(level, dtype=int)
427 return (size + (2**level - 1)) // (2**level)