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

154 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-07-27 11:53 +0000

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/>. 

16 

17""" 

18CDF 9/7 wavelet transformation 

19 

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""" 

26 

27import numpy 

28 

29import itertools 

30 

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 

37 

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 

49 

50 

51def cdf_9_7(data, level): 

52 """ 

53 Multi-dimensional forward wavelet transformation 

54 with the Cohen-Daubechies-Feauveau wavelet 9/7 

55 

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) 

60 

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. 

65 

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) 

72 

73 for axis, lev in zip(range(len(data.shape)), level): 

74 data = cdf_9_7_1d(data, lev, axis) 

75 

76 return data 

77 

78 

79def cdf_9_7_1d(data, level, axis=0): 

80 """ 

81 One-dimensional forward wavelet transformation. 

82 

83 @param data (numpy.ndarray) 

84 N-dimensional array (N >= 1). This array will be *destroyed*. 

85 

86 @param level (int) 

87 Level of wavelet analysis. 

88 

89 @param axis (int) 

90 

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) 

97 

98 for i in range(level): 

99 data[:size] = _cdf_9_7_1d_level1(data[:size]) 

100 size = (size + 1)//2 

101 

102 return numpy.swapaxes(data, 0, axis) 

103 

104 

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. 

109 

110 @param data (numpy.ndarray) 

111 N-dimensional array (N >= 1). This array will be *destroyed*. 

112 

113 @return (numpy.ndarray) 

114 Result of transformation. 

115 """ 

116 size = len(data) 

117 if size <= 1: 

118 return data 

119 

120 isEven = (size % 2 == 0) 

121 

122 # From equations (F-11) in ITU-T Rec. T.800 

123 

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] 

128 

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] 

134 

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] 

139 

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] 

145 

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] 

151 

152 return ret 

153 

154 

155def icdf_9_7(data, level): 

156 """ 

157 Multi-dimensional backword wavelet transformation 

158 with the Cohen-Daubechies-Feauveau wavelet 9/7 

159 

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) 

164 

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. 

169 

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) 

176 

177 for axis, lev in zip(range(len(data.shape)), level): 

178 data = icdf_9_7_1d(data, lev, axis) 

179 

180 return data 

181 

182 

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. 

187 

188 @param data (numpy.ndarray) 

189 N-dimensional array (N >= 1). This array will be *destroyed*. 

190 

191 @param level (int) 

192 Level of wavelet analysis. 

193 

194 @param axis (int) 

195 

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 

206 

207 for size in reversed(sizes): 

208 data[:size] = _icdf_9_7_1d_level1(data[:size]) 

209 

210 return numpy.swapaxes(data, 0, axis) 

211 

212 

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. 

217 

218 @param data (numpy.ndarray) 

219 N-dimensional array (N >= 1). This array will be *destroyed*. 

220 

221 @return (numpy.ndarray) 

222 Result of transformation. 

223 """ 

224 size = len(data) 

225 if size <= 1: 

226 return data 

227 

228 isEven = (size % 2 == 0) 

229 

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:] 

236 

237 # From equations (F-7) in ITU-T Rec. T.800 

238 

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] 

244 

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] 

249 

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] 

255 

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] 

260 

261 return data 

262 

263 

264def periodic_cdf_9_7_1d(data, level, axis=0): 

265 """ 

266 One-dimensional forward wavelet transformation. 

267 

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. 

271 

272 @param level (int) 

273 Level of wavelet analysis. 

274 

275 @param axis (int) 

276 

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) 

283 

284 if size % (2**level) != 0: 

285 raise ValueError("Size must be divisible by 2**level.") 

286 

287 for i in range(level): 

288 data[:size] = _periodic_cdf_9_7_1d_level1(data[:size]) 

289 size = (size + 1) // 2 

290 

291 return numpy.swapaxes(data, 0, axis) 

292 

293 

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. 

298 

299 @param data (numpy.ndarray) 

300 N-dimensional array (N >= 1). This array will be *destroyed*. 

301 

302 @return (numpy.ndarray) 

303 Result of transformation. 

304 """ 

305 size = len(data) 

306 if size <= 1: 

307 return data 

308 

309 assert(size % 2 == 0) 

310 

311 # From equations (F-11) in ITU-T Rec. T.800 

312 

313 # predict (1) 

314 data[1:-1:2] += alpha * (data[0:-2:2] + data[2::2]) 

315 data[-1] += alpha * (data[0] + data[-2]) 

316 

317 # update (1) 

318 data[0] += beta * (data[1] + data[-1]) 

319 data[2:-1:2] += beta * (data[1:-2:2] + data[3::2]) 

320 

321 # predict (2) 

322 data[1:-1:2] += gamma * (data[0:-2:2] + data[2::2]) 

323 data[-1] += gamma * (data[0] + data[-2]) 

324 

325 # update (2) 

326 data[0] += delta * (data[1] + data[-1]) 

327 data[2:-1:2] += delta * (data[1:-2:2] + data[3::2]) 

328 

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] 

334 

335 return ret 

336 

337 

338def periodic_icdf_9_7_1d(data, level, axis=0): 

339 """ 

340 One-dimensional backword wavelet transformation. 

341 

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. 

345 

346 @param level (int) 

347 Level of wavelet analysis. 

348 

349 @param axis (int) 

350 

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) 

357 

358 if size % (2**level) != 0: 

359 raise ValueError("Size must be divisible by 2**level.") 

360 

361 sizes = [] 

362 for i in range(level): 

363 sizes.append(size) 

364 size = (size + 1) // 2 

365 

366 for size in reversed(sizes): 

367 data[:size] = _periodic_icdf_9_7_1d_level1(data[:size]) 

368 

369 return numpy.swapaxes(data, 0, axis) 

370 

371 

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. 

376 

377 @param data (numpy.ndarray) 

378 N-dimensional array (N >= 1). This array will be *destroyed*. 

379 

380 @return (numpy.ndarray) 

381 Result of transformation. 

382 """ 

383 size = len(data) 

384 if size <= 1: 

385 return data 

386 

387 assert(size % 2 == 0) 

388 

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:] 

395 

396 # From equations (F-7) in ITU-T Rec. T.800 

397 

398 # update (2) 

399 data[0] -= delta * (data[1] + data[-1]) 

400 data[2:-1:2] -= delta * (data[1:-2:2] + data[3::2]) 

401 

402 # predict (2) 

403 data[1:-1:2] -= gamma * (data[0:-2:2] + data[2::2]) 

404 data[-1] -= gamma * (data[0] + data[-2]) 

405 

406 # update (1) 

407 data[0] -= beta * (data[1] + data[-1]) 

408 data[2:-1:2] -= beta * (data[1:-2:2] + data[3::2]) 

409 

410 # predict (1) 

411 data[1:-1:2] -= alpha * (data[0:-2:2] + data[2::2]) 

412 data[-1] -= alpha * (data[0] + data[-2]) 

413 

414 return data 

415 

416 

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)