STAYCHARTED BLOG · AMAZON S3 · IMAGE CLASSIFICATION
How to classify images in an S3 bucket with your own categories
Sort the photos in your S3, R2, B2 or Google Cloud bucket into your own categories, learned from the folders you have. Originals untouched.
The usual ways to classify images in S3
1. A Lambda function calling a general image API. An S3 upload triggers a Lambda, which sends the photo to Amazon Rekognition's DetectLabels (or Google Cloud Vision) and stores the labels. It's quick to build, but the labels are the service's own: "Box", "Car", "Machine". They can't say crushed corner or PN-10423, because they've never seen your categories.
2. Amazon Rekognition Custom Labels. It learns your own labels, and it can take them from your S3 folder names. The catch is running it: you start the trained model before you use it, you're charged for every hour it's running, and you stop it yourself. For a folder that fills up once a day, you either leave it running or build the start and stop around it.
3. Build your own. A SageMaker notebook, a pre-trained vision model, a training script, an endpoint and the code around it. That's flexible, but it's weeks of work and someone to keep it running.
If you used Amazon Lookout for Vision for defect photos: AWS ended support for it on 31 October 2025, so those models need a new home too.
What you probably already have
Most teams don't start from nothing. The photos are already sorted, one way or another:
- By folder:
parts/PN-10423/IMG_4412.jpg,claims/water-damage/… - By file name:
PN-10423_front.jpg,crushed-corner_0041.jpg - By keyword: your photo library or inspection app wrote the category into each photo's own metadata (its keywords, title or description).
That sorting is the training data. You don't need to label anything again.
Train from the bucket
With StayCharted AI Model Trainer, the photos are read where they already are. There's no ZIP to build and no spreadsheet of links.
- Connect the storage in Settings → Storage. For Amazon S3, a CloudFormation template makes a role in your account, with no key to paste. You list the folders AMT may read, and, only if you want sorted copies, the folders it may copy into. The role is written from those lists: read-only unless you ask for copies, and never a delete.
- New model → Pictures → From your storage. Pick the folder, and say where each photo's category is: its folder name (at the level you choose), its file name, or a metadata field in the photo. A preview shows the categories and counts before anything is read.
- Check your pictures. Every photo is checked before training. You see photos that look like they belong in another category, the same photo under two categories, and near-identical copies, each one click to fix.
- Train and test. The model learns from the picture itself, never from the folder
or file name, because a new photo arrives as
IMG_4412.jpg. It's tested on photos it never trained on, and the report shows how often it's right per category.
New photos for a category later? Add new photos from this folder reads only the ones it hasn't read before, then you retrain.
Sort new photos back into the bucket
Categorize new pictures → From your storage. Pick the folder of new photos. It can be in another bucket. By default only photos this model hasn't answered before are read, so a folder that fills up every day is one click: Fill new photos.
What you get back:
- A spreadsheet in Filled files, one row per photo, with its category and confidence.
- Answers it's unsure of go to the Review Queue, for a person to check.
- Optional: a sorted copy of each photo, in
<your folder>/<category>/, with unsure ones in<your folder>/_needs-review/. It's a server-side copy, so the photo isn't downloaded again, and only folders you listed can be written to. - Optional: tags on each copy:
staycharted-category,staycharted-confidence,staycharted-reviewandstaycharted-model, beside the photo's own tags. - Optional: the category in each copy's metadata, as a keyword, title or description, so your photo library or DAM sees it too.
Your originals are never written to. Not moved, not re-encoded, not tagged, not deleted. A sorted copy is your photo exactly, with only the additions you ticked.
Route them with EventBridge
Because the copies land in folders by category, your own AWS workflow can pick them up. Turn on Amazon EventBridge notifications for the bucket, then add a rule that matches new copies in the review folder:
Show JSON example
{
"source": ["aws.s3"],
"detail-type": ["Object Created"],
"detail": {
"bucket": { "name": ["parts-photos"] },
"object": { "key": [{ "prefix": "sorted/_needs-review/" }] }
}
}
Send it to an SNS topic for the team, a Step Functions workflow, or a Lambda. Match
sorted/PN-10423/ instead to start the reorder for one part. The setup guide has the
details: Connect your storage.
Not only Amazon S3
The same connection works with any storage that speaks the S3 API at a public HTTPS address:
| Storage | How it connects |
|---|---|
| Amazon S3 | A role made by our template (no key), or an access key |
| Cloudflare R2 | An R2 API token's access key and your account ID |
| Backblaze B2 | An application key and your bucket's region |
| Wasabi | An access key and region |
| DigitalOcean Spaces | A Spaces access key and region |
| Google Cloud Storage | An HMAC key (Cloud Storage → Settings → Interoperability) |
| Other S3-compatible | Any S3 endpoint at a public HTTPS address |
How accurate is it?
It depends on your photos and how different your categories look, so the report measures it on your own photos, per category, before you rely on it. On a public set of car damage photos (6 categories, front or rear, broken, crushed or undamaged, 552 held-out photos), measured on our production service:
| StayChartedAI Model Trainer · model comparison | ||
|---|---|---|
| Model | Right | Projected after review |
| AI Image Classifier Model | 76.6% | 83.5% (12% checked) |
| Dedicated AI Image Model | 86.4% | 95.8% (23% checked) |
The full method is in the car photo benchmark.
Projected results assume a person corrects every flagged mistake without introducing errors. Human review was not measured in this test.
What it doesn't do yet
Azure Blob Storage isn't S3-compatible. It needs its own connector, which is planned.
- Private storage (inside a VPN, or a MinIO only your network can reach) can't be reached from our service. That's a self-hosted conversation: contact us.
- Watching a folder by itself. New photos are read when someone presses Fill new photos. Filling on a schedule is planned.
Common questions
Does StayCharted change the photos in my bucket?
No. Originals are only read. When you ask for sorted copies, the only write is a copy into a folder you listed, and the role itself can't write anywhere else.
What permissions does it need?
To train and fill: list and read, on the folders you name. For sorted copies: write on the copy folder only, plus reading the original's tags so the copy keeps them. Never delete.
Does it keep my photos?
It keeps its own small copy of each photo (at most 512 pixels on a side), made from the pixels alone, plus a thumbnail, for training, the report and the Review Queue. The original isn't kept. Deleting the model deletes them.
How many photos do I need per category?
At least 10, and 20 or more is better. Categories that look alike need more. The report shows which ones.
I already use Rekognition Custom Labels. Can I use the same bucket?
Yes. If your training photos are in folders named by label, which Custom Labels can also use, connect the same bucket and train from the same folders.
What does it cost?
Reading pictures needs the Vision add-on, on Essentials or Business. The photos read count toward your plan's pictures a month. See pricing.