Image Quality Checker — Detect Blurry, Dark & Duplicate Photos avatar

Image Quality Checker — Detect Blurry, Dark & Duplicate Photos

Pricing

from $0.70 / 1,000 image checkeds

Go to Apify Store
Image Quality Checker — Detect Blurry, Dark & Duplicate Photos

Image Quality Checker — Detect Blurry, Dark & Duplicate Photos

Score photos 0-100 and flag blurry, motion-blurred, too dark, overexposed, noisy, low-contrast, low-resolution and duplicate images in bulk. For listings, uploads, KYC and AI datasets. Fast CPU checks, pay per image.

Pricing

from $0.70 / 1,000 image checkeds

Rating

0.0

(0)

Developer

Leandro Zanatta

Leandro Zanatta

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 days ago

Last modified

Categories

Share

Image Quality Checker — Blurry, Dark & Duplicate Photo Detection

Check photos in bulk before they go live or into a dataset. Every image gets a 0–100 quality score, a clear pass / flagged verdict and the reasons: blurry, motion blur, too dark, overexposed, low contrast, noisy, low resolution or duplicate of another image in the batch. Fast CPU measurements, no AI service calls, pay per image.

Five photos checked: one passed, four flagged as blurry, motion blur, too dark and duplicate, with scores and measurements

Real output of this Actor on its sample set (photos CC BY-SA 4.0, Wikimedia Commons, with blur and darkening added).

Why use it

  • 🚫 Stop bad photos at the door: blurry listing photos, dark selfies and tiny thumbnails cost conversions, re-shoots and support tickets.
  • 🧹 Cleaner AI datasets: drop blurred, dark and duplicate images before labeling or training.
  • 🎯 Tells you why: each issue is named, with the measurement behind it, so you can show users a precise message ("photo is too dark").
  • 🔁 Finds duplicates: resized or re-compressed copies of the same photo in a batch are flagged.
  • ⚙️ Your rules: strict, standard or lenient presets, or set each threshold yourself; choose which issues should not fail an image.
  • ⚡ Fast and cheap: about 0.2 s of CPU per 10-megapixel photo; nothing is sent to external AI services.

Who uses it

SectorTypical use
Marketplaces & classifiedsReject or warn on blurry, dark or tiny listing photos before publishing
Real estate & hospitalityAudit property and room photos across thousands of listings
E-commerceCheck product photos from suppliers before they reach the catalog
KYC & onboardingAsk users to retake a document photo or selfie that is too dark or blurry
AI & data teamsFilter training images and remove duplicates
Insurance & inspectionsMake sure field photos are usable before closing a claim or report
Media & DAMSort archives by quality and find duplicate files

Checks

IssueHow it is measuredStandard threshold
blurryLaplacian variance on the most detailed parts of the picture, divided by contrast (a soft background or a dark photo is not mistaken for blur)sharpness < 20
motion blurSame, plus a direction check: camera shake removes detail in one direction onlysharpness < 20 and direction balance < 0.08
too darkAverage brightness, share of pure-black pixelsbrightness < 40 or > 15% clipped
overexposedAverage brightness, share of pure-white pixelsbrightness > 215 or > 15% clipped
low contrastStandard deviation of brightness< 25
noisyNoise measured in the smoothest areas (sky, walls), where texture can't be confused with noise> 1.0
low resolutionShort side in pixels< 480 px
duplicatePerceptual hash compared with earlier images in the rundistance ≤ 6

Tested on four real photos, each degraded eight ways (Gaussian blur, horizontal and vertical motion blur, darkening, overexposure, noise, low resolution, low contrast): 35 of 36 cases flagged correctly, and every original passed. The one miss was a vertical shake on a wide landscape, labeled blurry instead of motion blur (still flagged). Typical sharp photos score 30–200 in sharpness, blurry ones under 10.

Input

