Blog · 2026-05-19 · 7 min read
Total integration time per target across multiple imaging sessions
"How many hours of luminance do I have on M81?" sounds trivial until you actually try to answer it for an archive that spans multiple years, multiple rigs, and a couple of different sites. The arithmetic isn't the problem. The data is.
This piece is about the per-target question specifically — not "how many hours have I imaged in total this year", but "what do I have on this object". That's the number that drives actual imaging decisions.
Why the per-target question is the one that matters
A grand total ("612 hours of integration since I started") is a vanity metric. It doesn't help you plan tonight. The number you actually need, sitting in the warm room at 9pm with a clear sky and three potential targets, is per-target: M81 is at 22h luminance and only 4h Ha — go shoot Ha. M31 has plenty across every filter — leave it alone. NGC 7000 is barely started.
Per-target totals are what tell you a target is "done" (whatever your personal SNR bar is), which one is starved of a particular filter, and which one you've been quietly neglecting. A generic "total hours imaged" tells you exactly none of that.
The manual approaches and where they break down
Most imagers cycle through several of these before giving up. Each one works in the narrow case it was designed for, and each one falls apart the moment your archive spans more than one sequencer or more than one season.
Counting files in folders, multiplied by sub length
ls | wc -l in the M81 luminance folder, multiplied by 300 seconds, divided by 3,600. Fine if every file in that folder is a light, every sub is the same length, and that folder is the only place M81 luminance lives. In a real archive none of those hold — there are test frames, the night you tried 180s subs, and a second copy of some of the frames inside a stacking project folder.
NINA's project / target totals
NINA tracks integration per target inside its project view, and the numbers there are good — for what NINA captured. They do not cover the season you used Sequence Generator Pro, frames a friend contributed, or anything from before you set up the project. NINA's view of your M81 is "M81 as recorded by NINA on this machine."
SGP's run history
Sequence Generator Pro keeps a run log per sequence. Same shape of problem: it's a per-sequence record, not a per-target archive. If you've rebuilt the sequence file, or moved machines, or alternated SGP and NINA across nights, the per-target total in SGP's history is a partial answer.
APT's session log
APT writes a session log per imaging plan. Useful for reviewing what happened on a given night; not useful for "across every night I've ever spent on this target". The log is a session record by design.
FITS Liberator (or any single-file inspector)
FITS Liberator and similar tools let you open one file at a time, read its header, see its exposure. Perfect for confirming a single frame. Useless as an aggregation method — nobody is going to open 4,000 files by hand.
AstroImageJ aperture / stats inspection
AstroImageJ can ingest a folder and report per-file statistics, which is closer to the right shape. It's still oriented around a working set of frames you've loaded for analysis — not your whole archive across years and rigs. It answers "what's in this stack" rather than "what's in everything I've ever shot on this object".
The pattern is consistent: each tool answers the question correctly for the slice it owns (this session, this sequence, this stack), and the per-target archive total is somebody else's problem.
What "by target" actually means once an archive spans years
The arithmetic — sum exposures, group by target — is genuinely easy. The work is in agreeing on what "by target" means across a long archive. A non-exhaustive list of the things that will trip you up:
- Target name disagreements. Your sequencer wrote
OBJECT = "M31"on Monday,"Andromeda"on Tuesday, and"NGC 224"in 2022 when you were briefly using a different catalogue plugin. All three are the same galaxy. None of them aggregate without a normalization step. - Rig changes. Hours on M81 through a 130mm refractor at f/7 are not directly comparable to hours through an 8" SCT at f/10. Same target, different image scale, different SNR per hour. You usually want to bucket per-target totals per rig, not collapse them.
- Filter naming drift.
"Ha","H_alpha","HA","H-alpha"— same filter, four spellings, depending on which filter wheel profile was active that night. Without normalization they group as four separate filters and your Ha total comes out four times too small per bucket. - Framing variants. If you reframed M31 by 90 degrees this year to capture more of the outer halo, do those hours add to last year's framing or sit alongside it? Either answer is defensible; you have to pick one.
- Test frames mixed in. Focus-test exposures, the 5-second sub you took to confirm the mount was tracking, the frame from the night a cloud rolled in halfway through. They have
IMAGETYP = "LIGHT"and they're on the right target, but they're not really integration.
None of this is conceptually hard. It's all bookkeeping. But until it's done, summing EXPTIME grouped by OBJECT gives a misleading answer.
A metadata-first approach
The FITS headers your sequencer already writes contain the answer. The recipe, once stated:
- Walk every
.fit/.fitsfile in every location your archive lives — local disk, NAS, that external drive from 2023. - Read
OBJECT,FILTER,EXPTIME,IMAGETYPfrom each header. (See FITS headers for the full set Photon Ledger reads.) - Drop anything that isn't a light frame.
- Normalize target names against an alias table —
M31,Andromeda,NGC 224,NGC224all map to a single canonical target. - Normalize filter names the same way.
- Sum
EXPTIMEgrouped by (target, filter). Optionally split further by year, rig, or site.
The output is a per-target ledger: one row per (target, filter), totals in hours, sortable, filterable, exportable. That row tells you whether to point at M81 tonight or move on.
The folder layout doesn't matter — date-first, target-first, or the chaotic hybrid most archives end up in. The headers carry the same information regardless. See folder schemas for the layouts that parse cleanly with no extra hinting.
What to do with the per-target number once you have it
Per-target hours are useful only insofar as they change a decision. A few decisions they should be informing:
- What needs more time, and in which filter. If M81 is at 22h L and 4h Ha, the next clear night with decent transparency is an Ha night. The ledger surfaces this; memory does not.
- What's done. Knowing a target has crossed your personal "enough" line is permission to move on. Without a real number it's easy to either over-image a target you've already nailed or under-image one you only think you've covered.
- Comparison against an SNR-target. For a given optical setup, sky brightness, and camera, you can estimate roughly how many hours produce a given SNR. The per-target ledger is what you compare against — not a vibe.
- Identifying lopsided targets. 30h luminance, 0h colour. 12h Ha, 0h OIII. These are common; they're also common to not notice until you sit down to process and realise the data isn't balanced.
Where Photon Ledger fits in
This per-target view is one of the views Photon Ledger produces out of the box. Point it at your archive, let it walk the FITS headers, and the per-target / per-filter table is one of the first things it shows you — sortable, exportable, and split by rig or year if you want.
The free tier indexes up to 5,000 frames on SQLite, which is enough for many beginner and intermediate archives. Download for macOS, Windows, or Linux →
Related reading
- How to count your astrophotography integration time — the broader piece on why integration counting is harder than it looks.
- Folder schemas — the layouts Photon Ledger parses without extra configuration.
- FITS headers — the specific headers Photon Ledger reads and what it does with each.
- Getting started — install and first scan.