Survey method · GIS development

Reading a tree survey from its photographs

A large survey may generate hundreds of site photographs, and almost every one of them shows several trees at once. On a recent survey for a major redevelopment in Norwich that came to 358 photographs across 1,256 trees and groups.

The project scope required a photographic record of all trees, with their survey reference numbers within the filename to allow the project team to identify them during the design phase. This would either involve writing the reference numbers to each file during capture or else manually renaming all the photographs after completion.

Version 1.1 · September 2026

The problem

It is rarely possible on a large non-linear site to collect tree data perfectly sequentially (i.e. T1, T2, T3, etc.) due to access restrictions and the need to work around other site activities. So writing the initial reference number to the photo during capture would embed that non-spatial sequence and force us to use numbering that didn't flow around the site. However, having reference number sequences that are spatially ordered is very useful, because it aids location and allows users to navigate to find a particular tree more easily (e.g. if you are looking for T451, you should be more likely to find it near trees T425–T475 rather than trees T100–T150). We use a custom tool to automate the renumbering process by projecting each tree onto a user defined path, and then sampling its position along that path (or proximity to it) to determine its place in the sequence: the tree closest to the start of the path becomes T1, the next becomes T2, and so on. This ensures a logical and spatially ordered sequence within all our survey outputs no matter how many trees are surveyed.

However, re-labelling photographs by hand is slow, and invites inevitable and variable human error. 10–20 photographs can be done by eye and checked fairly easily, but the work involved in re-labelling and checking more than 40–50 is disproportionately harder and quickly becomes unmanageable.

The solution is that the information needed to automate the process is already present: every photograph carries the position it was taken from and the direction the camera was pointing, the field of view of the camera is a known quantity, the terrain of the site is freely available from the Environment Agency’s 2022 LIDAR Composite Digital Terrain Model (DTM) at 1 m resolution, and the survey already holds the canopy of every tree as a drawn shape, with its height. What was missing was a way to bring these together, so we built a tool that works out which surveyed trees are actually visible in each photograph, using the position and compass bearing recorded by the camera, the field of view of the camera, the canopy shapes already drawn in the survey, and the terrain of the site itself.

What this is not: it is not image recognition. Nothing in the method looks at the content of the picture. It is a geometry question answered from survey data, which means the result can be checked against the drawing rather than trusted on faith.

358photographs processed in a single run
1,256surveyed trees, groups and hedges tested against every photograph
<0.5 mcamera position accuracy, from an external GNSS receiver
67.8° × 53.5°angle of view of the survey camera’s main lens

Before any geometry: the photograph itself

The method can only be as good as the position and bearing each photograph carries, so the capture set-up was chosen with that in mind. Survey photographs are taken on a Samsung Galaxy S20 FE (model SM-G780G) using the Conota camera app, which writes the camera’s position, true compass bearing, estimated position error, image orientation and time into each file’s EXIF metadata, as well as stamping the coordinates visibly on the picture.

The phone’s own satellite positioning was the starting point, but early results made it clear that its error of four to five metres would throw a lot of the matches off: at the short distances involved in tree survey that is enough to put the camera on the wrong side of a tree. Positions were instead supplied by a Juniper Geode GNS3S receiver, set as the phone’s mock location provider. Android’s mock location setting lets an external receiver stand in for the handset’s own positioning, so every app on the phone, Conota included, records the Geode’s sub-half-metre fix rather than the phone’s.

What each photograph carries

EXIF fields read from every photograph
InformationEXIF fieldUsed for
PositionGPSLatitude, GPSLongitude Camera location. Stored as latitude and longitude (WGS84) and converted to British National Grid (EPSG:27700).
BearingGPSImgDirection (ref. T) The direction the lens was pointing. Recorded against true north, so no magnetic correction is needed.
Position errorGPSHPositioningError Setting aside unreliable photographs, and grading confidence in the rest.
Image sizeImageWidth, ImageHeight Identifying which lens took the photograph, and whether it was held in portrait or landscape.
TimeDateTimeOriginal Dating the renamed copy, and placing the photograph in its season (in leaf or bare).

Focal length and lens model are not recorded, so the method does not assume them. One trap is worth recording: the app’s own settings block carries an EPSG:27700 entry, which reads as though the coordinates have already been converted to British National Grid. They have not; it is a display preference, and the stored position is plain latitude and longitude.

