Which of your stacked versions is really the best one?
Deutsche Fassung: README.md
finiSCOPE takes several stacked TIFFs of the same capture — different frame
percentages, different noise-robust settings, with and without drizzle —
measures them all by the same rules and tells you in one sentence which
version won and why.
Instead of clicking back and forth on screen and guessing, you get numbers,
curves and a verdict in plain language.
Built for the sun (H-alpha and white light), the moon and the planets.
Free of charge, no warranty, use at your own risk.
finiSCOPE is released under the MIT licence (see LICENSE) and
may be shared freely. Liability for damages is excluded.
Contents
- Download and run the finished app
- Using it
- The measurements — in plain words
- The two ratings
- The score (rank)
- Object profiles
- Drizzle, .as3 and sessions
- Running from source
- Building the programs yourself
- When something goes wrong
- How the project is laid out
- Colours
- Assumptions made
1. Download and run the finished app
If you use the finished programs you need no Python and install
nothing. Python is bundled inside the app.
macOS
- Download
finiSCOPE.appand drag it into your Applications folder. - On the very first launch: do not double-click. Instead
right-click the app → Open → Open again in the dialog.
Why? The app is not registered with Apple (that carries a yearly
developer fee). macOS therefore blocks a plain double-click and reports
an unidentified developer. Confirming once via right-click → Open is
enough; after that it launches normally.
- If macOS says the app is damaged: that happens with files downloaded
from the internet. Once in Terminal:
bash
xattr -dr com.apple.quarantine /Applications/finiSCOPE.app
Requires macOS 11 or newer on an Apple Silicon Mac (M1 to M4). Older Intel
Macs need a build made on an Intel Mac — see
section 9.
Windows
- Download the ZIP file and extract it completely, for example to
C:Program FilesfiniSCOPE.
Important: extract the whole folder; do not just pull the.exeout of
it — it needs the files beside it. - Double-click
finiSCOPE.exe. - On first launch Windows Defender SmartScreen reports “Windows
protected your PC”. That is normal for programs without a purchased
signing certificate:
→ click “More info”
→ “Run anyway”
From the second launch onwards the message does not appear again.
Language
finiSCOPE speaks German and English. Switch under View → Language; the
choice is remembered.
2. Using it
1 · Load images. Drag the stacked TIFFs into the window — one at a
time, several at once, or a whole folder. Alternatively use Choose files
or File → Open images. Two or more versions of the same capture
make sense.
2 · Pick the object type. Sun, moon or planet. This switches the
measurement bands and the size of the measurement window.
3 · Optional: enter your optics. Pixel size (µm), focal length (mm) and
aperture (mm).
These figures change neither the measurement nor the score — they
unlock additional statements that are impossible without them:
| Entered | What you get in addition |
|---|---|
| pixel size + focal length | sampling in arc seconds per pixel and the effective resolution of your image in arc seconds |
| plus the aperture | % of optimum — how close the image gets to the theoretical resolving power, and the sampling rated as good / too coarse / too fine |
If the fields stay empty everything else works unchanged; only those lines
are missing. They cannot be filled automatically — neither the TIFF nor
AutoStakkert’s .as3 contains such information. finiSCOPE does remember
them, though: type them once and they are there next time.
Typical values: pixel size is in your camera’s data sheet (e.g. 2.9 µm for
an ASI 174/178, 3.76 µm for an ASI 183). Focal length including any Barlow.
Aperture is the diameter of the telescope.
4 · Read the result.
- Winner box at the top: the best version with a one-sentence reason.
- Image view: the image with the measurement window as a blue
rectangle. Beside it, in a fixed place, the content of that window at
original size. Switch version and the same spot from the other image
appears there. So you compare by eye exactly what was measured — the
numbers say what is better, this crop shows how it looks. - Chart: one curve per image, and below it a sentence in plain
words saying what can be seen — for instance “the curves lie almost on
top of each other, the difference is in the noise”. Especially when two
versions are nearly equally sharp the curves overlap and you seem to see
nothing; that sentence is then the actual answer. - Table: two ratings side by side — quality (absolute, with a
light) and rank (the comparison among each other). Click a row to
open the raw values and a longer plain-text verdict. ✕ Remove at the
end of a row takes an image out of the comparison; the file on disk is
left untouched.
The measured values are colour-coded as well: green means practically
level with the best image of the run, neutral means slightly behind, warm
means clearly worse. For signal-to-noise the colour is absolute — it
does not depend on what else is loaded.
Switching between versions works three ways: the thumbnail strip above
the image view, clicking a table row, or the arrow keys ← →. Image,
1:1 crop and highlighted curve all follow.
5 · Adjusting the measurement area. By default finiSCOPE looks for the
most detailed region — not simply the centre of the frame. On a full
disc the window therefore lands on an active region or a spot group by
itself rather than on quiet surface.
It is searched not in the first image but in the average of all loaded
images. That way the location does not depend on which file happened to
load first, and it sits where every version shows structure. The window is
then identical for all images.
If one capture differs strongly — different dimensions, a completely
different brightness — it cannot contribute, and finiSCOPE points out in
the notice bar that the images probably do not belong together.
To rate a particular spot, drag a rectangle in the image view. While
dragging, its size in pixels is shown. The window is always square —
the frequency analysis requires that — and is placed on the centre of
the area you dragged.
Once set, it can be fine-tuned:
- drag inside it to move it,
- drag a corner to resize,
- zoom in first to place it as precisely as you like.
The area applies to all images alike — only then is the comparison
fair. The this image only tick makes it apply to the selected image as an
exception. Reset area returns to automatic placement.
Offset between captures is compensated automatically. Two stacks from
the same session are almost never aligned to the pixel — the sun drifts,
AutoStakkert anchors differently. With Compensate offset ticked (the
default), the measurement window is moved in every further image to where
the same content sits. The offset found is listed in that row’s raw values.
6 · Zooming. The scroll wheel or two-finger swipe zooms up to 12×,
always towards the pointer. Pan with the Alt key held (or the middle
mouse button); double-click shows the whole image again. The zoom is
kept when switching versions — so you can flick between two stacks of the
same spot and see the difference directly.
7 · Saving. Save CSV writes every raw value (semicolon separated, so
Excel opens it directly). HTML report produces a single self-contained
file with images, chart and verdicts — ready to send or archive. Both are
also in the File menu.
The two chart views
Top right you can switch between two presentations of the same
measurement:
- Sharpness curve (default) — every curve starts at full detail on the
left and drops where the image stops carrying detail. The further right
a curve falls off, the sharper. The dot on the dashed line is exactly
the MTF50 value from the table. This is the view for comparing. - Power spectrum — the technical raw form. It falls off steeply towards
the right by nature; that is a property of the subject, not of sharpness.
In exchange you can see the noise plateau here: a curve that stays flat
and high on the right is noisy.
3. The measurements — in plain words
Measurement always happens inside the measurement window, never across the
whole image. Every image gets the same window in the same place.
Sharpness (MTF50)
What: how fine the image still shows real detail, in cycles per pixel.
0.5 would be the theoretical ceiling; good solar images land at 0.15–0.25.
Remember: higher = sharper.
Pitfall: hard sharpening lifts the value artificially while driving up
the noise floor at the same time. Never read it alone — always together
with SNR and noise.
Amount of detail
What: how much real structure the image holds — the power in the detail
band of the spectrum, after the noise share has been subtracted.
Normalised to the best image of the run = 1.00.
Remember: higher = more real detail.
Why the subtraction matters: noise is broadband and would otherwise be
counted as “detail”. A noisy image would then look more detailed than a
clean one — exactly what this tool is meant to prevent.
Signal-to-noise (SNR)
What: how much structure there is compared with the noise, in decibels.
Above 35 dB is very clean, below 20 dB clearly grainy.
Remember: higher = cleaner.
What for: it shows whether sharpness was bought dearly. High MTF50 with
low SNR almost always means oversharpened.
Noise level
What: how strong the per-pixel noise is — independent of how much
structure the image holds.
Remember: lower = better.
How it is measured: with a Laplacian-style filter that largely cancels
smooth gradients and even edges; what remains is essentially noise. The
advantage: it works even on crops with no dark sky at all, such as a
full-frame active region. In addition — where present — the spread in the
dark part of the image is reported as background.
Contrast and tonal range
What: how strong the brightness differences are and how much of the
available tonal range is used.
Remember: higher = punchier, low = flat.
Pitfall: contrast can be changed at will afterwards. That is why it
only counts 10 % in the score.
Local sharpness
What: a quick sharpness figure in the spatial domain (spread after a
high-pass filter). It usually tracks MTF50 but reacts more strongly to
sharpening.
Noise plateau
What: the frequency at which the curve sinks into the noise (given as a
bin number from 0 to 255).
Remember: early = lots of noise, late = clean.
Effective resolution (with optics figures only)
What: your sharpness converted to arc seconds, right next to the
theoretical limit of your aperture (Dawes limit, 116 ÷ aperture in mm).
Remember: smaller is better. 3.4″ means two details must be at least
3.4 arc seconds apart to still be seen as two.
The value beside it — what the aperture could do in theory — is therefore
always smaller than the one reached; you cannot beat physics. The
percentage says how close you get.
Example: 3.44″, 2.90″ would be possible — reached: 84 %. If the
percentage stays below 60 % it is usually seeing, focus or too few good
frames.
Sampling (with optics figures only)
What: how much sky lands on one pixel, in arc seconds per pixel.
Rule of thumb: about 2–3 pixels per smallest resolvable detail.
Much coarser and detail is lost (a Barlow helps). Much finer and you only
get more noise and longer exposures without any gain.
4. The two ratings
finiSCOPE answers two different questions, and it matters to keep them
apart:
| Question | Where | |
|---|---|---|
| Quality | Is this image good in its own right? | light and word in the table |
| Rank | Which of the loaded versions is the best? | 1., 2., 3. with points |
The difference counts: if you load three mediocre versions, the best of
them still comes first — but the light stays blue or red. If every row
is blue, finiSCOPE additionally points this out in the notice bar, because
even the winner is then not worth much.
What quality is worked out from
Only from quantities that have an absolute meaning:
- Share of the theoretical resolving power of your aperture — the most
honest measure there is. Needs the optics figures. - Signal-to-noise in decibels — fixed thresholds, independent of the
subject.
From these comes a word: very good · good · medium · weak · very weak.
The worse of the two decides — a razor-sharp but heavily noisy image is
simply not good.
Without optics figures the rating is provisional and rests on the noise
alone: whether 0.18 cycles/pixel is much or little depends on aperture and
focal length, which cannot be said without them. The tooltip says so.
Over 100 % is impossible. If the calculation gives more than the
aperture can physically deliver, finiSCOPE reports unclear — usually the
image was sharpened very hard (the measurement then fakes resolution that
never came from the telescope) or the focal length entered does not match.
5. The score (rank)
The score condenses everything into a number from 0 to 100:
| Metric | Weight | Direction |
|---|---|---|
| Sharpness (MTF50) | 40 % | higher is better |
| Detail energy | 25 % | higher is better |
| SNR | 20 % | higher is better |
| Contrast | 10 % | higher is better |
| Noise floor | −15 % | lower is better |
The most important thing about the score
Scores only apply within one comparison run.
The best loaded image always gets exactly 100 — even if every loaded
version is mediocre. So 100 means “the best of those loaded here”,
not “an absolutely good image”.That is why the winner box says “best of N images” rather than
“score”.Comparing scores across sessions is meaningless. A 95 from yesterday may
be better or worse than a 100 from today.
A single image gets no score at all — a dash appears instead. A
relative value without anything to compare would be a false statement.
So what is absolutely meaningful?
Three things — regardless of what else is loaded:
| Value | Absolute meaning |
|---|---|
| % of optimum | Needs the optics figures. Says how close the image gets to the theoretical resolving power of the aperture. Above 85 % is maxed out; below 65 % something is usually in the way — seeing or focus. |
| SNR | Above 35 dB very clean, 28–35 clean, 22–28 usable, 16–22 visibly grainy, below that heavily noisy. The value is coloured accordingly in the table. |
| Sampling | Needs the optics figures. Good / too coarse / too fine. |
Every other figure — score, detail energy, MTF50 — is relative and only to
be read within one run.
The weights live as the constant WEIGHTS at the top of
analysis/scoring.py and can be changed there.
6. Object profiles
Each profile decides where measurement happens and which
frequencies count as real detail (bin limits referring to a 512 px
window):
| Profile | Detail band | Noise from | Window | Where it measures |
|---|---|---|---|---|
| Sun | 50–125 | 150 | 512 px | most detailed region |
| Moon | 55–135 | 155 | 512 px | most detailed region (usually at the terminator) |
| Planet | 40–110 | 140 | 256 px | disc found by brightness threshold, window centred on it |
For small images or small planetary discs the window is shrunk
automatically. All values are in
analysis/profiles.py.
What the switch does in practice: between sun and moon the
difference is small — both measure at the most detailed spot, the moon’s
detail band merely sits slightly higher because crater edges are finer than
H-alpha fibrils. The score usually shifts by a few points, the order almost
never.
Planet is markedly different: the disc is first located by a brightness
threshold and the window centred on it (rather than on the most detailed
tile), and at 256 px the window is only half the size — otherwise a small
Jupiter would have black sky measured along with it.
So pick the profile that matches the subject, but do not lose time
wondering whether a lunar image is measured “wrongly” with the solar
profile. What matters above all is that every image of a run uses the
same profile, and that is always the case.
7. Drizzle, .as3 and sessions
Drizzle is handled fairly
An image stacked with drizzle 1.5× is 1.5 times as large. Measuring it as
is would place its detail at different frequencies and make the comparison
worthless. finiSCOPE therefore scales such images back to their native
pixel size before measuring (cubic interpolation).
Detection is deliberately cautious — an image is only scaled back if it is
actually larger than the smallest of the run and the ratio matches a
usual factor (1.5× / 2× / 3×), or if file name and size ratio agree. An
image that is larger for some other reason is left alone and triggers a
session warning instead.
The proof that this works is in the test run: the same capture stacked once
natively and once as drizzle 1.5× is measured at 0.1 % identical
sharpness.
The .as3 is read if it is there
You do not have to load the .as3. finiSCOPE looks for it by itself: if
a image.as3 from AutoStakkert sits next to image.tif, its
Median quality is read and shown in the table. AutoStakkert often appends
suffixes to the TIFF names (_conv, _lapl4_ap1274) — finiSCOPE finds the
matching .as3 anyway.
Assigning one yourself is possible too. If the .as3 is named quite
differently from the TIFF, automatic matching has no chance — then there
are two ways:
- click the value in the as3 column of the table (it reads “load …”
if none was found) and pick the file, or - simply drag the .as3 into the window — it is assigned to the
currently selected image.
The tooltip in that column shows which file the value came from and whether
it was found automatically or assigned by you.
Careful: this value is only comparable within the same capture.
Between two sessions it means nothing. If the file is missing, everything
else runs normally and the column shows a dash.
Session warnings
finiSCOPE checks whether the loaded images plausibly belong together and
warns about strongly differing dimensions, markedly different average
brightness, or files that had to be skipped. The warnings appear below the
table and are included in the HTML report.
8. Running from source
Needed if you want to change the program. Requires Python 3.9 or newer
(3.11+ recommended).
macOS
Double-click run_mac.command. On the first run it creates its own
Python environment and downloads the packages — a few minutes, once.
If macOS refuses to run it, once in Terminal:
chmod +x run_mac.command build_mac.command
Windows
Double-click run_windows.bat. It sets everything up on first run too.
If Python is not installed yet: get it from
https://www.python.org/downloads/ and be sure to tick
“Add python.exe to PATH” during installation.
By hand
python3 -m venv .venv
source .venv/bin/activate # Windows: .venvScriptsactivate
pip install -r requirements.txt
python app.py
Files can also be passed directly:
python app.py image1.tif image2.tif
9. Building the programs yourself
Important: a Windows
.execan only be built on Windows and a
macOS.apponly on a Mac. PyInstaller cannot cross-compile for a
foreign operating system. To offer both you need both systems — or let
them be built automatically (see below).
macOS → dist/finiSCOPE.app
./build_mac.command
Takes a minute or two; the result is about 180 MB and runs without any
Python installed. The app is ad-hoc signed so that macOS does not report it
as damaged. It runs on the processor type it was built on (Apple Silicon or
Intel).
For distribution run ./paket_mac.command afterwards. That wraps a
dist/finiSCOPE-0.1-macOS.dmg containing the app, a shortcut to the
Applications folder and a short bilingual guide — a single file you can
send.
Windows → distfiniSCOPEfiniSCOPE.exe
build_windows.bat
For distribution, zip the whole folder distfiniSCOPE — the .exe
alone does not run.
Step by step with all the pitfalls:
WINDOWS_BUILD_EN.md
Ready-made transfer folders
./ordner_erstellen.command
Creates Fertig/Mac-App (app + DMG) and Fertig/Windows-Projekt
(everything needed to build on the laptop, without any macOS leftovers).
Building both automatically
If you put the project on GitHub,
.github/workflows/build.yml builds the
macOS and Windows versions on every change — then the laptop is only needed
for testing, not for building.
Checking a built app for completeness
./dist/finiSCOPE.app/Contents/MacOS/finiSCOPE --selftest
Lists every package and image file and says at the end whether anything is
missing.
10. When something goes wrong
The file will not load.
finiSCOPE reads TIFF (.tif, .tiff) with 8, 16 or 32 bit, one or three
channels. Colour images are reduced to luminance. FITS, PNG and JPG are not
read. Broken files are skipped and the rest still measured — the notice
line says which.
“The images have different dimensions.”
They probably come from different captures. The comparison still runs, but
the power spectrum then compares different subjects — read the scores with
caution.
Every image gets almost the same score.
Then they really are almost equally good. Look at the 1:1 view: if you
cannot see a difference there, there is none that matters.
The measurement window sits somewhere uninteresting.
Drag your own rectangle over the spot you care about.
Measuring takes a long time.
Large drizzle TIFFs (4000 px and more) have to be scaled back. The window
stays responsive; progress runs as a thin line below the status bar.
macOS: “app is damaged”.
See section 1 — remove the quarantine flag once.
11. How the project is laid out
finiSCOPE/
app.py entry point (also --selftest)
i18n.py all texts, German and English
analysis/
core.py loading, scale-back, window search, PSD,
MTF50, SNR, noise, contrast, offset compensation
profiles.py sun / moon / planet: bands and windows
scoring.py weighted score + plain-text verdicts
quality.py absolute rating of a single image
as3.py reading the AutoStakkert file
ui/
theme.py colours, fonts, stylesheet, asset paths
widgets.py drop zone, cards, winner box, (i) explanations
imageview.py image view with measurement window and 1:1 crop
chart.py sharpness curve and power spectrum
table.py comparison table with expandable raw values
mainwindow.py assembly, menu bar, analysis thread, export
export/
report.py producing CSV and HTML
report.html.j2 template of the HTML report
assets/ background, logo, icons (replaceable)
prototype/preview.html design prototype (static, opens in a browser)
tests/
make_testdata.py generates synthetic test images
test_analysis.py 37 checks of the measurement
screenshot.py renders the window to an image
requirements.txt · LICENSE · README.md · README_EN.md
run_mac.command · run_windows.bat
build_mac.command · build_windows.bat · finiSCOPE.spec
paket_mac.command · ordner_erstellen.command
The name is the constant APP_NAME in ui/theme.py —
change it once there.
Images in assets/ are found by their base name; the extension is
free. So background.png can be swapped for background.jpg at any time.
Expected are background, favicon, logo and logo_wordmark; if one is
missing the app still runs.
All user-visible texts live in i18n.py as a table
“key → German / English”. No fixed text remains in the program code, so a
third language would only be typing work in that one file.
Tests
python tests/make_testdata.py tests/data # generate test images
python tests/test_analysis.py # 37 checks
The test builds four variants from one subject and proves that
- the blurred version shows less detail (MTF50 0.128 against 0.221,
detail energy a fifth), - the drizzle 1.5× version measures equivalently after being scaled
back (0.1 % deviation), - the noisy version, despite nominally equal sharpness, gets a tenfold
noise floor and 18 dB worse SNR — and drops in the ranking accordingly, - an artificially shifted image is detected to the pixel and the window
tracked (deviation after compensation: exactly zero).
Plus checks for RGB, 8 bit, missing files, broken files, missing .as3, very
small images and manually set measurement windows.
12. Colours
The interface deliberately does without yellow:
- Green is the only all-clear — good, clean, level with the best image.
The winner is green too, because green means “good” throughout. - Blue is the base colour of the whole application: neutral, medium,
and every control. It is the same blue as on finisky.com
(#4F8DE0/#8FC0FFon#16263D). The measurement window in the image
is blue as well — it stands out equally on grey lunar and orange solar
images. - Warm and red are reserved for what is genuinely weak.
Yellow and gold appear nowhere.
All colour values are constants in ui/theme.py.
13. Assumptions made
Where the brief left room, it was decided like this:
An aperture field was added. Without it the theoretical resolution
limit (Dawes) cannot be calculated and the “how close to optimum”
comparison would be impossible. The field is optional.
MTF50 is determined on a de-noised and “whitened” spectrum. A subject
has a spectrum that falls towards higher frequencies by nature — that is a
property of the subject, not of sharpness. Looking for the half-power point
of the raw curve gives almost the same value for a sharp and a blurred
image. So the noise floor is subtracted first and then the natural falloff
divided out; what remains is the transfer function of the system. Only that
separates sharp from soft cleanly (0.221 against 0.128 in the test run).
Noise is measured in the measurement window, not in the dark sky. A
crop of an active region has no dark sky. The method used (Laplacian filter
with median) works in both cases. The spread in the dark area is reported
additionally when there is one.
Detail energy has the noise removed. Without the subtraction, grain
would count as detail and a noisy image would win — exactly what happened
in the first test run.
Cautious drizzle detection. Better to skip a scale-back once than to
wrongly shrink an image from another session. Unexplained size differences
produce a warning instead.
A dragged area applies to all images by default. Anything else would
not be a fair comparison. The this image only tick allows the exception.
The automatic measurement area is searched on the average of all
images. Taking the first image would make the location depend on the
order in which files were loaded — and it might sit somewhere that only
looks interesting in the blurriest version.
A single image gets no score, but does get a quality light. The
comparison falls away, the absolute assessment remains.
Offset between images is compensated by phase correlation. Without it,
slightly shifted stacks would have two different spots compared — the most
likely measurement error in this tool. The method is insensitive to
brightness differences and finds the offset to the pixel (in the test run:
deviation after compensation exactly zero). It can be switched off if the
images are guaranteed to line up.
The sharpness curve is the chart’s default view. The raw power spectrum
falls off steeply by nature and therefore looks similar for every image —
the differences hide in details that take practice to see. The whitened
curve shows directly what matters: where the image stops carrying detail.
The power spectrum stays one click away.
Plain-text verdicts take the size of the difference into account. With
two nearly equally good images it says “just a touch grainier” rather than
“clearly noisy” — even though one is behind on paper.
The chart is drawn by hand rather than with pyqtgraph or Matplotlib.
That gives exactly the intended look, starts faster and saves the finished
app about 40 MB.
Author and licence
finiSCOPE is a tool by Josef Kreidl — astrophotography at
finisky.com.
Free of charge, no warranty, use at your own risk. The software is
released under the MIT licence and may be used, shared and modified as long
as the licence text and copyright notice stay with it. Liability for
damages is excluded. The values shown are guidance for comparing your own
images, not calibrated measurements.
The same information is available inside the app under Help → About,
and the full text is in LICENSE.
The images in assets/ (sun, moon, logo, icon) are copyrighted photographs
by Josef Kreidl and are not covered by the MIT licence.
Support
finiSCOPE is free and will stay free — every feature works without paying
anything. If you would like to support its development, there is a way to do
so at finisky.com/en/support,
entirely voluntary. Inside the app the link sits quietly in the footer and
under Help → Support finiSCOPE.
© 2026 Josef Kreidl · finisky.com