FieldTypeDefaultDescription
Image URLs (imageUrls)array—Photos to check (JPEG, PNG, WebP, BMP, TIFF), up to 100 MB. Google Drive and Dropbox links work
Strictness (preset)stringstandardstandard, strict (print, product, documents) or lenient (user content, thumbnails)
Issues that do not fail an image (ignoreIssues)array—Still reported, but passed stays true
Flag duplicates (findDuplicates)booleantrueCompare each image with the earlier ones in the run
Duplicate tolerance (duplicateDistance)integer60 = identical only, 6 = resized/re-saved copies, 12 = similar shots
Threshold overridesstringpresetminSharpness, minBrightness, maxBrightness, maxClippedPercent, minContrast, maxNoise, minShortSide
PresetSharpnessBrightnessClippedContrastNoiseShort side
lenient≥ 1025–230≤ 25%≥ 15≤ 2.0≥ 240 px
standard≥ 2040–215≤ 15%≥ 25≤ 1.0≥ 480 px
strict≥ 3060–200≤ 8%≥ 35≤ 0.7≥ 1000 px
{
"imageUrls": ["https://example.com/listing/123/1.jpg", "https://example.com/listing/123/2.jpg"],
"preset": "standard",
"ignoreIssues": ["low resolution"]
}

Output

{
"sourceUrl": "https://example.com/listing/123/2.jpg",
"passed": false,
"qualityScore": 65,
"issues": [
"blurry"
],
"width": 1600,
"height": 899,
"megapixels": 1.44,
"fileBytes": 76368,
"sharpness": 0.27,
"directionBalance": 0.228,
"brightness": 105.4,
"contrast": 46.8,
"shadowsClippedPercent": 0.0,
"highlightsClippedPercent": 0.09,
"noise": 0.05,
"colorfulness": 41.7,
"phash": "ebcc84d4d0c8eaae",
"duplicateOf": null
}

passed is true when the image has no issue (except those in ignoreIssues). qualityScore (0–100) is useful to sort or rank images. A run summary (passed, failed, duplicates) is saved as SUMMARY. Failed downloads return an error field and are free.

Pricing

Pay per image checked, plus a tiny per-run start fee. No subscription. Apify plan discounts apply automatically (see the Pricing tab).

ExampleImages billed
One listing with 12 photos12
5,000 product images5,000
100,000 dataset images100,000

Use it from code or an AI agent

Python: keep only the good photos

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("adorable_partial/image-quality-checker").call(run_input={
"imageUrls": ["https://example.com/a.jpg", "https://example.com/b.jpg"],
"preset": "standard",
})
good = [r["sourceUrl"] for r in client.dataset(run["defaultDatasetId"]).iterate_items() if r.get("passed")]
print(good)

JavaScript: show the user why a photo was rejected

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('adorable_partial/image-quality-checker').call({
imageUrls: ['https://example.com/upload.jpg'],
});
const [r] = (await client.dataset(run.defaultDatasetId).listItems()).items;
if (!r.passed) console.log(`Please retake the photo: ${r.issues.join(', ')}`);

HTTP

curl -X POST "https://api.apify.com/v2/acts/adorable_partial~image-quality-checker/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"imageUrls": ["https://example.com/photo.jpg"]}'

No-code and agents: check new uploads with Make, Zapier or n8n, chain it after a scraper with an integration, or let an AI agent judge photos through the Apify MCP server.

FAQ

My product photos on white background are flagged as overexposed. White backgrounds have many pure-white pixels. Raise maxClippedPercent (e.g. 60) or add overexposed to ignoreIssues.

Night photos are flagged as too dark. That is the intended signal; use the lenient preset or lower minBrightness for night content.

Does it judge composition or aesthetics? No. It measures technical quality (focus, exposure, noise, size, duplicates), which is objective and explainable.

Are duplicates checked against previous runs? Only within one run. Each row includes its phash, so you can compare across runs in your own database (Hamming distance).

Is my data kept? Images are processed inside the run and not stored; only the measurements are saved in your dataset.

Support

A photo judged wrongly? Open an issue in the Issues tab with the image link and the result.

Need a different tool? Request it

Missing a feature, an input or output format, or a whole different tool for your workflow? Open an issue in the Issues tab and describe what you need:

  • what goes in (files, URLs, data) and what should come out,
  • roughly how much you process (per day or month),
  • one example, if you can share it.

Requests with a real use case get built, either as a new option in this Actor or as a new Actor in this collection, and you get notified in the issue when it's live. Every request is read.