Which lens took it

The S20 FE has three rear cameras. Only the main lens is used: the ultra-wide distorts too much for its angle of view to be relied on, and the telephoto is not used for survey work. Because the lens is not named in the metadata, it is identified by the size of the image it produces, which differs between lenses even though both are the same 4:3 shape.

Lens identified from image size (long edge × short edge)
Image sizeLensTreatment
4032 × 3024MainProcessed
4000 × 3000Ultra-wideSet aside and listed
Anything elseUnrecognisedSet aside and flagged for manual review

The long and short edges are compared rather than width and height, so a portrait photograph is recognised as readily as a landscape one. This check comes before any geometry: the main lens’s angle of view is never applied to a photograph that the check has not confirmed was taken with it.

Where it was taken from

Any photograph whose recorded position error exceeds a threshold, 10 m by default and adjustable, is set aside before any matching is attempted. It is not quietly discarded: it is listed by filename with its error value, and copied through unchanged. With the Geode supplying positions this should rarely apply; it is the safeguard for the occasional photograph taken with a poor fix.

Working: why half a metre matters

A position error moves the camera sideways relative to the tree, which swings the tree’s apparent direction. The worst case is an error at right angles to the line of sight:

δθ = atan( e / d ) where e is the position error and d the distance from camera to tree.
Position errorTree at 10 mTree at 20 mTree at 40 m
0.5 m (Geode)2.9°1.4°0.7°
4.5 m (phone alone)24.2°12.7°6.4°

Half the landscape frame is 33.9° wide. A phone-only fix can shift a tree at 10 m by more than a third of the frame; the Geode keeps the same tree within about 3°.

Which way it was pointing

The bearing comes from the phone’s magnetometer. A phone compass is only trustworthy if it corrects for the phone being tilted, and if it holds its heading however the phone is turned. Conota was checked against a hand-held compass and does both, keeping the correct heading in portrait, in landscape and at any rotation in between.

Working: how accurate is a phone compass?

The S20 FE uses an Asahi Kasei AK09918 three-axis magnetometer, which reads the magnetic field in steps of 0.15 µT. The horizontal component of the Earth’s field in the UK is roughly 20 µT, so the smallest change of heading the sensor can resolve is:

θmin = atan( 0.15 / 20 ) ≈ 0.43°

Ordinary sensor noise takes that to about 0.9–1.3°. The larger errors come from elsewhere: an uncorrected tilt adds roughly 2–5° of heading error for each degree the phone is off level, and uncorrected magnetic interference from nearby metal can add 10–20° or more. With tilt correction confirmed, the realistic working error is about 1–3°, which the tolerance described in the next section is sized to absorb.

One: what the lens could see

A camera at a known position, pointing on a known bearing, with a known angle of view, can only have captured what fell inside a wedge of ground in front of it. Every canopy the wedge touches is a candidate for that photograph.

The angle of view depends on how the phone was held. The main lens covers 67.8° across the long side of the image and 53.5° across the short side. In landscape the wider figure spans the ground in front of the camera; in portrait the narrower one does, and the 67.8° runs vertically instead. Surveyors switch between the two from shot to shot, so the orientation is read from each photograph’s dimensions rather than assumed for the survey as a whole.

The wedge is then widened by 15% of the angle of view to absorb the small remaining error in position and bearing. A percentage is used rather than a fixed number of degrees so that it scales correctly between portrait and landscape. The wedge runs out to 50 m by default; both figures are adjustable, and both were settled by checking early results against the photographs, which showed trees at the edges of the frame and further back being missed.

Drag the camera, swing the bearing, and watch the candidate list change.

Interactive

Candidate selection

Drag the blue camera marker, or the handle on the end of its bearing line. With the plan selected, the arrow keys move the camera.

Photograph held in 67.8°
Wedge width78.0°
Trees in frame0
References, nearest first (italic: caught only by the tolerance) None

Each tree is drawn from its four recorded crown spreads, each group as the combined outline of its members, and the hedge as a band along its centre line. As in the tool, a canopy becomes a candidate only where its drawn outline actually enters the wedge. A circle of average spread would catch some trees whose real crown falls short of the wedge, and miss others that reach into it on one side.

Working: where the 67.8° and 53.5° come from

The published angles of view for the S20 FE main camera correspond to a 35 mm-equivalent focal length of 26.8 mm. They can be checked from first principles, taking the 4:3 image across a 36 mm-wide reference frame (36 × 27 mm):

FOV = 2 × atan( w / 2f ) long side: 2 × atan( 36 / 53.6 ) = 67.8°
short side: 2 × atan( 27 / 53.6 ) = 53.5°

The two agree to a tenth of a degree, so the figures are sourced and cross-checked rather than estimated, and no field calibration was needed.

Working: building the wedge
edges = bearing ± FOV × (1 + t) / 2 where FOV is 67.8° (landscape) or 53.5° (portrait) and t is the tolerance, 0.15 by default.
Held inAngle of viewWidened wedgeEither side of bearingAdded each side
Landscape67.8°78.0°39.0°5.1°
Portrait53.5°61.5°30.8°4.0°

The 4–5° added each side covers the 1–3° compass error plus the angular effect of a sub-half-metre position error at survey distances. Any canopy outline that intersects the widened wedge within range becomes a candidate.

What this is not: the root protection area is not used anywhere in the method. It describes roots, not crown, and although it is the obvious survey figure to reach for, it would be the wrong one. Canopy extent comes only from the canopy outlines drawn for each tree, group and hedge in the survey.

Two: why a taller tree can be the hidden one

Knowing a tree fell inside the frame is not the same as knowing it can be seen. The obvious rule, that a taller tree shows over a shorter one, is wrong often enough to matter. What decides the question is the angle a crown occupies from where the photographer stood, and that depends on distance and on ground level as much as on height.

Below, a nearer 8 m tree stands between the camera and a 16 m tree well behind it. On level ground about a quarter of the taller crown shows over the top: enough to count, though marginal enough to be flagged for a person to confirm. Drop it a couple of metres into a hollow and it falls below the threshold and is treated as hidden, while remaining twice the height of the tree hiding it.

Interactive

Apparent height, not measured height

A section through the ground, seen from the side. The dashed line is the sightline that just grazes the top of the nearer crown.

Near crown, apparent angle0°
Far crown, apparent angle0°
Far crown showing0%
Visible

Under 15% of the crown showing, the tree is treated as hidden. Between 15% and 40% it is kept but flagged for a person to confirm. Above 40% it is accepted. Nothing is silently included or silently dropped.

Working: apparent height

Heights are converted to levels above Ordnance Datum (AOD) so that trees on different ground can be compared directly, and each crown is then reduced to the angle it rises to above the photographer’s eye:

eyeAOD = ground(camera) + 1.5 m
apexAOD = ground(tree) + height
θapex = atan2( apexAOD − eyeAOD, d ) where d is the horizontal distance from the camera to the centre of the crown. Eye height defaults to 1.5 m and is adjustable; heights are read from the live survey data.

The comparison replaced an earlier rule that simply compared heights. That rule had two faults: it ignored level changes, and, less obviously, it ignored distance even on flat ground. A 10 m tree at 5 m blocks far more of the view than the same tree at 40 m.

Two different points on each canopy do different jobs. The centre of the crown is where the top of the tree actually is, so it sets the distance used for the angle. The near edge is where the tree starts to block the ground behind it, so it is where the terrain check (below) stops. Using the near edge for both treats every crown as leaning towards the camera, overstating how much each one hides.

Working: how much of the crown shows
f = ( θapex − θobstruction ) / ( θapex − θbase ) where θobstruction is the highest angle reached by anything nearer on the same bearing, trees or ground, and θbase the angle down to the foot of the tree. The denominator is the crown’s full vertical extent as seen from the camera.
Share showingVerdict
under 15%Hidden; the record keeps what hid it
15% to 40%Visible, flagged for review
40% and overVisible

Worked example (the demonstration’s starting position): near crown atan(6.5 / 18) = 19.9°; far crown top atan(14.5 / 28) = 27.4°; far crown base atan(−1.5 / 28) = −3.1°. So f = (27.4 − 19.9) / (27.4 + 3.1) = 25%: visible, flagged for review. Lower the far tree 2 m and f falls to 13%: hidden.

A nearer tree only counts as an obstruction if it covers the far tree’s bearing, to within 0.5°. Where a nearer crown overlaps more than 30% of a candidate’s width without hiding it, the candidate is flagged for review rather than accepted outright.

Three: terrain obstruction

On level sites the trees are the only obstruction worth modelling. On sites with real relief they are not. A tree can sit in full view of the camera with nothing in front of it and still be invisible, because the land rises in between.

We step along the line of sight at fixed intervals, reading the ground height at each step from a terrain model, and keep the steepest angle the ground reaches. Anything sitting below that angle is behind the hill. Raise the ridge and watch the crown go.

Interactive

Stepping along the sightline

Each tick is one sample of the ground. The dashed line is the steepest angle the ground reaches, which is the horizon for this view.

Ground horizon0°
Crown top0°
Crown showing0%
Visible

Widen the sample spacing and the ridge is eventually stepped over entirely, and the tree wrongly reappears. This is why the spacing is kept close to the 1 m resolution of the terrain model rather than chosen for speed.

Working: stepping along the sightline
θground = max over s = 2, 4, 6 … m of atan2( DTM(s) − eyeAOD, s )
θobstruction = max( θground, θnearer trees ) where DTM(s) is the ground level read from the terrain model at distance s along the sightline, stopping at the near edge of the canopy being tested.

Ground and trees feed the same single figure, so one test handles both. Ground levels come from the Environment Agency’s 2022 LIDAR Composite DTM at 1 m resolution. A 2 m step reads every other cell along the sightline: close enough that no bank or ridge large enough to hide a crown can fall between samples, without re-reading the same ground for no gain.

  • The terrain model is optional. Without one, the ground is taken as level and the stepping is skipped, but the distance-aware angle comparison still applies, so the result improves even with no terrain loaded.
  • Outside the terrain model, the ground level is unknown, never zero. Substituting zero would put the tree at sea level, which on most sites is well underground. Affected trees are flagged and listed instead.
  • Sloping groups and hedges are flagged. A group or hedge whose outline spans more than 2 m of ground level cannot fairly be given one base level, so it is marked for review.

What comes out

Each photograph is copied, renamed for the trees it shows, and marked with a small label in the corner. The original files are never altered, so the process can be run again safely at any time.

G12, T77, T78, T79, H14

The corner label: brand blue at 60% opacity, with the lettering sized to match the camera app’s own coordinate stamp. It sits top left because the app’s stamp occupies the bottom left and its orientation arrow the bottom right. Plain lettering, or no label at all, can be chosen instead.

Naming and filing
Renamed fileG12-T77-T78-T79-H14_(24-07-26).jpg
References nearest first, then the date taken.
Long listsG12-T77-T78-T79-H14-T80-H15-T74-G11-T85_+2more_(03-07-26).jpg
Up to ten references (adjustable), then a count of the rest. The schedule lists them all.
Same trees, same dayTwo photographs of the same trees on the same day would otherwise get the same name. The second and later copies take _2, _3, so no photograph can overwrite another.
Location dataPosition, bearing and time are carried into every copy, so the renamed photographs still plot on a map.
TaggedEvery photograph showing at least one visible tree.
SkippedPhotographs taken on the wrong lens, with too large a position error, or with nothing visible, copied through unchanged so that nothing disappears quietly.

The schedule

The schedule is the useful artefact. Given a tree reference, it answers which photographs show that tree, in order of how close the photographer was standing, with each photograph a link that opens it directly. On the Norwich survey it ran to 2,852 entries across 839 of the 1,256 surveyed trees and groups.

Many trees have no direct photographs. These are typically internal category C or U trees within large groups, where the light, their suppressed form and the spatial density of the group make capturing a useful photograph next to impossible.

