Hide keyboard shortcuts

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

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

48 

49 

50def cdf_9_7(data, level): 

51 """ 

52 Multi-dimensional forward wavelet transformation 

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

54 

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) 

59 

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. 

64 

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) 

71 

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

73 data = cdf_9_7_1d(data, lev, axis) 

74 

75 return data 

76 

77 

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

79 """ 

80 One-dimensional forward wavelet transformation. 

81 

82 @param data (numpy.ndarray) 

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

84 

85 @param level (int) 

86 Level of wavelet analysis. 

87 

88 @param axis (int) 

89 

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) 

96 

97 for i in range(level): 

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

99 size = (size + 1)//2 

100 

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

102 

103 

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. 

108 

109 @param data (numpy.ndarray) 

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

111 

112 @return (numpy.ndarray) 

113 Result of transformation. 

114 """ 

115 size = len(data) 

116 if size <= 1: 

117 return data 

118 

119 isEven = (size % 2 == 0) 

120 

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

122 

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] 

127 

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] 

133 

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] 

138 

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] 

144 

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] 

150 

151 return ret 

152 

153 

154def icdf_9_7(data, level): 

155 """ 

156 Multi-dimensional backword wavelet transformation 

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

158 

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) 

163 

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. 

168 

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) 

175 

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

177 data = icdf_9_7_1d(data, lev, axis) 

178 

179 return data 

180 

181 

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. 

186 

187 @param data (numpy.ndarray) 

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

189 

190 @param level (int) 

191 Level of wavelet analysis. 

192 

193 @param axis (int) 

194 

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 

205 

206 for size in reversed(sizes): 

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

208 

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

210 

211 

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. 

216 

217 @param data (numpy.ndarray) 

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

219 

220 @return (numpy.ndarray) 

221 Result of transformation. 

222 """ 

223 size = len(data) 

224 if size <= 1: 

225 return data 

226 

227 isEven = (size % 2 == 0) 

228 

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

235 

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

237 

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] 

243 

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] 

248 

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] 

254 

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] 

259 

260 return data 

261 

262 

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

264 """ 

265 One-dimensional forward wavelet transformation. 

266 

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. 

270 

271 @param level (int) 

272 Level of wavelet analysis. 

273 

274 @param axis (int) 

275 

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) 

282 

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

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

285 

286 for i in range(level): 

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

288 size = (size + 1) // 2 

289 

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

291 

292 

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. 

297 

298 @param data (numpy.ndarray) 

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

300 

301 @return (numpy.ndarray) 

302 Result of transformation. 

303 """ 

304 size = len(data) 

305 if size <= 1: 

306 return data 

307 

308 assert(size % 2 == 0) 

309 

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

311 

312 # predict (1) 

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

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

315 

316 # update (1) 

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

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

319 

320 # predict (2) 

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

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

323 

324 # update (2) 

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

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

327 

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] 

333 

334 return ret 

335 

336 

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

338 """ 

339 One-dimensional backword wavelet transformation. 

340 

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. 

344 

345 @param level (int) 

346 Level of wavelet analysis. 

347 

348 @param axis (int) 

349 

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) 

356 

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

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

359 

360 sizes = [] 

361 for i in range(level): 

362 sizes.append(size) 

363 size = (size + 1) // 2 

364 

365 for size in reversed(sizes): 

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

367 

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

369 

370 

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. 

375 

376 @param data (numpy.ndarray) 

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

378 

379 @return (numpy.ndarray) 

380 Result of transformation. 

381 """ 

382 size = len(data) 

383 if size <= 1: 

384 return data 

385 

386 assert(size % 2 == 0) 

387 

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

394 

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

396 

397 # update (2) 

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

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

400 

401 # predict (2) 

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

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

404 

405 # update (1) 

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

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

408 

409 # predict (1) 

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

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

412 

413 return data 

414 

415 

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)