CWaveletTransform(3)
β¨ CWaveletTransform β¨ β the libpgf manual, bestie edition π
okay so this is the page for CWaveletTransform(3) from libpgf, and it's giving wavelet energy π. Buckle up.
πΈ NAME πΈ
CWaveletTransform β PGF wavelet transform. that's it, that's the whole vibe. π«Ά
β¨ SYNOPSIS β¨
#include <WaveletTransform.h>
π Public Member Functions
CWaveletTransform (UINT32 width, UINT32 height, int levels, DataT *data=nullptr)~CWaveletTransform ()β Destructor.OSError ForwardTransform (int level, int quant)OSError InverseTransform (int level, UINT32 *width, UINT32 *height, DataT **data)CSubband * GetSubband (int level, Orientation orientation)
π Private Member Functions
void Destroy ()void InitSubbands (UINT32 width, UINT32 height, DataT *data)void ForwardRow (DataT *buff, UINT32 width)void InverseRow (DataT *buff, UINT32 width)void InterleavedToSubbands (int destLevel, DataT *loRow, DataT *hiRow, UINT32 width)void SubbandsToInterleaved (int srcLevel, DataT *loRow, DataT *hiRow, UINT32 width)
π Private Attributes
int m_nLevelsβ number of LL levels: one more thanheader.nLevelsinPGFimageCSubband(* m_subband )[NSubbands]β quadtree of subbands:LLHLLHHH
π§ Friends
class CSubband
π Detailed Description π
PGF wavelet transform.
PGF wavelet transform class.
Author
- C. Stamm, R. Spuler
Definition at line 55 of file WaveletTransform.h.
π Constructor & Destructor Documentation π
CWaveletTransform::CWaveletTransform (UINT32 width, UINT32 height, int levels, DataT * data = nullptr)
Constructor: Constructs a wavelet transform pyramid of given size and levels. no cap, it literally builds you a whole pyramid ποΈβ¨
Parameters
widthβ The width of the original image (at level 0) in pixelsheightβ The height of the original image (at level 0) in pixelslevelsβ The number of levels (>= 0)dataβ Input data of subbandLLat level 0
Definition at line 40 of file WaveletTransform.cpp.
41 : m_nLevels(levels + 1) // m_nLevels in CPGFImage determines the number of FWT steps; this.m_nLevels determines the number subband-planes
42 , m_subband(nullptr)
43 #ifdef __PGFROISUPPORT__
44 , m_indices(nullptr)
45 #endif
46 {
47 ASSERT(m_nLevels > 0 && m_nLevels <= MaxLevel + 1);
48 InitSubbands(width, height, data);
49 }
CWaveletTransform::~CWaveletTransform () [inline]
Destructor. it says bye π, cleans up its mess, iconic behaviour.
Definition at line 69 of file WaveletTransform.h.
69 { Destroy(); }
π Member Function Documentation π
void CWaveletTransform::Destroy () [inline], [private]
Definition at line 125 of file WaveletTransform.h.
125 {
126 delete[] m_subband; m_subband = nullptr;
127 #ifdef __PGFROISUPPORT__
128 delete[] m_indices; m_indices = nullptr;
129 #endif
130 }
void CWaveletTransform::ForwardRow (DataT * buff, UINT32 width) [private]
Definition at line 180 of file WaveletTransform.cpp.
180 {
181 if (width >= FilterSize) {
182 UINT32 i = 3;
183
184 // left border handling
185 src[1] -= ((src[0] + src[2] + c1) >> 1); // high pass
186 src[0] += ((src[1] + c1) >> 1); // low pass
187
188 // middle part
189 for (; i < width-1; i += 2) {
190 src[i] -= ((src[i-1] + src[i+1] + c1) >> 1); // high pass
191 src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass
192 }
193
194 // right border handling
195 if (width & 1) {
196 src[i-1] += ((src[i-2] + c1) >> 1); // low pass
197 } else {
198 src[i] -= src[i-1]; // high pass
199 src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass
200 }
201 }
202 }
OSError CWaveletTransform::ForwardTransform (int level, int quant)
Compute fast forward wavelet transform of LL subband at given level and stores result in all 4 subbands of level + 1. the way it just... sends it forward π₯
Parameters
levelβ A wavelet transform pyramid level (>= 0 && < Levels())quantβ A quantization value (linear scalar quantization)
Returns
- error in case of a memory allocation problem π (yes, that's the only thing it's stressing about here)
Definition at line 88 of file WaveletTransform.cpp.
88 {
89 ASSERT(level >= 0 && level < m_nLevels - 1);
90 const int destLevel = level + 1;
91 ASSERT(m_subband[destLevel]);
92 CSubband* srcBand = &m_subband[level][LL]; ASSERT(srcBand);
93 const UINT32 width = srcBand->GetWidth();
94 const UINT32 height = srcBand->GetHeight();
95 DataT* src = srcBand->GetBuffer(); ASSERT(src);
96 DataT *row0, *row1, *row2, *row3;
97
98 // Allocate memory for next transform level
99 for (int i=0; i < NSubbands; i++) {
100 if (!m_subband[destLevel][i].AllocMemory()) return InsufficientMemory;
101 }
102
103 if (height >= FilterSize) { // changed from FilterSizeH to FilterSize
104 // top border handling
105 row0 = src; row1 = row0 + width; row2 = row1 + width;
106 ForwardRow(row0, width);
107 ForwardRow(row1, width);
108 ForwardRow(row2, width);
109 for (UINT32 k=0; k < width; k++) {
110 row1[k] -= ((row0[k] + row2[k] + c1) >> 1); // high pass
111 row0[k] += ((row1[k] + c1) >> 1); // low pass
112 }
113 InterleavedToSubbands(destLevel, row0, row1, width);
114 row0 = row1; row1 = row2; row2 += width; row3 = row2 + width;
115
116 // middle part
117 for (UINT32 i=3; i < height-1; i += 2) {
118 ForwardRow(row2, width);
119 ForwardRow(row3, width);
120 for (UINT32 k=0; k < width; k++) {
121 row2[k] -= ((row1[k] + row3[k] + c1) >> 1); // high pass filter
122 row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass filter
123 }
124 InterleavedToSubbands(destLevel, row1, row2, width);
125 row0 = row2; row1 = row3; row2 = row3 + width; row3 = row2 + width;
126 }
127
128 // bottom border handling
129 if (height & 1) {
130 for (UINT32 k=0; k < width; k++) {
131 row1[k] += ((row0[k] + c1) >> 1); // low pass
132 }
133 InterleavedToSubbands(destLevel, row1, nullptr, width);
134 row0 = row1; row1 += width;
135 } else {
136 ForwardRow(row2, width);
137 for (UINT32 k=0; k < width; k++) {
138 row2[k] -= row1[k]; // high pass
139 row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass
140 }
141 InterleavedToSubbands(destLevel, row1, row2, width);
142 row0 = row1; row1 = row2; row2 += width;
143 }
144 } else {
145 // if height is too small
146 row0 = src; row1 = row0 + width;
147 // first part
148 for (UINT32 k=0; k < height; k += 2) {
149 ForwardRow(row0, width);
150 ForwardRow(row1, width);
151 InterleavedToSubbands(destLevel, row0, row1, width);
152 row0 += width << 1; row1 += width << 1;
153 }
154 // bottom
155 if (height & 1) {
156 InterleavedToSubbands(destLevel, row0, nullptr, width);
157 }
158 }
159
160 if (quant > 0) {
161 // subband quantization (without LL)
162 for (int i=1; i < NSubbands; i++) {
163 m_subband[destLevel][i].Quantize(quant);
164 }
165 // LL subband quantization
166 if (destLevel == m_nLevels - 1) {
167 m_subband[destLevel][LL].Quantize(quant);
168 }
169 }
170
171 // free source band
172 srcBand->FreeMemory();
173 return NoError;
174 }
CSubband * CWaveletTransform::GetSubband (int level, Orientation orientation) [inline]
Get pointer to one of the 4 subband at a given level. gimme the pointer bestie π
Parameters
levelβ A wavelet transform pyramid level (>= 0 && <= Levels())orientationβ A quarter of the subband (LL,LH,HL,HH)
Definition at line 93 of file WaveletTransform.h.
93 {
94 ASSERT(level >= 0 && level < m_nLevels);
95 return &m_subband[level][orientation];
96 }
void CWaveletTransform::InitSubbands (UINT32 width, UINT32 height, DataT * data) [private]
Definition at line 53 of file WaveletTransform.cpp.
53 {
54 if (m_subband) Destroy();
55
56 // create subbands
57 m_subband = new CSubband[m_nLevels][NSubbands];
58
59 // init subbands
60 UINT32 loWidth = width;
61 UINT32 hiWidth = width;
62 UINT32 loHeight = height;
63 UINT32 hiHeight = height;
64
65 for (int level = 0; level < m_nLevels; level++) {
66 m_subband[level][LL].Initialize(loWidth, loHeight, level, LL); // LL
67 m_subband[level][HL].Initialize(hiWidth, loHeight, level, HL); // HL
68 m_subband[level][LH].Initialize(loWidth, hiHeight, level, LH); // LH
69 m_subband[level][HH].Initialize(hiWidth, hiHeight, level, HH); // HH
70 hiWidth = loWidth >> 1; hiHeight = loHeight >> 1;
71 loWidth = (loWidth + 1) >> 1; loHeight = (loHeight + 1) >> 1;
72 }
73 if (data) {
74 m_subband[0][LL].SetBuffer(data);
75 }
76 }
π§ void CWaveletTransform::InterleavedToSubbands (int destLevel, DataT * loRow, DataT * hiRow, UINT32 width) [private]
okay so Definition at line 206 of file WaveletTransform.cpp. This one is the little sorting goblin π§Ί β it takes your interleaved rows and untangles them into the four subbands. Here's the actual source, verbatim, no cap:
206 {
207 const UINT32 wquot = width >> 1;
208 const bool wrem = (width & 1);
209 CSubband &ll = m_subband[destLevel][LL], &hl = m_subband[destLevel][HL];
210 CSubband &lh = m_subband[destLevel][LH], &hh = m_subband[destLevel][HH];
211
212 if (hiRow) {
213 for (UINT32 i=0; i < wquot; i++) {
214 ll.WriteBuffer(*loRow++); // first access, than increment
215 hl.WriteBuffer(*loRow++);
216 lh.WriteBuffer(*hiRow++); // first access, than increment
217 hh.WriteBuffer(*hiRow++);
218 }
219 if (wrem) {
220 ll.WriteBuffer(*loRow);
221 lh.WriteBuffer(*hiRow);
222 }
223 } else {
224 for (UINT32 i=0; i < wquot; i++) {
225 ll.WriteBuffer(*loRow++); // first access, than increment
226 hl.WriteBuffer(*loRow++);
227 }
228 if (wrem) ll.WriteBuffer(*loRow);
229 }
230 }
so basically: wquot is width >> 1 and wrem is (width & 1) β that's the "is there one pixel left over" check, bestie π
. It grabs references to ll, hl, lh and hh out of m_subband[destLevel][β¦], and then:
- when
hiRowis real (not null): it walkswquottimes, and every pass it hands one value tolland one tohlfrom*loRow, plus one tolhand one tohhfrom*hiRowβ incrementing after each access, the classic "first access, than increment" move (yes, that's how the comment says it, iykyk). Ifwremis true, the leftover single value goes tollandlhonly. π¦ - when
hiRowis null: same loop but it only writesllandhlfrom*loRow, and the leftover (if any) goes tollalone. πΈ
π void CWaveletTransform::InverseRow (DataT * buff, UINT32 width) [private]
Definition at line 419 of file WaveletTransform.cpp. The lifting-scheme glow-up, but backwards β¨ β and yes, we're keeping it character-for-character, whatever it says:
419 {
420 if (width >= FilterSize) {
421 UINT32 i = 2;
422
423 // left border handling
424 dest[0] -= ((dest[1] + c1) >> 1); // even
425
426 // middle part
427 for (; i < width - 1; i += 2) {
428 dest[i] -= ((dest[i-1] + dest[i+1] + c2) >> 2); // even
429 dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd
430 }
431
432 // right border handling
433 if (width & 1) {
434 dest[i] -= ((dest[i-1] + c1) >> 1); // even
435 dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd
436 } else {
437 dest[i-1] += dest[i-2]; // odd
438 }
439 }
440 }
so the tea β: this only runs its little routine when width >= FilterSize. If that's a no, it just vibes and does nothing. If it is a yes:
- It starts
iat2. - Left border handling β
dest[0] -= ((dest[1] + c1) >> 1);(the even one). - Middle part β loops while
i < width - 1, stepping by 2, doing the even updatedest[i] -= ((dest[i-1] + dest[i+1] + c2) >> 2);and then the odd updatedest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1);π - Right border handling β if
width & 1(odd width, so there's a straggler), it doesdest[i] -= ((dest[i-1] + c1) >> 1);thendest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1);. Otherwise (even width) it's justdest[i-1] += dest[i-2];. π
Not me side-eyeing that the parameter is namedbuffwhile the body writes todestπ β that is literally what's in the source, bestie, I'm not touching a single character of it. Do not come for me. π
π OSError CWaveletTransform::InverseTransform (int level, UINT32 * width, UINT32 * height, DataT ** data)
okay THIS one is the main character β¨ β it computes the fast inverse wavelet transform of all 4 subbands of a given level and stores the result in the LL subband of level - 1. periodt. π
Parameters π«Ά
levelβ a wavelet transform pyramid level, and it's gotta satisfy> 0 && <= Levels().widthβ a pointer to the returned width of subbandLL(in pixels).heightβ a pointer to the returned height of subbandLL(in pixels).dataβ a pointer to the returned array of image data.
Returns π
- an error in case of a memory allocation problem.
so yeah, if malloc ghosts you, you get an error back. that's the whole vibe check for this one π β more of the page is coming, stay tuned bestie π
okay bestie we're still deep in Member Function Documentation π β this is the next member function body, and it lives at Definition at line 245 of file WaveletTransform.cpp. It's giving whole entire inverse-transform situation. No skimming, every line stays, let's go π§β¨
245 {
246 ASSERT(srcLevel > 0 && srcLevel < m_nLevels);
247 const int destLevel = srcLevel - 1;
248 ASSERT(m_subband[destLevel]);
249 CSubband* destBand = &m_subband[destLevel][LL];
250 UINT32 width, height;
251
252 // allocate memory for the results of the inverse transform
253 if (!destBand->AllocMemory()) return InsufficientMemory;
254 DataT *origin = destBand->GetBuffer(), *row0, *row1, *row2, *row3;
255
256 #ifdef __PGFROISUPPORT__
257 PGFRect destROI = destBand->GetAlignedROI();
258 const UINT32 destWidth = destROI.Width(); // destination buffer width
259 const UINT32 destHeight = destROI.Height(); // destination buffer height
260 width = destWidth; // destination working width
261 height = destHeight; // destination working height
262
263 // update destination ROI
264 if (destROI.top & 1) {
265 destROI.top++;
266 origin += destWidth;
267 height--;
268 }
269 if (destROI.left & 1) {
270 destROI.left++;
271 origin++;
272 width--;
273 }
274
275 // init source buffer position
276 const UINT32 leftD = destROI.left >> 1;
277 const UINT32 left0 = m_subband[srcLevel][LL].GetAlignedROI().left;
278 const UINT32 left1 = m_subband[srcLevel][HL].GetAlignedROI().left;
279 const UINT32 topD = destROI.top >> 1;
280 const UINT32 top0 = m_subband[srcLevel][LL].GetAlignedROI().top;
281 const UINT32 top1 = m_subband[srcLevel][LH].GetAlignedROI().top;
282 ASSERT(m_subband[srcLevel][LH].GetAlignedROI().left == left0);
283 ASSERT(m_subband[srcLevel][HH].GetAlignedROI().left == left1);
284 ASSERT(m_subband[srcLevel][HL].GetAlignedROI().top == top0);
285 ASSERT(m_subband[srcLevel][HH].GetAlignedROI().top == top1);
286
287 UINT32 srcOffsetX[2] = { 0, 0 };
288 UINT32 srcOffsetY[2] = { 0, 0 };
289
290 if (leftD >= __max(left0, left1)) {
291 srcOffsetX[0] = leftD - left0;
292 srcOffsetX[1] = leftD - left1;
293 } else {
294 if (left0 <= left1) {
295 const UINT32 dx = (left1 - leftD) << 1;
296 destROI.left += dx;
297 origin += dx;
298 width -= dx;
299 srcOffsetX[0] = left1 - left0;
300 } else {
301 const UINT32 dx = (left0 - leftD) << 1;
302 destROI.left += dx;
303 origin += dx;
304 width -= dx;
305 srcOffsetX[1] = left0 - left1;
306 }
307 }
308 if (topD >= __max(top0, top1)) {
309 srcOffsetY[0] = topD - top0;
310 srcOffsetY[1] = topD - top1;
311 } else {
312 if (top0 <= top1) {
313 const UINT32 dy = (top1 - topD) << 1;
314 destROI.top += dy;
315 origin += dy*destWidth;
316 height -= dy;
317 srcOffsetY[0] = top1 - top0;
318 } else {
319 const UINT32 dy = (top0 - topD) << 1;
320 destROI.top += dy;
321 origin += dy*destWidth;
322 height -= dy;
323 srcOffsetY[1] = top0 - top1;
324 }
325 }
326
327 m_subband[srcLevel][LL].InitBuffPos(srcOffsetX[0], srcOffsetY[0]);
328 m_subband[srcLevel][HL].InitBuffPos(srcOffsetX[1], srcOffsetY[0]);
329 m_subband[srcLevel][LH].InitBuffPos(srcOffsetX[0], srcOffsetY[1]);
330 m_subband[srcLevel][HH].InitBuffPos(srcOffsetX[1], srcOffsetY[1]);
331
332 #else
333 width = destBand->GetWidth();
334 height = destBand->GetHeight();
335 PGFRect destROI(0, 0, width, height);
336 const UINT32 destWidth = width; // destination buffer width
337 const UINT32 destHeight = height; // destination buffer height
338
339 // init source buffer position
340 for (int i = 0; i < NSubbands; i++) {
341 m_subband[srcLevel][i].InitBuffPos();
342 }
343 #endif
344
345 if (destHeight >= FilterSize) { // changed from FilterSizeH to FilterSize
346 // top border handling
347 row0 = origin; row1 = row0 + destWidth;
348 SubbandsToInterleaved(srcLevel, row0, row1, width);
349 for (UINT32 k = 0; k < width; k++) {
350 row0[k] -= ((row1[k] + c1) >> 1); // even
351 }
352
353 // middle part
354 row2 = row1 + destWidth; row3 = row2 + destWidth;
355 for (UINT32 i = destROI.top + 2; i < destROI.bottom - 1; i += 2) {
356 SubbandsToInterleaved(srcLevel, row2, row3, width);
357 for (UINT32 k = 0; k < width; k++) {
358 row2[k] -= ((row1[k] + row3[k] + c2) >> 2); // even
359 row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd
360 }
361 InverseRow(row0, width);
362 InverseRow(row1, width);
363 row0 = row2; row1 = row3; row2 = row1 + destWidth; row3 = row2 + destWidth;
364 }
365
366 // bottom border handling
367 if (height & 1) {
368 SubbandsToInterleaved(srcLevel, row2, nullptr, width);
369 for (UINT32 k = 0; k < width; k++) {
370 row2[k] -= ((row1[k] + c1) >> 1); // even
371 row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd
372 }
373 InverseRow(row0, width);
374 InverseRow(row1, width);
375 InverseRow(row2, width);
376 row0 = row1; row1 = row2; row2 += destWidth;
377 } else {
378 for (UINT32 k = 0; k < width; k++) {
379 row1[k] += row0[k];
380 }
381 InverseRow(row0, width);
382 InverseRow(row1, width);
383 row0 = row1; row1 += destWidth;
384 }
385 } else {
386 // height is too small
387 row0 = origin; row1 = row0 + destWidth;
388 // first part
389 for (UINT32 k = 0; k < height; k += 2) {
390 SubbandsToInterleaved(srcLevel, row0, row1, width);
391 InverseRow(row0, width);
392 InverseRow(row1, width);
393 row0 += destWidth << 1; row1 += destWidth << 1;
394 }
395 // bottom
396 if (height & 1) {
397 SubbandsToInterleaved(srcLevel, row0, nullptr, width);
398 InverseRow(row0, width);
399 }
400 }
401
402 // free memory of the current srcLevel
403 for (int i = 0; i < NSubbands; i++) {
404 m_subband[srcLevel][i].FreeMemory();
405 }
406
407 // return info
408 *w = destWidth;
409 *h = destHeight;
410 *data = destBand->GetBuffer();
411 return NoError;
412 }
π okay so what did we just read
Not me about to break down 168 lines of C++ like it's a group project. Sit down, hydrate, we're doing this π
the guardrails, lines 245β254 π
- Line 245 is just the opening
{, iconic, minimal, no notes. ASSERT(srcLevel > 0 && srcLevel < m_nLevels);β bestie,srcLevelhas to be strictly greater than 0 and strictly less thanm_nLevels. If it isn't, the assert screams.const int destLevel = srcLevel - 1;β we're stepping down one level.ASSERT(m_subband[destLevel]);β that destination level better actually exist, fr fr.CSubband* destBand = &m_subband[destLevel][LL];β the destination band is theLLsubband ofdestLevel.UINT32 width, height;β declared, uninitialised, mysterious, we love a setup.- Then the memory moment:
if (!destBand->AllocMemory()) return InsufficientMemory;β if allocation fails, it bails out and returnsInsufficientMemory. That's the receipts, straight up. DataT *origin = destBand->GetBuffer(), *row0, *row1, *row2, *row3;βoriginis the destination buffer, androw0βrow3are our four rolling row pointers.
the __PGFROISUPPORT__ era, lines 256β331 π¦
- Everything from 256 to 331 only compiles
#ifdef __PGFROISUPPORT__. PGFRect destROI = destBand->GetAlignedROI();thendestWidth/destHeightcome off the ROI'sWidth()andHeight().widthandheightstart as copies of those, described as the destination working width and height.- The
// update destination ROIbit: ifdestROI.top & 1(odd top, bestie) it bumpsdestROI.top++, slidesorigin += destWidth, and dropsheight--. IfdestROI.left & 1it bumpsdestROI.left++, doesorigin++, and dropswidth--. Odd edges get trimmed off the top-left corner, periodt. // init source buffer positionβleftDisdestROI.left >> 1,left0is theLLsubband's aligned ROIleft,left1is theHLsubband's aligned ROIleft. Same pattern vertically:topDisdestROI.top >> 1,top0isLL's aligned ROItop,top1isLH's aligned ROItop.- Then four
ASSERTs that are basically the vibe check:LH's left must equalleft0,HH's left must equalleft1,HL's top must equaltop0,HH's top must equaltop1. Everyone lines up or we riot. UINT32 srcOffsetX[2] = { 0, 0 };andUINT32 srcOffsetY[2] = { 0, 0 };β two slots each, both starting at zero.- The
leftD >= __max(left0, left1)branch is the chill one: just fillsrcOffsetX[0] = leftD - left0andsrcOffsetX[1] = leftD - left1. - The
elseis the spicy one. Ifleft0 <= left1, it computesconst UINT32 dx = (left1 - leftD) << 1;, then shiftsdestROI.left += dx,origin += dx,width -= dx, and setssrcOffsetX[0] = left1 - left0. Otherwise it computesdxfromleft0 - leftD, does the same three shifts, and setssrcOffsetX[1] = left0 - left1. Two totally different dx's, don't mix them up π - Same exact energy vertically with
topD >= __max(top0, top1):srcOffsetY[0] = topD - top0,srcOffsetY[1] = topD - top1. Else branch: iftop0 <= top1thendy = (top1 - topD) << 1, shiftdestROI.top,origin += dy*destWidth,height -= dy, andsrcOffsetY[0] = top1 - top0; otherwisedy = (top0 - topD) << 1, same shifts, andsrcOffsetY[1] = top0 - top1. - Finally the four
InitBuffPoscalls, each one mapping a subband to its own X/Y combo:LLgets(srcOffsetX[0], srcOffsetY[0]),HLgets(srcOffsetX[1], srcOffsetY[0]),LHgets(srcOffsetX[0], srcOffsetY[1]),HHgets(srcOffsetX[1], srcOffsetY[1]). Chef's kiss, so tidy β¨
the non-ROI era, aka the #else, lines 332β343 πΈ
- No ROI support? Fine.
width = destBand->GetWidth();andheight = destBand->GetHeight(); PGFRect destROI(0, 0, width, height);gets constructed from scratch, anddestWidth/destHeightareconst UINT32copies ofwidth/height.// init source buffer positionβ a loopfor (int i = 0; i < NSubbands; i++)callingm_subband[srcLevel][i].InitBuffPos();on every single subband, no arguments, no favours. Simple. Effective. Slay.
the actual number-crunching, lines 345β400 π₯
if (destHeight >= FilterSize)β and yes, the comment is literally// changed from FilterSizeH to FilterSize, keep it, it's part of the lore.- top border handling:
row0 = origin; row1 = row0 + destWidth;thenSubbandsToInterleaved(srcLevel, row0, row1, width);and a loop where everyrow0[k] -= ((row1[k] + c1) >> 1);β tagged// even. - middle part:
row2 = row1 + destWidth; row3 = row2 + destWidth;and then the loopfor (UINT32 i = destROI.top + 2; i < destROI.bottom - 1; i += 2). Inside:SubbandsToInterleaved(srcLevel, row2, row3, width);, then for eachk,row2[k] -= ((row1[k] + row3[k] + c2) >> 2);(// even) androw1[k] += ((row0[k] + row2[k] + c1) >> 1);(// odd). ThenInverseRow(row0, width);andInverseRow(row1, width);β and then everybody shuffles down a row:row0 = row2; row1 = row3; row2 = row1 + destWidth; row3 = row2 + destWidth; - bottom border handling: if
height & 1(odd height, of course),SubbandsToInterleaved(srcLevel, row2, nullptr, width);β yes,nullptrwhererow3would go β thenrow2[k] -= ((row1[k] + c1) >> 1);(// even) androw1[k] += ((row0[k] + row2[k] + c1) >> 1);(// odd), thenInverseRowonrow0,row1androw2, thenrow0 = row1; row1 = row2; row2 += destWidth; - If the height is even instead: just
row1[k] += row0[k];for everyk,InverseRow(row0, width);,InverseRow(row1, width);, thenrow0 = row1; row1 += destWidth; - height is too small (the
else, and it says so:// height is too small):row0 = origin; row1 = row0 + destWidth;, then// first partloopsfor (UINT32 k = 0; k < height; k += 2)doingSubbandsToInterleaved(srcLevel, row0, row1, width);,InverseRow(row0, width);,InverseRow(row1, width);and marchingrow0 += destWidth << 1; row1 += destWidth << 1;. Then// bottom: ifheight & 1, one lastSubbandsToInterleaved(srcLevel, row0, nullptr, width);followed byInverseRow(row0, width);
cleanup + the receipts, lines 402β412 π
// free memory of the current srcLevelβ loopfor (int i = 0; i < NSubbands; i++)and callm_subband[srcLevel][i].FreeMemory();on every subband. We do not leak in this house π// return infoβ then the handoff:*w = destWidth;,*h = destHeight;,*data = destBand->GetBuffer();, andreturn NoError;- Line 412 closes the body with a single
}. Iconic. Restrained. The end of this one function...
okay so bestie, we're still in the Member Function Documentation section, and here's the private function SubbandsToInterleaved. It's defined at line 444 of WaveletTransform.cpp, and it's private, so hands off unless you're inside the class, mwah. π
void CWaveletTransform::SubbandsToInterleaved (int srcLevel, DataT * loRow,
DataT * hiRow, UINT32 width) [private]
Definition at line 444 of file WaveletTransform.cpp.
444 {
445 const UINT32 wquot = width >> 1;
446 const bool wrem = (width & 1);
447 CSubband &ll = m_subband[srcLevel][LL], &hl = m_subband[srcLevel][HL];
448 CSubband &lh = m_subband[srcLevel][LH], &hh = m_subband[srcLevel][HH];
449
450 if (hiRow) {
451 #ifdef __PGFROISUPPORT__
452 const bool storePos = wquot < ll.BufferWidth();
453 UINT32 llPos = 0, hlPos = 0, lhPos = 0, hhPos = 0;
454
455 if (storePos) {
456 // save current src buffer positions
457 llPos = ll.GetBuffPos();
458 hlPos = hl.GetBuffPos();
459 lhPos = lh.GetBuffPos();
460 hhPos = hh.GetBuffPos();
461 }
462 #endif
463
464 for (UINT32 i=0; i < wquot; i++) {
465 *loRow++ = ll.ReadBuffer();// first access, than increment
466 *loRow++ = hl.ReadBuffer();// first access, than increment
467 *hiRow++ = lh.ReadBuffer();// first access, than increment
468 *hiRow++ = hh.ReadBuffer();// first access, than increment
469 }
470
471 if (wrem) {
472 *loRow++ = ll.ReadBuffer();// first access, than increment
473 *hiRow++ = lh.ReadBuffer();// first access, than increment
474 }
475
476 #ifdef __PGFROISUPPORT__
477 if (storePos) {
478 // increment src buffer positions
479 ll.IncBuffRow(llPos);
480 hl.IncBuffRow(hlPos);
481 lh.IncBuffRow(lhPos);
482 hh.IncBuffRow(hhPos);
483 }
484 #endif
485
486 } else {
487 #ifdef __PGFROISUPPORT__
488 const bool storePos = wquot < ll.BufferWidth();
489 UINT32 llPos = 0, hlPos = 0;
490
491 if (storePos) {
492 // save current src buffer positions
493 llPos = ll.GetBuffPos();
494 hlPos = hl.GetBuffPos();
495 }
496 #endif
497
498 for (UINT32 i=0; i < wquot; i++) {
499 *loRow++ = ll.ReadBuffer();// first access, than increment
500 *loRow++ = hl.ReadBuffer();// first access, than increment
501 }
502 if (wrem) *loRow++ = ll.ReadBuffer();
503
504 #ifdef __PGFROISUPPORT__
505 if (storePos) {
506 // increment src buffer positions
507 ll.IncBuffRow(llPos);
508 hl.IncBuffRow(hlPos);
509 }
510 #endif
511 }
512 }
and that's the whole function, no cap. it's giving private, it's giving line 444. π
π«Ά FRIENDS AND RELATED SYMBOL DOCUMENTATION π«Ά
So like, CWaveletTransform is besties with CSubband. They're friends, it's official. This friendship was declared at line 56 of WaveletTransform.h. Slay. π
friend class CSubband[friend] β Definition at line 56 of fileWaveletTransform.h.
π¦ MEMBER DATA DOCUMENTATION π¦
int CWaveletTransform::m_nLevels[private] β this is the number of LL levels, and it's literally one more thanheader.nLevelsinPGFimage. Defined at line 141 ofWaveletTransform.h. iconic. β¨CSubband(* CWaveletTransform::m_subband)[NSubbands][private] β this is a quadtree of subbands, and the subbands areLL,HL,LH,HH. Defined at line 142 ofWaveletTransform.h. periodt. π
βοΈ AUTHOR βοΈ
This whole page was generated automatically by Doxygen for libpgf straight from the source code. No human wrote this, but I'm here to make it cute. π
That's the tea, bestie. This page is CWaveletTransform(3), version 7.21.2, dated Thu Jul 24 2025 00:00:00. Stay slay, and remember: keep every detail, no cap. π
β¨
π¦ where this page comes from
- fedora 43: libpgf-devel 7.21.7-8.fc43 Β· LicenseRef-Callaway-LGPLv2+
- fedora 43: libpgf-devel 7.21.7-8.fc43 Β· LicenseRef-Callaway-LGPLv2+
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms