Skip to main content
View source

Image Orientation Fixer

View as Markdown

A RocketRide filter node that turns scanned photographs the right way up.

What it does

Scanning a photo album gives you pictures at every orientation — a print laid sideways on the platen comes out sideways, and nothing downstream knows. This node looks at each photo four ways (as it arrived, and turned 90°, 180°, 270°), finds faces in each, and keeps the orientation they agree on.

It is deliberately cautious. A photo turned the wrong way is worse than one left alone, so unless the evidence is clear the image passes through untouched and is listed on the text lane instead. Expect it to fix most of a family album and name the rest for you to do by hand — not to sweep everything.

Photos it does not rotate are forwarded byte-for-byte, never re-encoded, so leaving one alone costs it nothing in quality.

Lanes

Lane inLane outDescription
imageimageThe photo, upright if the node was sure, unchanged if it was not
imagetextJSON decision record — what it chose, how sure it was, and why it declined

The decision record

{"decoded": true, "rotation": 270, "confident": true,
"scores": {"0": 0.011, "90": 0.004, "180": 0.0, "270": 0.194},
"faces": 2, "ratio": 17.6, "reason": null}

rotation is the correction applied, in degrees clockwise — not the rotation the photo was found in. A picture that arrived turned 90° clockwise is corrected with "rotation": 270.

0 means the image was left as it was, and confident separates the two ways that happens: true is "measured, and it was already upright", false is "not sure". reason names the doubt:

reasonMeans
no_facesNothing that scored as a face at any orientation
few_facesFewer faces backed the winner than Faces needed to decide
thin_marginNo orientation led the others by enough. Two orientations disagreeing looks like this too
mixed_signalsThe two readings of the detections pointed different ways — the rotation holding the most face was not the one the detector was most certain about
unencodable_formatAnalysed, but not JPEG or PNG, so the node declines to re-save it
no_modelThe face model could not be loaded; nothing was analysed

decoded: false is different again — the bytes were not a readable image. That needs a different fix from "read it and left it alone", which is why they are not merged.

Configuring it

SettingDefaultWhat it does
How sure before rotatingBalanced (1.1)How clearly the winning orientation must beat the next best. Trades coverage, not correctness — see below
Faces needed to decide2How many faces must back the winner. Lower to 1 for portraits, where there is only ever one face
Face clarity vs face sizeBalanced (1)When one rotation shows a bigger face and another a clearer one, this decides which wins. See below
Minimum face score0.6How certain the detector must be that something is a face before it gets a vote. Raising it ignores doubtful faces but also discards real ones in dim or grainy scans; lowering it admits things that are not faces. Rarely worth changing — it was the least useful dial in testing, and moving it in either direction cost accuracy
Detection size (px)800How big a copy the face search runs on. Your image is never scaled; this only affects the search. Raise it if faces in group photos are missed. Cost grows with the square — 1600 is about 4× the work of 800
JPEG qualityautoQuality to re-save a rotated JPEG at. auto matches what the photo already had. Ignored for PNG; photos that are not rotated are never re-saved at all

The first two are the ones worth touching. Both defaults were measured over 98 real album photographs, not guessed:

How sure before rotatingFixedTurned the wrong way
Fix as many as possible (1.0)370
Balanced (1.1) — default370
Cautious (1.5)350
Only when certain (2.0)290

None of those turn a photo the wrong way, because safety does not come from the threshold — it comes from a rule inside the node: two independent readings of the same faces must point the same way before it acts. One reading asks which orientation holds the most face; the other asks which the detector was most certain about. Where they disagree the record says mixed_signals and the photo is left alone. Without that rule, matching this coverage cost two photos turned wrongly.

So the setting trades coverage, not correctness. Lower it to fix a few more marginal cases; raise it if you want the node to touch as little as possible.

Face clarity vs face size

Each rotation is scored as confidence ^ k x face area, and this setting is k. It matters for one specific failure: an upside-down face is still detected, just less confidently — and the box drawn around it is sometimes larger than the box around the upright one. At k = 1 the bigger box wins and the photo is left the wrong way up.

