Coverage for python/lsst/obs/subaru/strayLight/waveletCompression.py: 9%
154 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-15 03:44 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-15 03:44 -0800
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
42# low-pass filter.
43# The value K = 1.230174104914001 is for this normalization.
44#
45# We use the normalization:
46# H(0) = \sqrt{2}, \tilde{H}(0) = \sqrt{2}.
47# For this normalization, K must be the following value.
48K = 0.86986445162477855
51def cdf_9_7(data, level):
52 """
53 Multi-dimensional forward wavelet transformation
54 with the Cohen-Daubechies-Feauveau wavelet 9/7
56 @param data (numpy.ndarray)
57 N-dimensional array (N >= 1). This array will be *destroyed*.
58 If you want `data` kept, copy it before calling this function:
59 cdf_9_7(numpy.copy(data), level)
61 @param level (int or tuple)
62 Level of wavelet analysis.
63 If a tuple is given, its length must agree with the rank of `data`,
64 and level[i] is to be the level for the i-th axis.
66 @return (numpy.ndarray)
67 Result of multiresolution analysis.
68 """
69 data = numpy.asarray(data, dtype=float)
70 if numpy.asarray(level, dtype=int).shape == ():
71 level = itertools.repeat(level)
73 for axis, lev in zip(range(len(data.shape)), level):
74 data = cdf_9_7_1d(data, lev, axis)
76 return data
79def cdf_9_7_1d(data, level, axis=0):
80 """
81 One-dimensional forward wavelet transformation.
83 @param data (numpy.ndarray)
84 N-dimensional array (N >= 1). This array will be *destroyed*.
86 @param level (int)
87 Level of wavelet analysis.
89 @param axis (int)
91 @return (numpy.ndarray)
92 Result of multiresolution analysis.
93 """
94 data = numpy.asarray(data, dtype=float)
95 data = numpy.swapaxes(data, 0, axis)
96 size = len(data)
98 for i in range(level):
99 data[:size] = _cdf_9_7_1d_level1(data[:size])
100 size = (size + 1)//2
102 return numpy.swapaxes(data, 0, axis)
105def _cdf_9_7_1d_level1(data):
106 """
107 Level 1 one-dimensional forward wavelet transformation.
108 The 0th axis is used in the transformation.
110 @param data (numpy.ndarray)
111 N-dimensional array (N >= 1). This array will be *destroyed*.
113 @return (numpy.ndarray)
114 Result of transformation.
115 """
116 size = len(data)
117 if size <= 1:
118 return data
120 isEven = (size % 2 == 0)
122 # From equations (F-11) in ITU-T Rec. T.800
124 # predict (1)
125 data[1:-1:2] += alpha * (data[0:-2:2] + data[2::2])
126 if isEven:
127 data[-1] += 2*alpha * data[-2]
129 # update (1)
130 data[0] += 2*beta * data[1]
131 data[2:-1:2] += beta * (data[1:-2:2] + data[3::2])
132 if not isEven:
133 data[-1] += 2*beta * data[-2]
135 # predict (2)
136 data[1:-1:2] += gamma * (data[0:-2:2] + data[2::2])
137 if isEven:
138 data[-1] += 2*gamma * data[-2]
140 # update (2)
141 data[0] += 2*delta * data[1]
142 data[2:-1:2] += delta * (data[1:-2:2] + data[3::2])
143 if not isEven:
144 data[-1] += 2*delta * data[-2]
146 # de-interleave
147 scaling_size = (size + 1) // 2
148 ret = numpy.empty_like(data)
149 ret[:scaling_size] = (1/K) * data[0::2]
150 ret[scaling_size:] = K * data[1::2]
152 return ret
155def icdf_9_7(data, level):
156 """
157 Multi-dimensional backword wavelet transformation
158 with the Cohen-Daubechies-Feauveau wavelet 9/7
160 @param data (numpy.ndarray)
161 N-dimensional array (N >= 1). This array will be *destroyed*.
162 If you want `data` kept, copy it before calling this function:
163 icdf_9_7(numpy.copy(data), level)
165 @param level (int or tuple)
166 Level of wavelet analysis.
167 If a tuple is given, its length must agree with the rank of `data`,
168 and level[i] is to be the level for the i-th axis.
170 @return (numpy.ndarray)
171 Result of multiresolution synthesis.
172 """
173 data = numpy.asarray(data, dtype=float)
174 if numpy.asarray(level, dtype=int).shape == ():
175 level = itertools.repeat(level)
177 for axis, lev in zip(range(len(data.shape)), level):
178 data = icdf_9_7_1d(data, lev, axis)
180 return data
183def icdf_9_7_1d(data, level, axis=0):
184 """
185 One-dimensional backword wavelet transformation.
186 The 0th axis is used in the transformation.
188 @param data (numpy.ndarray)
189 N-dimensional array (N >= 1). This array will be *destroyed*.
191 @param level (int)
192 Level of wavelet analysis.
194 @param axis (int)
196 @return (numpy.ndarray)
197 Result of multiresolution synthesis.
198 """
199 data = numpy.asarray(data, dtype=float)
200 data = numpy.swapaxes(data, 0, axis)
201 size = len(data)
202 sizes = []
203 for i in range(level):
204 sizes.append(size)
205 size = (size + 1) // 2
207 for size in reversed(sizes):
208 data[:size] = _icdf_9_7_1d_level1(data[:size])
210 return numpy.swapaxes(data, 0, axis)
213def _icdf_9_7_1d_level1(data):
214 """
215 Level 1 one-dimensional backword wavelet transformation.
216 The 0th axis is used in the transformation.
218 @param data (numpy.ndarray)
219 N-dimensional array (N >= 1). This array will be *destroyed*.
221 @return (numpy.ndarray)
222 Result of transformation.
223 """
224 size = len(data)
225 if size <= 1:
226 return data
228 isEven = (size % 2 == 0)
230 # interleave
231 scaling_size = (size + 1) // 2
232 ret = data
233 data = numpy.empty_like(ret)
234 data[0::2] = K * ret[:scaling_size]
235 data[1::2] = (1/K) * ret[scaling_size:]
237 # From equations (F-7) in ITU-T Rec. T.800
239 # update (2)
240 data[0] -= 2*delta * data[1]
241 data[2:-1:2] -= delta * (data[1:-2:2] + data[3::2])
242 if not isEven:
243 data[-1] -= 2*delta * data[-2]
245 # predict (2)
246 data[1:-1:2] -= gamma * (data[0:-2:2] + data[2::2])
247 if isEven:
248 data[-1] -= 2*gamma * data[-2]
250 # update (1)
251 data[0] -= 2*beta * data[1]
252 data[2:-1:2] -= beta * (data[1:-2:2] + data[3::2])
253 if not isEven:
254 data[-1] -= 2*beta * data[-2]
256 # predict (1)
257 data[1:-1:2] -= alpha * (data[0:-2:2] + data[2::2])
258 if isEven:
259 data[-1] -= 2*alpha * data[-2]
261 return data
264def periodic_cdf_9_7_1d(data, level, axis=0):
265 """
266 One-dimensional forward wavelet transformation.
268 @param data (numpy.ndarray)
269 N-dimensional array (N >= 1). This array will be *destroyed*.
270 The size of this data must be divisible by 2**level.
272 @param level (int)
273 Level of wavelet analysis.
275 @param axis (int)
277 @return (numpy.ndarray)
278 Result of multiresolution analysis.
279 """
280 data = numpy.asarray(data, dtype=float)
281 data = numpy.swapaxes(data, 0, axis)
282 size = len(data)
284 if size % (2**level) != 0:
285 raise ValueError("Size must be divisible by 2**level.")
287 for i in range(level):
288 data[:size] = _periodic_cdf_9_7_1d_level1(data[:size])
289 size = (size + 1) // 2
291 return numpy.swapaxes(data, 0, axis)
294def _periodic_cdf_9_7_1d_level1(data):
295 """
296 Level 1 one-dimensional forward wavelet transformation.
297 The 0th axis is used in the transformation.
299 @param data (numpy.ndarray)
300 N-dimensional array (N >= 1). This array will be *destroyed*.
302 @return (numpy.ndarray)
303 Result of transformation.
304 """
305 size = len(data)
306 if size <= 1:
307 return data
309 assert(size % 2 == 0)
311 # From equations (F-11) in ITU-T Rec. T.800
313 # predict (1)
314 data[1:-1:2] += alpha * (data[0:-2:2] + data[2::2])
315 data[-1] += alpha * (data[0] + data[-2])
317 # update (1)
318 data[0] += beta * (data[1] + data[-1])
319 data[2:-1:2] += beta * (data[1:-2:2] + data[3::2])
321 # predict (2)
322 data[1:-1:2] += gamma * (data[0:-2:2] + data[2::2])
323 data[-1] += gamma * (data[0] + data[-2])
325 # update (2)
326 data[0] += delta * (data[1] + data[-1])
327 data[2:-1:2] += delta * (data[1:-2:2] + data[3::2])
329 # de-interleave
330 scaling_size = (size + 1) // 2
331 ret = numpy.empty_like(data)
332 ret[:scaling_size] = (1/K) * data[0::2]
333 ret[scaling_size:] = K * data[1::2]
335 return ret
338def periodic_icdf_9_7_1d(data, level, axis=0):
339 """
340 One-dimensional backword wavelet transformation.
342 @param data (numpy.ndarray)
343 N-dimensional array (N >= 1). This array will be *destroyed*.
344 The size of this data must be divisible by 2**level.
346 @param level (int)
347 Level of wavelet analysis.
349 @param axis (int)
351 @return (numpy.ndarray)
352 Result of multiresolution synthesis.
353 """
354 data = numpy.asarray(data, dtype=float)
355 data = numpy.swapaxes(data, 0, axis)
356 size = len(data)
358 if size % (2**level) != 0:
359 raise ValueError("Size must be divisible by 2**level.")
361 sizes = []
362 for i in range(level):
363 sizes.append(size)
364 size = (size + 1) // 2
366 for size in reversed(sizes):
367 data[:size] = _periodic_icdf_9_7_1d_level1(data[:size])
369 return numpy.swapaxes(data, 0, axis)
372def _periodic_icdf_9_7_1d_level1(data):
373 """
374 Level 1 one-dimensional backword wavelet transformation.
375 The 0th axis is used in the transformation.
377 @param data (numpy.ndarray)
378 N-dimensional array (N >= 1). This array will be *destroyed*.
380 @return (numpy.ndarray)
381 Result of transformation.
382 """
383 size = len(data)
384 if size <= 1:
385 return data
387 assert(size % 2 == 0)
389 # interleave
390 scaling_size = (size + 1) // 2
391 ret = data
392 data = numpy.empty_like(ret)
393 data[0::2] = K * ret[:scaling_size]
394 data[1::2] = (1/K) * ret[scaling_size:]
396 # From equations (F-7) in ITU-T Rec. T.800
398 # update (2)
399 data[0] -= delta * (data[1] + data[-1])
400 data[2:-1:2] -= delta * (data[1:-2:2] + data[3::2])
402 # predict (2)
403 data[1:-1:2] -= gamma * (data[0:-2:2] + data[2::2])
404 data[-1] -= gamma * (data[0] + data[-2])
406 # update (1)
407 data[0] -= beta * (data[1] + data[-1])
408 data[2:-1:2] -= beta * (data[1:-2:2] + data[3::2])
410 # predict (1)
411 data[1:-1:2] -= alpha * (data[0:-2:2] + data[2::2])
412 data[-1] -= alpha * (data[0] + data[-2])
414 return data
417def scaled_size(size, level):
418 """
419 Get the size of the level-n average portion
420 (as opposed to the detail portion).
421 @param size (int or tuple of int)
422 Size of the original vector
423 @param level (int or tuple of int)
424 Level of wavelet transformation
425 """
426 size = numpy.asarray(size, dtype=int)
427 level = numpy.asarray(level, dtype=int)
428 return (size + (2**level - 1)) // (2**level)