DEV Community

Misael Braga de Bitencourt
Misael Braga de Bitencourt

Posted on

NodeJS: Blurring Human Faces in Photos

Face Blur

**This article was automatically translated from Portuguese by ChatGPT, the original article could be found here.

In 2017, I created a small utility in NodeJS to blur faces of people in photos. When this program was executed, it searched for all image files in a specified directory and then blurred (or removed) all the faces from the photos. The integrity of the photos was preserved, with only the facial expressions being removed.

This became a useful utility for not recording sensitive user data, which is their own face. It can be helpful for use on websites where the identity of children or individuals who do not wish to be exposed needs to be preserved.

In recent weeks, I have been refactoring this project, which was previously written in JavaScript and has now been refactored into TypeScript. I took the time to write this article to demonstrate how simple it is to implement this solution using a few libraries.

Gloob + OpenCV4NodeJs + JIMP

These three libraries can be combined to generate the proposed solution.

Gloob

Gloob is the most well-known and widely used among the three. It is used to search for files using shell-like commands, and the same implementation works on all platforms. For example:

const filesStream = await glob('**/*.dat')
Enter fullscreen mode Exit fullscreen mode

The code above will search for .dat files in all directories from the context and return a list of them.

OpenCV4NodeJs

The OpenCV4NodeJs A.I. library provides an interface for calling OpenCV routines in NodeJS.

Face recognition

JIMP

The last library is used for image manipulation in JavaScript in NodeJS. JIMP is used to apply the blur effect to the region where faces exist.

Although in this example, we only use it for this purpose, JIMP is a powerful tool in the style of ImageMagick that allows us to perform various types of image manipulation. Below is an example of how to resize a photo, change its quality, and its color palette in just a few lines:

Jimp.read("lenna.png", (err, lenna) => {
  if (err) throw err;
  lenna
    .resize(256, 256) // resize
    .quality(60) // set JPEG quality
    .greyscale() // set greyscale
    .write("lena-small-bw.jpg"); // save
});
Enter fullscreen mode Exit fullscreen mode

Putting the Pieces Together

The most challenging parts of solving the problem have been handled by the previously mentioned libraries. Now, all that's left is to put them together to create the solution.

  • Gloob will scan the directory containing the images.
  • OpenCV will identify where faces exist in each image.
  • JIMP will apply blur to the regions where faces are found.

index.ts

(async () => {

    await argParser.parseArgs(process.argv);
    const rootDir = argParser.getArgument('dir');
    const files = await getImageFiles(rootDir || '');
    console.log(rootDir, files);
    await imageService.detectFaceInFiles(files);
    console.log('Done!');

})().catch(err => {
    console.error(err);
})
Enter fullscreen mode Exit fullscreen mode

image-service.ts

import * as cv from "opencv4nodejs";
import * as jimp from "jimp";

export type Rect = {
    x: number;
    y: number;
    width: number;
    height: number;
};

export default {

    readImage(path: string) {
        return cv.imreadAsync(path).then((img: any) => img.bgrToGrayAsync());
    },

    async hideFromImage(file: string, regions: Rect[]) {
        regions = regions.slice();
        let image = await jimp.read(file);

        for (let region of regions) {
            image = await image.pixelate(21, region.x, region.y, region.width, region.height);
        }

        return image;
    },

    async detectFaceInFiles(files: string[]) {
        const classifier = new cv.CascadeClassifier(cv.HAAR_FRONTALFACE_ALT2);
        const result = [];

        for (let file of files) {
            try {
                const grayImg = await this.readImage(file);
                const res = await classifier.detectMultiScaleAsync(grayImg);                
                result.push(res);
                console.log(res);
                const img = await this.hideFromImage(file, res.objects);
                await img.write(file);
            } catch (e) {
                console.error(e);
            }
        }

        return result;
    }

}
Enter fullscreen mode Exit fullscreen mode

**Note: The code above can be refactored to perform tasks in parallel, but this may require more computational resources.

The complete code can be accessed at: https://github.com/misabitencourt/face-blur.

Top comments (0)