SettingFaces neededCorrectedTurned the wrong way
Balanced (1) — default2370
Favour the clearer face (4)2381
Strongly favour (8)1393

Raising it rescues photos the default cannot reach, and costs errors elsewhere — the two move together, so treat it as "how much am I willing to check by hand afterwards". It interacts with Faces needed to decide: the highest setting only reaches those photos when that is also 1, because they are single-face pictures.

If something looks wrong

SymptomTry
A photo came out the wrong way roundRaise How sure before rotating. This should not happen; the file is worth keeping as an example
Too many photos left aloneLower How sure before rotating toward 1.0, then Faces needed to decide to 1
Portraits of one person are never rotatedLower Faces needed to decide to 1 — there is only ever one face to find
Faces in group shots are missedRaise Detection size; cost grows with the square, so 1600 is ~4× the work of 800
Nothing is ever rotated, every record says no_modelThe model could not be downloaded. Check network access from the engine host

Limitations

  • It needs faces. Landscapes, documents and photographs of the backs of people's heads give it nothing to work with, and it will abstain on them. That is the honest boundary of the approach, not a tuning problem.
  • Upside-down photos are the hardest case. A face detector fails on a sideways face, which is what makes 90°/270° detectable; it fails less reliably on an inverted one, so 180 corrections are less often confident than quarter turns.
  • Expect a residue it cannot reach. On a 98-photo album it corrects 37 and leaves the rest, most of them genuinely upright but some not. A photo where one reading says upright and the other says inverted is exactly the case it refuses, and it will keep refusing it — the text lane names those so they can be done by hand rather than hunted for.
  • Only JPEG and PNG are re-saved. Other formats are still analysed, and the record names unencodable_format as the reason — but it reports rotation: 0, not the correction it worked out, so it tells you the image was left alone and not which way it should go. The node will not re-encode these, because it has no way to recover their original compression settings and would be choosing one for you.
  • No EXIF is carried over. A rotated image is re-encoded with OpenCV, which writes no EXIF and no colour profile. Photos that are not rotated keep their bytes exactly, so they keep everything.

Schema

FieldTypeDescriptionDefault
image_orient.confidenceWeightnumberFace clarity vs face size
When one rotation shows a bigger face but another shows a clearer one, this decides which wins. 'Balanced' is the safe default: measured over 98 album photographs it corrected 37 and got none wrong. Raising it rescues photos where an upside-down face is detected with a larger box than the upright one - but it acts on thinner evidence, and at the highest setting with 'Faces needed to decide' at 1 it corrected 39 and got 3 wrong. Raise it only if upside-down photos are being missed, and check the results.
1
image_orient.detectSizeintegerDetection size (px)
How big a copy of the photo the face search runs on. Your image is never scaled - this only affects the search. Raise it if faces in group photos are being missed; the cost grows with the square, so 1600 is about four times the work of 800.
800
image_orient.marginnumberHow sure before rotating
How clearly the winning orientation must beat the next best one. Measured over 98 real album photographs, 'Balanced' corrected 37 and got none wrong. Move up if a photo ever comes out the wrong way round; move down only if you would rather fix more and check the results yourself.
1.1
image_orient.minConfidencenumberMinimum face score
How certain the detector must be that something is a face before it gets a say. Raising it ignores doubtful faces; lowering it lets more in, including things that are not faces at all.
0.6
image_orient.minFacesintegerFaces needed to decide
How many faces must agree before the photo is turned. One face is thin evidence and was behind most of the mistakes in testing, so two is the default. Lower to 1 for portraits and single-subject photos, where there is only ever one face to find.
2
image_orient.qualitystringJPEG quality
Type 'auto' to save at the same quality the photo already had, or a number from 1 to 100. Leave it on 'auto': the image has been through JPEG once already, so saving higher only makes the file bigger without recovering anything. Ignored for PNG, which is lossless. Photos that are not rotated are never re-saved at all.
"auto"