Processing log · September 2026
Wolf's Cave (vdB 152 / Barnard 175)
The processing, warts and all
This is the other half of the Wolf's Cave story. The capture log covers what happened under the sky; this is what happened at the desk, in the order it happened, including everything that went wrong.
I process in PixInsight with an AI assistant beside me. It doesn't touch PixInsight — it reads the files, measures them, and tells me what changed. Every number below was measured off the actual files, mostly out of the processing history stored inside each XISF, not remembered. Several of the mistakes were the assistant's. Several were mine. They are all here.
Before PixInsight — culling and stacking in Siril
What to throw away, and the rule that saved 62 frames. The first cull graded on eccentricity and threw out 83 luminance subs from night 2. I stopped it: an elongated but symmetric star is an egg, and BlurXTerminator fixes an egg. What can't be fixed is a comet — a one-sided tail where the mount was kicked mid-exposure and the flux piled up at one end. Eccentricity can't tell them apart; both measure about 1.6. So the assistant wrote a grader that measures, per star, the flux-weighted skew along that star's own long axis: symmetric shapes sit near zero however stretched they are, a tail drives it up. Comets and streaks out, eggs kept. 62 frames came back, and night 2's luminance went from 6h 02m to 7h 29m. I asked to see the difference rather than take it on faith, so it built a gallery of magnified stars: kept round, kept egg, culled comet, culled streak. At 7× the difference is obvious; at full frame it's invisible, which is why I couldn't see it.
Final tally: 953 of 1,095 subs kept — night 1 423 of 438, night 2 186 of 298, night 3 344 of 359.
Stacking. Siril per night: calibrate with that night's own bias, darks and flats, register with global star alignment, stack winsorized sigma clip with additive-with-scaling normalisation. Then the per-night masters were registered onto the long luminance and combined. Both meridian flips crossed cleanly — 1,830 star matches, rotation measured at +179.77°, inliers 1.000 — so the 180° orientation split never became a problem. No debanding: measured column noise 1.56 ADU against 1.83 for rows, so the columns were the cleaner axis. Dithering had done its job.
What night 2 was worth, measured. 65 % more integration bought about half the expected depth. Its frames are genuinely poorer — best FWHM 2.18 px against night 1's 1.77 — and a noise-weighted stack correctly discounts them.
Is the hydrogen alpha even real? One hour on a faint target is easy to imagine. The arc measures 1.32 sigma per pixel in the Ha master, and to check the noise behaved as it should, the assistant stacked half the subs: 0.97 sigma at 30 minutes against 1.32 at 60, which is 96 % of the square-root law. Real, and worth blending — gently.
Three mistakes in this stage, all the assistant's:
- It reported the channel masters were misaligned by hundreds to 1,800 pixels. I said that couldn't be right. It was phase correlation, which on a field this rich locks onto the star field instead of the registration, and it gave a different answer every run. The honest check was the dumb one: find the brightest stars in luminance, look in the same box in every other master, read off the offset. Answer: single-digit pixels.
- Its stacking script wrote the masters into a scratch folder that it then deleted, and still exited reporting success — because Siril sets its own working directory and the script had passed a relative path. Never hand Siril a relative path.
- It built the calibration tree out of symlinked folders, which its own file scan wouldn't follow, so every dark and flat read as missing.
Pass 1 — Sept 12 to 17 — learning the target the hard way
The blown star cores. The bright stars were saturated in the 90 s subs, so I shot 10 s sets to repair them. HDRComposition looked perfect on every metric the assistant ran: 96–100 % core recovery, profiles matching within 1 %, noise unchanged. I looked at it and said it was wrong. It took most of a day to find why: HDRComposition had fitted the exposure ratio at 8.01 when the true ratio was 8.47, and that 5 % error cut a dark trench around every star at 6–9 pixels radius, plus it swapped 163,775 isolated single pixels across the frame. A clean sweep of metrics only proves the metrics you chose didn't catch it. We rebuilt the repair in PixelMath instead: it only ever adds light, in the top two pixels of a core, and the minimum change anywhere is exactly zero.
How we actually did it. For each channel the assistant measured two numbers off the real stars: the flux ratio between the long and short exposures, and the level where the long frame stops being linear. Ratios came out L 8.47, R 7.61, G 7.28, B 8.25 — not the 9 you would guess from 90 s over 10 s, because the shorter frames lose a slice to the shutter and the read. Then one PixelMath expression per channel: below the threshold keep the long exposure untouched, above it swap in the short one scaled by that ratio, with a narrow feather across the join so nothing steps. Thresholds were L 0.70, R 0.25, G 0.45, B 0.50. Verified afterwards: light was only ever added, only in the top couple of pixels of a core, and below the threshold the file is bit-identical to the original.
One trap in it. A repaired core comes out eight times brighter than the old clipped ceiling, which is past PixInsight's 1.0 limit, and the channel combination quietly truncated several hundred pixels on the first try. The fix was to rescale the whole image down by 0.1158 before combining, so nothing overflows — and that rescale is exactly what made the linear preview look broken.
And the lesson for next time: 10 s was still too long. Reconstructing the true stellar peaks from the unsaturated wings says 49 stars still clip at 10 s, 21 at 3 s, 12 at 2 s and 5 at 1 s. So the short set should be 1 s, not 10. About five of the very brightest stars in this field can't be saved at any sane exposure.
Then it turned out not to matter. After a normal stretch the repaired and unrepaired cores differ by 0.0001. Both saturate at 0.98. The whole star-core saga bought nothing visible.
The linear preview lies. The repaired image looked ringed and posterised on screen. It wasn't. The repair had pushed the data's scale up so far that the background sat below one display level. Stretched properly, the same file holds 40,000 distinct values in a background patch. Never judge a blended linear image by its screen stretch.
The red background that wasn't a red background. I spent two sessions chasing a red cast. Measured across the linear masters, the red ramp changed between nights while the dust didn't — so it was sky gradient, not colour. Fixing it was a gradient job, not a colour job.
The mask that couldn't exist. I wanted to lift filament detail in the dark nebula without touching the background, so we tried to build a mask of the cave. A brightness range mask can't do it: the dark nebula sits on the same side of any threshold as the sky. A local-contrast mask can't either — measured, it was selecting the background mottle, the exact thing I wanted to suppress. Two mornings gone. Then I applied the enhancement globally with no mask at all and measured the background before and after: it hadn't suffered. The machinery was protecting against damage that doesn't happen.
LocalHistogramEqualization did nothing, three times. At amount 0.21, then 0.50, then 0.85, the cave contrast moved about 1 %. Cause: HDRMultiscaleTransform had already redistributed the local contrast, so there was nothing left to equalise. On a chain that contains HDRMT, expect LHE to do almost nothing.
Denoising after the stretch made it worse. It halved the fine grain but pushed the leftovers into the 2–8 pixel blotch band and nearly tripled the colour speckle. That's what "plastic" looks like. The fix was to move denoise, and sharpening, into the linear stage — which is what pass 2 does.
The curves that made colour by accident. My favourite version, 4f, had rich colour. The assistant simulated its five curves and found the saturation was manufactured: each curve crushed the black point, which pushes red, green and blue apart, and five of them stacked up. The same mechanism made the red cast I kept complaining about. You can't keep one and lose the other; they are the same thing. The honest saturation of the data was about 0.11, not 0.42.
The correction I had to make twice. The assistant told me the "red chroma noise" had dropped by 2.5×. I said the red was gone because everything was gone. It re-measured: colour signal had fallen by the same factor. A chroma-noise number means nothing unless you hold the colour constant.
The teal. I said the green-blue cast followed the nebula. The assistant ran a correlation over the whole frame, got 0.007, and told me it was a gradient. I told it my eyes disagreed. It rendered the colour as a picture and looked: sharp, filamentary, tracing the dust exactly — real reflection-nebula colour. The correlation had averaged opposing signs to zero. Since then: render it and look first, measure second.
PixInsight crashed twice, once with two days of uptime, and took the unsaved windows with it. The processed luminance existed only inside a project file, because the disk copies had been in a folder I'd cleared out. Rule now: anything reused gets saved to its own file before anything gets deleted.
Where pass 1 ended. Twenty-three versions. I had the assistant build a flip book of all of them, ranked by measurement, and picked two favourites. Then I decided the whole thing should be rebuilt properly, from the master channel stacks, with nothing carried over but what I'd learned.
Pass 2 — Sept 18 to 20 — the one that worked
Gradient correction first, and it is the most important step. I ran three rounds of trials — scale, structure separation, and the scale factors — and the assistant ranked each one on flatness, on how much dust the model contained, and on the corner where the splotch used to be. Winner: scale 768, separation 2, smoothness 10, and all three scale factors at 1.6, which is the class method of raising them together. The sky's green tilt went from 15 % top-to-bottom down to 1.6 %, with no dust in the model at all. Everything downstream inherits this.
No nebula-free sky. For colour calibration I wanted the background patch to be real sky. There isn't any: the assistant scanned every window in the frame on a starless version and the flattest ones were all dust. We used the opaque core of the dark cloud, which is the closest thing to pure sky glow, and also ran a version with no patch at all. The difference after the stretch was about 10 %; I picked the neutral one by eye.
Sharpening, which pass 1 never did. Every BlurXTerminator run in pass 1 was in correct-only mode, so its sharpening values were ignored and my stars stayed soft — that's why they looked blurry and I couldn't find out why. Pass 2 ran it with sharpening on: star widths dropped 25–34 %, with no dark rings and no rise in background noise.
Denoise, measured by scale. At 0.90 the luminance looked plastic to me. Measured: it removes 85 % of the fine grain but only 24 % of the 5–9 pixel mottle — at any amount. The amount only decides how much grain is left covering the mottle. At 0.60 the two sit in balance. The mottle itself is a depth problem, not a processing one.
How hard to stretch. This was the question I most wanted answered. The answer: grain divided by sky is about 0.10 no matter how hard you stretch, so no stretch level makes the data cleaner. What matters is where the sky lands. Put it at the level you want in the final and the curves never have to drag it back down — and that drag is exactly what made my earlier version splotchy. Target background 0.120.
Curves on L, not on K. A brightness curve on K pushes the three channels together and desaturates; on CIE lightness it leaves colour alone. Pinned at the sky, with two extra points at the top so the bright tip of vdB 152 keeps its highlights — the earlier version had 2.8 % of that tip flattened to white, this one has 0.3 %.
Hydrogen alpha, three times. At 0.25, matching pass 1, the red was too weak because pass 1's curves had been multiplying colour on the way to the final and these ones don't. At 0.75 it was a touch strong. 0.50 is the one, with the planetary nebula DeHt 5 masked so it keeps its blue centre inside a red rim.
The stars, and my girlfriend. I reduced the small stars with a median transform, three scales removed. She looked at it and said leave all the stars in. She was right — with the full field the dust sits inside the Milky Way instead of floating on grey. We settled on two scales removed, which keeps the sky dense and takes the speckle. Measured, the leftover texture at that scale is the small stars themselves, not noise: stripping the star layer's background entirely moves it by 2 %.
The assistant's mistakes, since I said everything would be here
- It told me a file was "the keeper" based on a chroma-noise number, when the image was simply desaturated.
- It answered a visual question with a correlation coefficient instead of rendering the map and looking.
- It said "lower left" twice while I was looking at the image the other way round; it had mixed portrait and landscape.
- It blamed a rise in blotchiness on the denoise. Re-measured in one fixed patch, the denoise wasn't responsible — the star layer was.
- It told me a mask had protected the planetary nebula. The file's own history showed the mask never applied, and the red had gone straight into the middle of it.
- It compared a linear number to a stretched one and called them the same measurement.
- It wrote a script with a bug it had written down and recorded as a rule the day before.
- Twice it answered "just do this and this and this" when I'd asked for one keystroke.
The pattern in all of them: a number reported without its control, or an answer given from memory instead of from the file. What works is the opposite — read the file, render the picture, and when I say my eyes see something, test harder instead of restating the statistic.
What this target changed for good
- Gradient correction is the most important step. Trial several settings and rank them; never run it once and move on.
- Fix everything that can only be fixed while linear — gradient, colour, sharpening, denoise, narrowband — before stretching.
- Stretch so the sky lands where you want it in the final. Curves should lift the subject, never drag the background down.
- Brightness curves go on L, saturation goes on S, and both go on while the image is starless.
- Denoise removes grain, never mottle. If the mottle bothers you, that's more integration, not more denoise.
- Save every reusable intermediate as its own file. A window or a project file is not a backup.
- Read the settings out of the file's own history. Icon names lie; histories don't.
- Measure a colour claim with saturation beside it, and a noise claim with signal beside it.
- Render derived maps as pictures and look at them before trusting a single correlation number.
- Judge a version against the one before it on the same measurements, in the same orientation, or the comparison means nothing.
What it cost: six days, twenty-three versions in the first pass and one in the second. The second pass took two days because the first one had already made every mistake.