Faizaniqbal/british-library-book-images
British Library Book Images 1,080,814 images cut out of 49,455 digitised books (65,227 volumes, ~25 million pages) published between c. 1510 and c. 1900, digitised by the British Library in partnership with Microsoft and released by British Library Labs on Flickr Commons as the "1 Million Images from Scanned Books" release. The books cover geography, philosophy, history, poetry and literature, in several languages. The four image types British Library Labs… See the full description on the dataset page: https://huggingface.co/datasets/Faizaniqbal/british-library-book-images.
British Library Book Images
1,080,814 images cut out of 49,455 digitised books (65,227 volumes, ~25 million pages) published between c. 1510 and c. 1900, digitised by the British Library in partnership with Microsoft and released by British Library Labs on Flickr Commons as the "1 Million Images from Scanned Books" release. The books cover geography, philosophy, history, poetry and literature, in several languages.
The four image types
British Library Labs deposited these as four separate records, split by an algorithmic estimate of what each cut-out region is. Each is a config here:
The type labels are algorithmic, not curatorial. The deposit states the images were "algorithmically gathered" but does not state the method, so plates / medium / embellishments are best read as size-and-position heuristics over the page, not as an art-historical taxonomy. Expect the boundary between medium and plates in particular to be fuzzy. Filter on your own classifier if the distinction matters to your task.
from datasets import load_dataset
# pick a config — the whole thing is ~621 GB, so stream unless you mean it
ds = load_dataset("biglam/british-library-book-images", "covers", split="train", streaming=True)
print(next(iter(ds)))Images per decade
The 1890s alone hold a third of the corpus, and everything before 1800 together holds about 1.6% of it. Anything trained on the whole set is overwhelmingly a model of late-Victorian book illustration.
Note the plates column before and after 1800: 86 images in the entire 1690s against 4,682 in the 1800s. Full-page plates are a 19th-century printing phenomenon here, not an even feature of the date range.
Data fields
image— the JPEG, at source resolutiondate— publication year as a string, not an integer. 5,291 rows (0.5%) carry"Unknown", and 2,151 rows carry a date after 1900 — up to 1946 — which the deposit's own c. 1510–c. 1900 framing marks as catalogue errors rather than genuinely 20th-century books. Cast and filter before doing anything arithmetic with it.fname— the original filename. The leading digits are the British Library system number (see below), and the rest encodes volume/page position plus the book title. The exact layout differs between image types, so parse defensively.image_type— one of the four above, redundant with the config but kept so the configs can be concatenated.
Joining images to their page text
The leading digits of fname are the British Library system number, which is the record_id in `biglam/blbooks-parquet` — the OCR text from the same digitisation programme. In a 20,000-row sample, 8,497 of 8,846 distinct system numbers (96%) matched a record there, so most images can be traced back to the book they were cut from and its text.
# system number -> the book this image came from
fname = "002543810_3_Dzieje Narodu Polskiego...jpg"
record_id = fname.split("_")[0] # "002543810"The 4% that don't match are books present in the image deposit but absent from the OCR release. The join is at book level, not page level — fname encodes a page position, but it is not guaranteed to align with the pg column in the OCR corpus, so treat page-level alignment as something to verify rather than assume.
What was selected, and by whom
The date range is not a sampling frame. The corpus is what the British Library and Microsoft chose to digitise from what the Library had acquired from what happened to survive — three selection layers stacked before any image reached this dataset — and digitisation programmes of this era were driven partly by preservation priorities and out-of-copyright status rather than by any attempt at representativeness. The 19th century dominates. Treat the collection as a record of what a large British institution digitised in the early 2010s, not as a sample of printed illustration.
Colonial-era publishing is heavily represented, and images carry the depictions, captions and categories of their period. Nothing here has been reviewed for offensive content.
Related datasets
The OCR text from the same digitisation programme is `biglam/blbooks-parquet` (14,011,953 pages).
Licensing
The images were published on Flickr Commons under no known copyright restrictions — the British Library placed them in the public domain, and the underlying works are out of copyright. Tagged cc0-1.0 here for machine-readability; the deposit's own statement is the Public Domain Mark.
No licence attaches to the images themselves that would restrict reuse. Attribution to the British Library is expected practice rather than a legal condition.
Credit
Mirrored and repackaged by Daniel van Strien (Machine Learning Librarian, Hugging Face); all source data created by the British Library, digitised in partnership with Microsoft and released by British Library Labs.
The four image types were deposited as four separate records on the British Library Research Repository (bl.iro.bl.uk), which is intermittently unavailable — this dataset is the more reliable route to the images.
Against the counts those deposits state, this dataset is a handful of images short: 6 fewer plates, 1 fewer medium, 13 fewer covers. The shortfall predates this repackaging and no cause has been established for it.
Point of contact for the original deposit: labs@bl.uk
Maintenance: Limited Maintenance — this is a mirror of a static 2014 deposit and is not expected to change.
Citation
@misc{bl_labs_book_images,
title = {Digitised Books. c. 1510 - c. 1900. JPG},
author = {{British Library Labs}},
year = {2014},
publisher = {British Library},
howpublished = {\url{https://bl.iro.bl.uk/}}
}SigLIP2 embeddings (siglip2_embeddings config)
Every image in this dataset, embedded with google/siglip2-so400m-patch16-256 (1152-d float32, images resized to 256x256 before encoding — the model's own preprocessing shape). One split per image config; rows are sorted to match the source parquet exactly, so row N of split `plates` is row N of config `plates`. Each row also carries source_filename and file_row_number, the direct coordinates of its image in this repository.
from datasets import load_dataset
emb = load_dataset("biglam/british-library-book-images", "siglip2_embeddings", split="plates")Because SigLIP2 is a dual encoder, text queries embed into the same space — encode a phrase with the model's text tower and rank rows by cosine similarity for free-text search over the collection.
Notes: embeddings were produced with vLLM serving SigLIP2 as a pooling model on Hugging Face Jobs; all 1,080,814 images are covered, one embedding each. 768 image pairs (1,536 filenames) are near-duplicates differing only in title spacing (same system number/volume/page/block) — these are distinct rows here, as in the source configs.
Crop masks (crop_masks config)
Model-predicted instance masks and bounding boxes for 1,019,266 images — every image in the embellishments, plates and medium configs (covers is excluded: the model cannot abstain, and covers are overwhelmingly not illustrations). The ABBYY-derived crops in this dataset are loose — a medium crop typically carries lines of body text above the art and a printed caption below — and these masks are the tightening layer: 3,022,916 instances, one row per image, joinable on fname.
Each row carries objects (index-aligned lists: bbox as [x, y, w, h] in source-frame pixels, score, area, rectangularity) and masks_rle (a JSON string of COCO RLE dicts in the same order; the RLE frame is the full-resolution source image, src_width x src_height).
Filter by `score` before display use. Predictions were kept down to a deliberately low threshold of 0.10 so that consumers can choose their own operating point, and 59.7% of instances score below 0.3 — at 0.10, dense pages can carry dozens of low-confidence instances. score >= 0.3 is a sensible display default; the confident singletons that dominate the corpus (76% of images have exactly one instance) are unaffected.
import json
from datasets import load_dataset
from pycocotools import mask as maskutil
masks = load_dataset("biglam/british-library-book-images", "crop_masks", split="plates")
row = masks[0]
rles = json.loads(row["masks_rle"])
keep = [i for i, s in enumerate(row["objects"]["score"]) if s >= 0.3]
m = maskutil.decode(rles[keep[0]]) # HxW numpy array, source frameTo join masks against the image configs' metadata, DuckDB reads both sides straight off the Hub with column pruning — no image bytes are fetched unless you select the image column:
import duckdb
duckdb.sql("""
SELECT i.fname, i.date, m.objects, m.masks_rle
FROM 'hf://datasets/biglam/british-library-book-images/plates/*.parquet' i
JOIN 'hf://datasets/biglam/british-library-book-images/crop-masks/plates-*.parquet' m
USING (fname)
""")Provenance: predicted by davanstrien/bl-crop-tighten-rfdetrseg-clip10, an RF-DETR-Seg student distilled from Falcon-Perception weak labels on 8,400 of these crops. On a 40-image random human check, 97.4% of the student's predictions were judged acceptable — matching its teacher, at roughly 12x the throughput. Every row is stamped with model_id and model_sha.