Extract from the photograph schedule issued for the Norwich survey
Tree IDPhotosPhotoLink
T33G2-T4-T3_(25-07-26).jpgTagged/G2-T4-T3_(25-07-26).jpg
G2-T4-T3-T6_(25-07-26).jpgTagged/G2-T4-T3-T6_(25-07-26).jpg
G2-T4-T3-T6-T1-G1-T2_(25-07-26).jpgTagged/G2-T4-T3-T6-T1-G1-T2_(25-07-26).jpg
T43G2-T4-T3_(25-07-26).jpgTagged/G2-T4-T3_(25-07-26).jpg
G2-T4-T3-T6_(25-07-26).jpgTagged/G2-T4-T3-T6_(25-07-26).jpg
G2-T4-T3-T6-T1-G1-T2_(25-07-26).jpgTagged/G2-T4-T3-T6-T1-G1-T2_(25-07-26).jpg
T62G2-T4-T3-T6_(25-07-26).jpgTagged/G2-T4-T3-T6_(25-07-26).jpg
G2-T4-T3-T6-T1-G1-T2_(25-07-26).jpgTagged/G2-T4-T3-T6-T1-G1-T2_(25-07-26).jpg

Trees are sorted in natural order, so T2 comes before T10. The schedule is written twice: first as a plain CSV file, unconditionally, and then as a formatted Excel workbook with the links. The plain file exists so that a complete run can never be lost to a fault in the final formatting step. The links are relative to the workbook’s own folder rather than tied to a drive, so they keep working when the folder is moved or sent on.

What this is not: it is not a substitute for looking. The method cannot know that a crown was bare in January, or that a gap in a hedge let a view through. Every judgement it makes is recorded with its reasoning, and anything marginal is marked for a person to confirm. It sorts the work; it does not sign it off.

Checking the result

Each stage of the process leaves its own layer on the survey plan in QGIS, so any result can be traced back through the steps that produced it.

1

Camera positions

A point at each recorded position, a marker pointing along the recorded bearing, and a dotted ring showing the position error to scale in ground metres. Hovering shows the photograph.

2

Wedges

The widened wedge for every photograph, drawn translucent and labelled with the trees it caught, so a missing or unexpected tree can be seen at a glance.

3

Verdicts

Canopies shaded green where visible, dashed red where hidden, with a warning mark on anything flagged. Each shows its verdict, confidence, what hid it, distance, ground and crown-top levels, the share of crown clearing the obstruction, and the photograph.

Every tree and photograph pairing carries a confidence grade. High means the tree sits well inside the frame, clearly wins its line of sight, and the photograph’s position error is low. Review means it sits near the edge of the frame, is closely contested by a nearer crown, clears its obstruction only marginally, or comes from a photograph with a larger position error. The grade is recorded against each pairing on the plan and sets the order in which the photographs are checked, rather than being discarded once the run finishes.

Why build it this way

The survey for a major redevelopment in Norwich was the first the method was run on at full scale. It leans entirely on survey data that already exists: the canopy shapes drawn during the survey, the heights recorded against them, and the position and bearing written by the camera. Nothing is estimated that could be measured, and nothing is measured twice.

That has a practical consequence. Because the working is geometry rather than interpretation, every result can be put back on the plan and checked. The wedge for any photograph can be drawn, the trees it caught can be highlighted, and the reason any tree was set aside can be read off directly.

Tested by counting, not by finishing

The full 358-photograph run was checked by counting what came out against what went in, not simply by whether it completed. That is how a fault was found that produced no error at all: two photographs of the same trees taken on the same day were given the same name, so one quietly replaced the other. A test batch of six tagged photographs produced three files. The fault was fixed, and counting the output is now part of every check.

Where it goes next

The same geometry that decides whether a tree is in the frame also says where in the frame it sits. With the angle of view and image size known, that angle converts directly to a position on the photograph, so a label could be placed on the tree itself rather than in the corner. The missing piece is the camera’s up-and-down tilt, which is not currently recorded. Until then, the corner label and the schedule do the job.

Document control

Version

Written and maintained by Tony Sorensen BSc (Hons) Arb, MICFor, MArborA.

Version 1.1 · September 2026

Revision history
VersionDateChanges
1.1September 2026 Capture set-up added (camera, GNSS receiver, photograph metadata, lens check, compass accuracy). Working added to each stage. Demonstrations updated to show survey canopy outlines, portrait and landscape, the compass tolerance and the review band. Schedule, checking layers and testing described. Terrain source stated.
1.0September 2026First publication.

Survey work that leaves a trail

We develop our own survey tools so that the evidence behind a recommendation can be examined, not just asserted. If you have a site where that matters, we would be glad to talk.