NodeJS: Blurring Human Faces in Photos
Tags: node, typescript, ai, image
Published: 2023-10-26 21:26:08

---
title: NodeJS: Blurring Human Faces in Photos
published: true
description: Create a NodeJS utility to Blur Human Faces in Photos.
tags: NodeJS, Typescript, ai, image
# cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jb2wbje3wqmo02mzztr4.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-10-26 21:21 +0000
---

![Face Blur](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jb2wbje3wqmo02mzztr4.png)

**This article was automatically translated from Portuguese by ChatGPT, the original article could be found [here](https://dev.to/justaguyfrombr/nodejs-ofuscando-rostos-humanos-em-fotos-2ip).

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](https://www.npmjs.com/package/glob)  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:

```javascript
const filesStream = await glob('**/*.dat')
```

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

### OpenCV4NodeJs
The [OpenCV4NodeJs](https://www.npmjs.com/package/opencv4nodejs) A.I. library provides an interface for calling [OpenCV](https://opencv.org/) routines in NodeJS.

![Face recognition](https://github.com/misabitencourt/face-blur/blob/master/docs/opencv.jpg?raw=true)

### JIMP
The last library is used for image manipulation in JavaScript in NodeJS. [JIMP](https://www.npmjs.com/package/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:

```javascript
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
});
```

## 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
```typescript
(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);
})
```
 
image-service.ts
```typescript
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;
    }

}
```

**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.