A rule like "keep the text at least 10 px tall for OCR" doesn't say which 10 px. A 10 px font size, a 10 px text line and a 10 px capital letter are three different images, and on a small screenshot the gap between them can move a result from zero errors to a few. The definition behind the samples in this post is narrow on purpose: text height is the height, in pixels, of the inked bounding box of a capital "H".
Font size and line height both overstate it
Font size describes the em box, the slot a typeface draws into, and a capital H only fills part of it. The samples were built in reverse: the Times New Roman font size was nudged in 0.2 px steps until the H came out exactly the target height, so the "12 px" sample needed a font size above 12. Line height overstates it even more, because an English line also carries ascenders and descenders (b, d, g, p, y). Measured by horizontal projection, which treats each band of rows containing ink as one line, the result came out at about 1.37 times the H height: 17 px for the 12 px sample, 22 for 16, 82 for 60.
Each engine needed a different minimum H height
The sample is one self-written English paragraph of 452 characters, black on white, rendered directly at nine heights from 6 to 60 px. The score is character accuracy, 1 minus edit distance over character count, on an Apple M4 Mac with one run per image, using the built-in macOS text recognition in accurate mode, Tesseract 5.5.3 with its English model, and the image text recognition in ImgIng https://imging.ai/ , run in a desktop browser (the first run downloads a recognition model of about 31.2 MB). Taking the floor as the smallest height with zero errors, Tesseract needed 16 px, macOS 12 px, and ImgIng was already clean at 8 px.
Below those floors the slopes differed a lot. At 8 px Tesseract made 21 errors (95.35%) and macOS made 3, and Tesseract still made 3 at both 10 and 12 px. At 6 px, where an H is six rows of pixels, Tesseract fell to 16.81% and macOS to 25.88%, while ImgIng still read 96.02%. Above each floor the errors stayed at zero all the way to 60 px, apart from one stray miss by ImgIng at 12 px, so "tall enough" behaves like a floor rather than a sweet spot. That is where the projection mistake bites: a 12 px screenshot measured by line height reads 17, looks safely past Tesseract's 16, and really sits where it still made 3 errors.
Measuring the H height in a real screenshot
A real screenshot doesn't come with its font size attached, so the height has to be read off the pixels. Connected components work much better than projection for English: threshold the image, label each blob of touching ink, drop specks, and take a high percentile of blob heights, since the tall letters set the top. The five lines below are an illustrative sketch of that idea, not the script that produced the numbers in this post.
gray = cv2.imread(path, cv2.IMREAD_GRAYSCALE) _, ink = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) _, _, stats, _ = cv2.connectedComponentsWithStats(ink, connectivity=8) blobs = stats[1:] glyph_h = np.percentile(blobs[blobs[:, cv2.CC_STAT_AREA] >= 3, cv2.CC_STAT_HEIGHT], 90) On the English samples this read exactly 6, 8, 10 and 12 px for the small ones and drifted slightly high on large text, 63 for 60. Ruling lines break projection completely: on a table screenshot the lines joined every row into one band and projection returned 559, while connected components returned 23. On the Chinese samples both methods stayed within ±2 px up to 30 px, so the 1.37x overstatement is mostly an English problem.
Once the H height is known, enlarging helps only some engines. Scaling the 8 px sample to about 32 px with bilinear interpolation took Tesseract from 21 errors to 0. macOS gained at 6 px (335 down to 77) without getting back to native 12 px quality, and ImgIng barely moved, while Lanczos pushed its 6 px sample from 18 errors to 115. A rule that fits this one sample set: measure the H height first, enlarge toward about 32 px with bilinear only when it is under your engine's floor, compare the output before and after, and take a larger screenshot instead whenever you can.
These are clean renders in one typeface, one run each. Real screenshots carry compression and noise, so my guess is they need a little more height than the floors above, but that part wasn't tested.