Image Processing

Detecting Blurry Images with Node.js: No OpenCV Required

Pablo Schaffner
5 min readUpdated Nov 17, 2025
#Node.js#Image Processing#Sharp#Computer Vision#npm
Detecting Blurry Images with Node.js: No OpenCV Required
Challenge

The Problem

You're building a photo app. Users upload images. Some are sharp, others... not so much. You need to detect blurry images programmatically.

The obvious solution: OpenCV. Industry standard. Battle-tested.

The problem: OpenCV adds 50MB+ to your bundle. For a simple blur detection feature, that's overkill.

There had to be a lighter way.

Approach

The Solution

The insight: Blur detection is about detecting edges. Sharp images have strong edges. Blurry images don't.

The tool: The Laplacian operator. A simple mathematical operation that highlights rapid changes in image intensity—exactly what edges are.

The implementation: Node.js + Sharp (the high-performance image library) + a custom Laplacian kernel.

Bundle size: Less than 1MB. Sharp is lean and fast.

Theory

How It Works

Convolution:

Imagine pressing a small stamp across an entire image, one section at a time. At each position, you're checking how well the stamp pattern matches that section. The result of this "stamping" process is a new image. In image processing, this is called convolution.

Kernel:

The stamp is the kernel—a small matrix of numbers that defines the pattern we're looking for. By changing the kernel, we can detect different features: edges, textures, or blur.

Laplacian Kernel:

The Laplacian kernel: a 3x3 matrix that detects edges by highlighting rapid intensity changes

This 3x3 matrix detects edges. When applied to an image:

  • Sharp images produce high variance (lots of edge detail)
  • Blurry images produce low variance (edges are soft/missing)

Visual comparison: Blurred image (low Laplacian variance) vs. Sharp image (high variance)

That's it. Simple math, powerful results.

Code

The Implementation

I built blurry-detector, a lightweight npm package that wraps this logic into a clean API.

Installation:

npm install blurry-detector

Core class:

javascriptindex.js
const sharp = require('sharp');

class BlurryDetector {
constructor(threshold = 300) {
  this.threshold = threshold;
}

async computeLaplacianVariance(imagePath) {
  // Laplacian kernel
  const laplacianKernel = {
    width: 3,
    height: 3,
    kernel: [0, 1, 0, 1, -4, 1, 0, 1, 0]
  };

  // Convolve image with kernel
  const laplacianImageData = await sharp(imagePath)
    .greyscale()
    .raw()
    .convolve(laplacianKernel)
    .toBuffer();

  // Calculate variance
  const mean = laplacianImageData.reduce((sum, value) => 
    sum + value, 0) / laplacianImageData.length;
  
  const variance = laplacianImageData.reduce((sum, value) => 
    sum + Math.pow(value - mean, 2), 0) / laplacianImageData.length;

  return variance;
}

async isImageBlurry(imagePath) {
  const variance = await this.computeLaplacianVariance(imagePath);
  return variance < this.threshold;
}
}

module.exports = BlurryDetector;

CLI tool:

javascriptcli.js
#!/usr/bin/env node
const yargs = require('yargs');
const BlurryDetector = require('./index');

const argv = yargs
.usage('Usage: $0 <imagePath> [options]')
.command('$0 <imagePath>', 'Assess image for blurriness', (yargs) => {
  yargs.positional('imagePath', {
    describe: 'Path to the image',
    type: 'string'
  });
})
.option('t', {
  alias: 'threshold',
  describe: 'Threshold for blurriness',
  default: 300,
  type: 'number'
})
.help('h')
.alias('h', 'help')
.argv;

const detector = new BlurryDetector(argv.threshold);

detector.isImageBlurry(argv.imagePath).then(isBlurry => {
if (isBlurry) {
  console.log('🔍 Given image is blurred!');
} else {
  console.log('🔍 Given image seems focused!');
}
});

Usage:

blurry-detector path/to/image.jpg
# Output: 🔍 Given image seems focused!
 
blurry-detector path/to/blurry.jpg --threshold 250
# Output: 🔍 Given image is blurred!
Applications

Real-World Usage

Photo upload validation: Automatically reject blurry uploads in your photo app.

Quality control: Batch process image collections and flag low-quality photos.

Camera feedback: Provide real-time feedback to users about image sharpness.

Image pipeline optimization: Skip expensive processing (resizing, filters) on blurry images.

The threshold is adjustable. Different use cases need different sensitivity:

  • Strict (400+): Only the sharpest images pass
  • Moderate (300): Balanced default
  • Lenient (200): Catches only obviously blurry images
Insights

Performance & Trade-offs

What this approach does well:

  • Fast: Sharp is one of the fastest image processing libraries for Node.js
  • Lightweight: No 50MB+ OpenCV dependency
  • Simple: One file, minimal dependencies
  • Configurable: Adjust threshold to your needs

What it doesn't do:

  • Not ML-based: This is classical computer vision, not deep learning
  • Context-agnostic: Doesn't understand image content (faces, objects)
  • Threshold tuning required: Different image types may need different thresholds

For most use cases, this simple approach is enough. If you need ML-based quality assessment, you'd reach for TensorFlow.js or similar—but for basic blur detection, Laplacian variance gets you 90% there with 10% of the complexity.

Lessons

What I Learned

On bundle size:

Always question heavyweight dependencies. OpenCV is amazing, but do you need 50MB for a single feature? Often, simpler solutions exist.

On classical computer vision:

Not everything needs ML. The Laplacian operator is 40+ years old and still works perfectly for edge detection. Don't overcomplicate.

On API design:

The best APIs have sensible defaults but allow customization. threshold = 300 works for most cases, but users can adjust it.

On packaging:

A good npm package should be:

  • Single-purpose (does one thing well)
  • Well-documented (clear examples)
  • CLI-friendly (can be used from command line or code)
Resources

Try It Yourself

GitHub Repository:
github.com/puntorigen/blurry-detector

npm Package:
npmjs.com/package/blurry-detector

Install:

npm install blurry-detector

Quick example:

javascript
const BlurryDetector = require('blurry-detector');
const detector = new BlurryDetector();

detector.isImageBlurry('photo.jpg').then(isBlurry => {
console.log(isBlurry ? 'Blurry 😢' : 'Sharp! 🎯');
});

Use cases to explore:

  1. Build a photo quality checker
  2. Add to your image upload pipeline
  3. Create a bulk image analysis tool
  4. Integrate with camera preview for real-time feedback

The code is open source. Fork it, extend it, make it your own.

Node.jsSharpJavaScriptLaplacian OperatorImage Processingnpm

Technologies Used

Node.jsSharpJavaScriptnpm

Share this article

TweetShare