M: Let's see how well this works. I'd
like you to look up online the program Kanoma from, oh, this would have
been at least 15 years ago. It's basically abandonware at this point.
I'd like you to look at what the program does. Think about it, then try
to explain to me, or at least start explaining to me. You don't have to
get the entire thing at once. Begin explaining the mathematics behind
what the program does.
G: [Non-text content: thoughts;
content_type=thoughts]
G: [Non-text content: thoughts;
content_type=thoughts]
G: [Non-text content:
reasoning_recap; content_type=reasoning_recap]
G: TL;DR: You’re almost certainly
thinking of Canoma (MetaCreations, 1999), a photo-based
modeling app. Under the hood it’s classic photogrammetry: a pinhole
camera model + projective geometry. You “pin” corners of simple 3D
primitives onto 2D photo points; the software solves for camera pose and
primitive parameters by minimizing reprojection error (bundle
adjustment), then textures the solved geometry by inverse-warping pixels
from the photos. citeturn0search0turn0search6turn0search1
If that’s the program you meant, here’s the first slice of the
math.
1) Camera model (pinhole /
projective)
Canoma assumes a standard pinhole camera: a 3D point
(X) projects to image point (x) via a (3\times4) matrix (P = K,[R|t]): [
\lambda , \mathbf{x} = P ,\mathbf{X},\quad P = K,[R|t],\quad
K=\begin{bmatrix}f&0&c_x\0&f&s_y
c_y\0&0&1\end{bmatrix} ] Here (K) encodes intrinsics (focal
length, principal point, skew), (R,t) are extrinsics (orientation,
position). This is the backbone of image formation used in
photogrammetry. citeturn0search12turn0search1
2)
“Pinning” corners ⇒ pose & shape from correspondences
When you drag a box/cylinder face to align with a photo, you’re
creating 2D–3D correspondences between primitive
vertices (known in the model frame, up to a few parameters like
width/height/depth) and their image locations. With ≥6 well-distributed
correspondences, the program solves a Perspective-n-Point
(PnP) problem to estimate (R,t) (and sometimes refines focal
length). It does this by minimizing the reprojection
error: [ \min_{\theta};\sum_i \left| \mathbf{x}_i -
\pi!\big(P(\theta),\mathbf{X}_i(\theta)\big)\right|^2 ] where (\theta)
collects camera parameters and any editable primitive dimensions. The
global refinement across all pinned points and all photos is a
bundle adjustment—nonlinear least squares, typically
Levenberg–Marquardt/IRLS to be robust to outliers.
citeturn0search1
3) Faces lie in planes ⇒
homographies
Each planar face of your primitive (a wall, roof, etc.) maps to the
image via a planar projective transform (homography)
(H). If (\mathbf{X}) lies on a plane (\Pi), then [
\lambda,\mathbf{x}=H,\mathbf{X}_{\Pi},\quad H=K,[r_1\ r_2\ \mathbf{t}] ]
(derived from (P) restricted to (\Pi)). This lets Canoma warp the source
pixels from the photo onto that face with one (3!\times!3) transform per
face, which is why flat façades texture so cleanly.
citeturn0search12
4) Inverse warping (texturing)
After solving geometry & pose, the software builds textures by
inverse warping: for each point on a face (in model
UVs), it applies (H^{-1}) (or the full projection) to fetch the correct
pixel from the photo, with interpolation and blending if multiple photos
cover the same area. Unseen faces can be mirrored or left
untextured—both were Canoma UX features. citeturn0search0
5) Multi-view consistency
With multiple photos, constraints tighten: the same 3D edges must
project consistently in all views. The objective just stacks more
reprojection terms, and bundle adjustment jointly optimizes all camera
poses and primitive dimensions. This is the same principle used in
Debevec’s Façade, a closely related system that
Canoma’s workflow echoed. citeturn0search6
6) Why
primitives (boxes, cylinders) worked so well
Restricting modeling to analytic primitives turns a hard free-form
reconstruction into a small parameter fit
(width/height/depth/radius/axis). That makes the optimization
well-conditioned with sparse, interpretable Jacobians and enables
near-real-time feedback on ordinary 1999 hardware.
citeturn0search6
7) What Canoma
shipped/required (context)
- Released 1999 by MetaCreations; later acquired by Adobe; effectively
discontinued/abandonware. Exported MetaStream (Viewpoint) and QuickTime
animations. Priced ~$499 back then. citeturn0search0turn0news48
- Period reviews emphasized the “pin-the-corners” workflow and
photorealistic web models; archival mirrors and catalogs still describe
the same pipeline. citeturn0search5turn0search2turn0search8
If this is the right app, I can next go deeper into the actual
optimization (parameterization, Jacobians, IRLS/Huber for outliers),
visibility/occlusion handling, and texture atlas generation—basically,
spell out the math you’d implement to re-create Canoma today.
M: First, a technical question that you
might have lined up for a later bit of math, and then a practical
question. First, how much does it complicate the math? If you introduce
the idea of lens distortion, if that distortion is uniform, and if it's
adjustable. I'm asking you, and probably still would have asked you, if
I had been completely successful, because I tried to figure out the
two-dimensional analogy with paper and pencil. In fact, unless there's a
significant reason to include the third dimension, feel free to collapse
any explanations down to a second dimension. I acknowledge that simply
adding a third dimension isn't just doubling the workload, but usually
at least quadrupling it. But often that workload is a question of
mathematical complexity, not actual intrinsic difficulty or conceptual
broadening. Anyway, when I was trying the two-dimensional version, I was
getting not hung up with, but kind of interested in the idea of a
distortion due to lenses. And I phrased that as a two-part thing,
because like if you take a picture with a phone today, which I did, and
tried to use with Kenoma, often there's a detectable curve due to the, I
don't know how you would describe it, the fisheye lens element. And I
know that the zoom can also affect things as well, but my point is that
that's kind of a rigid situation, as long as you define what those
parameters are. Like, it also would apply even to normal cameras, simply
because I don't think any of them are perfectly flat. And then I
included the second version with just a variable one, because I don't
know if the rigidity actually makes it an easier problem to solve, or if
it's relatively easy either with relatively easy, either with definite
parameters or with variable ones, and I'm just not well acquainted
enough with the math to recognize that from the hip. And then the
practical question is, I'd like you to go online and see if you can find
me anything, preferably cheap or free, that is equivalent to Kenoma, and
preferably for Linux.
G: Great questions — both the
technical lens/distortion aspect and the practical side
(Linux-friendly alternatives) are interesting. I’ll tackle the technical
part first, and then we’ll move on to the practical part.
Technical:
What happens when you add lens distortion?
Yes — introducing lens (radial/tangential) distortion does complicate
the mathematics, but conceptually the extension is quite manageable.
Here’s a breakdown (in 2D, as you suggested) of what changes, how much
extra work it is, and some of the trade-offs.
1. “Standard” pinhole
projection in 2D
Since you said “collapse any explanations down to a second
dimension,” let’s imagine the following very simplified setup:
- There’s a “model plane” (object) in 2D (say the (x)–(y) plane) and a
“camera line” (instead of full 3D).
- A point in model coordinates ((X,Y)) projects via a simple affine /
perspective model to an image coordinate (x).
- The simplest “perspective” in 2-D might be:
[ x = f \frac{X + t_x}{Z + t_z},
] where we’ve suppressed some axes for simplicity. (In real 3D you’d do
more with homogeneous coordinates, but you get the idea.)
- If the camera intrinsics are known (focal length (f), principal
point, etc), one solves for the extrinsics (position, orientation) plus
maybe the size/shape of the model.
This is the typical uninterrupted workflow: correspondences → camera
+ model parameters → minimise reprojection error.
Now, many real lenses don’t behave as perfect pinholes, especially
wide‐angle or fisheye lenses: radial distortion causes straight lines to
appear curved, etc. In 2D you can model this distortion by saying that
the “ideal” projection (from the pinhole) gives some coordinate
(x_{ideal}), but what you see in the image is (x_{dist}). A
common (radial) distortion model is:
[ x_{dist} = x_{ideal} \left(1 + k_1 r^2 + k_2 r^4 + \cdots \right) +
\text{(maybe tangential terms)}. ]
Here
- (r) is the radius from the principal point (i.e., (r^2 = x_{ideal}^2
+ y_{ideal}^2) in the 2D case).
- (k_1, k_2, \dots) are distortion coefficients (parameters) to
estimate.
- You could also have tangential distortion (terms like (p_1 xy), etc)
but let’s keep it simpler.
What does this add
mathematically?
- Now each image measurement (x_{obs}) corresponds to a model point
((X,Y)) via a composed mapping:
[ (X,Y) ;;\longrightarrow;; x_{ideal}(X,Y;,\theta) ;;\longrightarrow;;
x_{dist}(x_{ideal},r;;k_1,k_2,\dots) \approx x_{obs} ] where (\theta)
are your “old” parameters (camera pose, model shape etc) and
((k_1,k_2,\dots)) are the new distortion parameters.
- In your least‐squares or bundle‐adjustment cost function you must
now include these additional distortion parameters. So the cost becomes:
[ \min_{\theta,,\mathbf{k}} \sum_i | x_{obs,i} -
D\big(P(\theta,\mathbf{X}_i),,\mathbf{k}\big) |^2 ] where
(D(\cdot,\mathbf{k})) is the distortion mapping.
- The Jacobians (derivatives) with respect to the distortion
parameters must be computed. That is, you’ll need partial derivatives of
(x_{dist}) w.r.t (k_1,k_2,\dots), as well as the chain rule through
(x_{ideal}).
- If distortion is assumed uniform across all images
(i.e., same lens, same camera intrinsics, same distortion model), then
you have fewer extra unknowns (just one set of distortion parameters).
If you allow one distortion‐model per image (or per lens/camera), you
multiply the parameters.
How much more complex?
- The dimensionality of the parameter space increases. Instead of just
pose + model geometry, you have pose + geometry + distortion(s).
- The optimization landscape gets slightly more complicated (more
parameters, possible weaker constraints on distortion if correspondences
are few).
- The math for each residual is still quite manageable: it’s just a
pinhole projection + a polynomial distortion. So
conceptually it’s straightforward.
- Implementation: you’ll need to compute distortion correction (or its
inverse) reliably, add the derivatives (Jacobian) for the distortion
parameters, initialise them reasonably (e.g., (k_1 = 0) to start).
- If your distortion is strong (wide‐angle/fisheye), the nonlinearity
can make convergence slower or less stable, so you might need robust
estimation (e.g., Huber/L1 residuals), outlier filtering, better
initialisation.
- Uniform distortion assumption (same parameters
across all images) simplifies things: fewer unknowns, better
constrained. If it holds (i.e., you used the same camera/lens setup),
it’s very reasonable.
- Variable distortion (different for each image or
camera) adds parameters and hence potential under‐determination if you
don’t have many points / images. That makes the solver less stable
unless you have enough data.
- From a solver viewpoint: uniform → simpler, fewer parameters.
Variable → adds complexity, but in many modern solutions it’s still
quite routine.
3. Summarising: how “much”
harder is it?
- If you ignore distortion: simpler model, fewer parameters, cleaner
optimisation.
- If you add distortion (but uniform): moderate extra complexity —
you’ll need distortion model, derivatives, more unknowns, slightly
bigger Jacobian, maybe slower convergence. But not huge conceptual
jump.
- If you allow per‐image variable distortion: more unknowns, more
potential instability, but still entirely within the same mathematical
framework (projective geometry + nonlinear least squares).
In short: yes it complicates things, but not by an order of
magnitude. The core remains the same: projecting 2D↔︎3D
correspondences, minimising reprojection error. Distortion adds a
“wrapper” layer around the projection. So your intuition — that it’s
more about mathematical bookkeeping than entirely new concepts — is spot
on.
If I were to quantify: maybe 20-40% extra implementation/derivation
work (depending on how mature your solver is) and maybe a bit more care
for initialisation and convergence. But the underlying geometry,
optimisation framework etc remain.
Practical:
Free / Cheap equivalent to Canoma, preferably for Linux
Yes — you can find modern tools that fulfill similar roles
to what entity["software","Canoma",0] did (photo-based modelling of
simple primitives, camera pose + texture mapping) and many run on Linux
or are open-source. Here are some good options:
- entity["software","Meshroom",0] (by
entity["software","AliceVision",0]) — open source, free, supports
Windows & Linux. It’s more full-scale photogrammetry (dense mesh,
many images) but absolutely usable and community-supported.
citeturn0search0turn0search9turn0search8turn0search2
- entity["software","MicMac",0] — open‐source photogrammetry from
the French IGN, runs on Linux. More advanced / academic but robust.
citeturn0search8turn0search2
- entity["software","OpenDroneMap",0] — open source, often used for
large‐scale/outdoor modelling, runs on Linux via Docker.
citeturn0search10turn0search2
⚠️ Considerations & caveats
- These tools often assume a larger workflow (lots of images,
arbitrary geometry) compared to Canoma’s simpler “pin corners of
primitives” style. So there is a learning curve.
- For simple primitives + texture mapping (walls/boxes/cylinders) you
might need to do additional work (e.g., manually create the primitives,
align them to the reconstructed mesh).
- Ensure your GPU/CPU is adequate — some tools depend on CUDA/OpenCL
for speed.
- Check that the version you pick supports Linux (some tools are
Windows only or better supported on Windows).
- Learning the workflow (capturing good photographs, setting overlap,
lighting, Distortion correction etc) is just as important as the
software choice.
If you like, I can look up 3-5 specific Linux‐friendly
programs (free or low-cost) that are closest in spirit
to Canoma’s workflow (i.e., “photo → primitive modelling + texturing
with minimal manual mesh cleanup”), and I can pull direct download links
+ user‐feedback for each. Would you like me to do that?
M: I don't know if I prefer the manual
approach, but I'm more familiar with it. My interest is personal. I'm
trying to recreate something from older photos that aren't
necessarily... I can't go back and take pictures, basically. I can
guarantee that everything in the pictures is static. That is, the
calculations would not need to move. But in terms of past usage, I was
able to nearly recreate what was in the pictures, with the problems
being that it was largely architecture and older, so the requirements
for perfect geometric squareness that Konoma had were difficult to
compensate for, and usually when I got within 95% of success, the
program would start flipping out in some form, because of the minor
inconsistencies. So yeah, I would like a list of your top five
suggestions for use with Linux, with minimal cost, and while it doesn't
have to be manual, now that you know what I'm trying to do, you
understand what the limitations are in terms of the sources that I have,
and can make a choice based on that. That also leads me to more
technical questions, like how is it that the inconsistencies, whether
from manual selection or automated choices, how is it that they are, I
guess, averaged out or whatever for the calculation guessing? I'm
curious because I know that occasionally there would be a feedback loop
created, or a normally self-contained feedback loop that would find a
final spot, instead would shoot off to infinity as it attempted to
compensate for some sort of new entry. And that was another technical
question I had, although probably smaller. Does it make a difference in
the nature and complexity of the math, if you can guarantee that
everything is of the same photo? Because I feel like there was an
element of distrust, almost, in Canoma, in that, not maliciously, but
just thinking that the user will either be trying to be creative, an
idiot, or both, and having to compensate for, thinking that, for
example, two photos of a box for the same breakfast cereal would look
exactly the same, but because of differences in the cameras, or box
sizes, or whatever, that the program itself might have to compensate for
that kind of idiocy.
G: Great — thanks for the extra
context; it really helps refine the recommendation and the technical
explanation. I’ll split this into two parts:
1.
Why small inconsistencies cause instability (and how they’re handled
mathematically)
Since your scenario is: older photos, architecture, geometry that’s
nearly square/orthogonal but not perfect, static scene, single
photo (or small set) — you’re exactly in a regime where the solver
assumptions may be stretched. Here’s what’s going on under the hood, and
why things flip out sometimes.
a) What the solver
assumes vs. what happens
Most photogrammetry / modelling-from-photo systems (including your
previous experience with entity["software","Canoma",0]-style tools)
assume:
- The scene geometry can be approximated by simple primitives (boxes,
planes, cylinders) with clean relationships (orthogonality,
parallelism).
- The image correspondences you supply (e.g., pinning corners) are
exact, or at least “close enough” to the model assumptions (straight
lines, flat faces, no warping).
- The camera model (intrinsics, extrinsics, distortion) is correct /
adequate.
- The solver finds a minimum of the reprojection error (or
cost function) and converges to a reasonable solution.
But in your case:
- The architecture may be irregular: walls not perfectly vertical,
ceilings not perfectly horizontal, corners slightly skewed, windows
slightly angled. So you are introducing systematic
errors (structure not ideal) rather than just random
noise.
- Older photos may have distortions (lens, film, scanning) that aren’t
fully corrected, so the projection isn’t perfect.
- If you work with only one photo (or few), you have fewer
constraints: many parameters (camera pose, model dimensions, distortion)
and few correspondences → under‐constrained or poorly conditioned
system.
- The solver might assume orthogonality (or you force “box”
primitives) but the actual data violates that slightly — the solver then
tries to reconcile by pushing parameters to extremes (e.g., very large
depths, weird angles) which can “shoot off to infinity” or diverge.
b) Why “explosion” or
divergence happens
Mathematically: the cost function is something like
[ \min_{\theta};\sum_i |;x_{obs,i} - \pi(P(\theta),X_i)|^2 ] where
(\theta) = camera parameters + model geometry. If the data doesn’t
well-fit the model assumptions, there are multiple ways to lower the
cost (some unrealistic) because the system is under-determined or poorly
conditioned.
A few specific causes:
- Flatness of the cost‐landscape / weak curvature: If
the model is large/flat (e.g., a wall) and you only have one image,
small changes in depth produce small changes in reprojection error → the
solver may “slide” along a nearly flat valley in parameter space, thus
going to large values (infinite depth) because it doesn’t increase error
much.
- Bias from incorrect assumptions: If you force the
primitive to be “square” but the real architecture is slightly skewed,
the solver has to force distortion/pose to compensate, which might push
camera position far away or produce unrealistic zoom/scale.
- Outlier correspondences or mis‐pins: If you pinned
corners that don’t exactly correspond (due to photo error or scanning
error), those residuals act like “noise”, but they’re systematic. The
solver might then try to “fit” them by twisting geometry or exaggerating
camera parameters.
- Lens distortion / scanning warping: If the camera
model ignores distortion (or uses a poor model) the residuals due to
distortion get interpreted as geometry/pose error → again the solver
distorts other parameters to compensate, possibly pushing them to
extremes.
c)
How the solver should handle inconsistencies and what you can
do
- Use robust error functions: instead of plain
least‐squares, use Huber, Tukey, or other cost functions that reduce the
impact of large residuals (i.e., “outlier” pins) so the solver isn’t
dragged by one bad pin.
- Increase constraints: if you add more views (even if same scene) or
more pinned correspondences, you strengthen the constraint system and
reduce ambiguity.
- Relax assumptions: instead of forcing perfect orthogonality, allow
the primitive geometry to have free angles (or at least let some
parameters vary slightly). That gives the solver “wiggle room” so it
doesn’t need to use extreme camera parameters to force everything.
- Correct lens distortion (or include a distortion model) so that
mismatches due to lens warping aren’t misinterpreted as geometry
error.
- Use good initialisation: provide approximate camera pose or
approximate model dimensions so the solver starts near a reasonable
region rather than wandering.
- Fix some parameters: if your scene is static, you might fix the
camera intrinsics (focal length) and only optimise pose + geometry. That
reduces the unknowns and stabilises the solution.
d)
Does it matter that you’re using a single photo or
all from the same photo?
Yes — it does simplify things in some ways, but it also reduces
constraint strength.
Advantages of using a single (or same) photo
scenario:
- The camera intrinsics/distortion are fixed (no variation
between views) so you don’t have to handle multiple camera
poses/different distortions. That reduces unknowns.
- The scene being static and known helps you “trust” correspondences
more (you don’t have to worry about moving objects or mis‐alignment
between different photos).
- Because everything is from the same image, you can reasonably assume
the same distortion/intrinsics.
Disadvantages:
- Fewer independent constraints: with only one viewpoint many 3D
depth/scale ambiguities exist (the “bas‐relief ambiguity” in
photogrammetry). For example, a flat wall with a window: you can’t
easily tell how far away the wall is from the camera (scale ambiguity)
or how skewed it is in depth.
- Errors in the photo (scanning distortion, perspective skew, lens
distortion) affect everything and there’s no second view to
“triangulate” and correct.
- When the solver has less data, it’s more prone to diverging or
picking extremes because there are many near‐equivalent solutions.
So yes — using one photo simplifies some parts (fixed camera, no
multi‐view pose estimation) but at the cost of much less constraint
power. That means your solver must rely more on priors or
model constraints (e.g., "this wall is vertical", "corners are
orthogonal") and if those priors are violated (as you found) then
instability occurs.
Given your use case (older photos, static architecture, possibly
single or few images, wanting simple primitive modelling/texture
mapping) I’ve selected five tools that run on Linux (or have Linux
support), are free or low cost, and vary from “simple to advanced”. For
each I’ll note pros/cons with respect to your scenario (single
photo, architecture, manual control). Then you can pick the one that
seems the best fit.
1)
entity["software","Meshroom",0] (by
entity["software","AliceVision",0])
Platform & cost: Free, open source. Linux
support (though often more mature on Windows); builds may require CUDA
GPU. citeturn0search0turn0search11turn0search4
Why it's good for you:
- Easy drag-&-drop photo workflow; you can supply your old photos
and let it reconstruct.
- Because it builds camera pose + scene automatically, you might get a
nice textured mesh even from fewer images.
Caveats for your use case:
- The “automatic” pipeline is designed for many overlapping images;
with very few (or single) images, reconstruction may fail or be
weak.
- It builds full mesh rather than “primitive + pinning” style; less
manually controllable for aligning simple boxes/cylinders to old
architectural photos.
2)
entity["software","COLMAP",0]
Platform & cost: Free, open source; Linux
compatible. citeturn0search16turn0search15
Why it's good:
- More low-level / flexible: you can tweak feature matching, camera
parameters, etc.
- Allows you to fix certain parameters (intrinsics, poses) which is
helpful for fewer images.
Caveats:
- Command line oriented (less GUI friendly) so steeper learning
curve.
- Same problem of needing multiple images for robust reconstruction;
for single photo scenario you’ll still have ambiguities.
3)
entity["software","Regard3D",0]
Platform & cost: Free, open source; available
for Linux (though may need build from source).
citeturn0search13
Why it’s good:
- Open source and targeted at “photos to 3D model” workflow.
- If you’re comfortable building from source, you can customise or fix
parameters.
Caveats:
- Possibly less polished UI and fewer tutorials compared to the more
popular tools.
- Same challenge: single photo constraints weak.
4)
entity["software","MicMac",0]
Platform & cost: Free, open-source (French
mapping agency origin) for 3D reconstruction. citeturn0search18
Why it’s good:
- Very capable and used in professional mapping/architecture contexts
— so likely to handle “architecture from photos” use‐case well.
- Good ability to control camera calibration, distortion, etc.
Caveats:
- Less “simple” workflow; may require more manual steps and
learning.
- UI less friendly compared to tools designed for hobbyists.
5)
entity["software","Blender",0] (with add‐ons)
Platform & cost: Free, open source, native
Linux.
Why it’s good:
- While not strictly “photogrammetry software”, Blender supports
importing camera images, modelling primitives, aligning geometry to
images, and texturing from photos. For your use case (single photo,
modelling a scene) this may actually be a very good fit: you manually
set up a plane, align camera to the photo background, build primitives
(walls, windows) and texture with the photo.
- Very good manual control: since you’re comfortable with manual
approach, Blender gives you full freedom.
Caveats:
- More “manual work” (but you said you’re comfortable with that).
- Doesn’t automatically extract geometry from photos like
photogrammetry; you’ll essentially do the “pin corners” yourself.
Recommendation for your
scenario
Given your particular constraints (old photo(s), static scene,
nearly-square architecture but with small deviations, you’re comfortable
with manual approach), my recommendation is:
- Try Blender (Option 5) first, because you have full manual
control and fewer automatic assumptions to fail. Use the old photo as
background reference, build the model manually (walls, windows) aligning
to the photo, adjust camera so the photo aligns, then texture it from
the photo. This avoids the “under‐constraint” issue many photogrammetry
tools face with few images.
- If you want a more automatic help (to handle camera pose,
distortion, maybe extract geometry), try Meshroom (Option 1) or MicMac
(Option 4) — but treat the output as a starting point, then clean up
manually. Because you might only have one photo, you may need to supply
strong priors or fix many parameters in those tools to get stable
results.
- In whichever method you choose, fix as many parameters as
you can (camera intrinsics, distortion, known wall height,
known distances) so the solver isn’t free to “explode”. For example: set
the camera focal length manually (extracted from EXIF if available), set
the lens distortion coefficient to a value or zero, set the walls
orthogonal but allow small deviation. That will stabilise the
computation.
If you like, I can pull download links + version
compatibility notes + user-experience tips for each of those
five tools (especially focusing on how they handle single-photo or
few-photo workflows and how to stabilise them for your architectural
case). Would you like me to go ahead and do that?