Automate Brand Visibility Tracking With Amazon Rekognition

February 5, 2025

Creating an identity for a brand is an important part of any business strategy. You want your brand to be easily recognized by others. At Serverless Guru we have an awesome and good-looking brand identity. One key component of that brand identity is the “SG Mascot”, which is easily recognizable and is visually appealing. It has a unique style in its drawing and colors.

Illustration of a cloud-shaped character using a computer keyboard and mouse. The character is surrounded by abstract shapes, a floating lock connected to the cloud, and other colorful elements on a blue and white background.
Image of the “SG Mascot”. Taken from https://sls.guru

The purpose of this blog post is to showcase a “custom logo detector”, that is capable of analyzing photos uploaded by people, reviewing those images and detecting if the “SG Mascot” is present in the image or not.

Imagine hosting a global event where hundreds of attendees send pictures of the event through a web application. The system will identify the ones that match the “SG Mascot” and offer, for example, some sort of ticket to a raffle or something similar. While it can be done manually and review each image one by one, it wouldn’t be such a scalable process. And since we have access to so many amazing and easy-to-use AI tools, why not automate the process?

After a bit of research, I found Rekognition Custom Labels. Since I have used Amazon Rekognition a few times in the past, I’m more or less familiar with the interface. This API allows you to identify different custom objects based on your own specific needs. All you need is a dataset to train the custom labels you want and then do inference on the resulting model!

Model Training

Preparing the Dataset

First, to train a good model that can detect the mascot accurately, we need a good dataset of images. Since this is a classification model, it’s enough to know if the SG Mascot is detected in a picture or not. So we need images that contain the mascot but also images that don’t contain the mascot to teach the model what not to detect.

  • Positive Examples: Images with the mascot
  • Negative Examples: Images without the mascot

For the “Negative Examples”, I recurred to the COCO Dataset, which is a large, open dataset of images for machine-learning purposes. “COCO is a large-scale object detection, segmentation, and captioning dataset.

A grid of thumbnail images displayed on a screen, each with a file name underneath, showing various subjects like landscapes, animals, and people.
Sample images from the COCO dataset. Images taken from https://cocodataset.org

For the “Positive Examples”, I manually gathered some images that I found for the SG Mascot. With this approach, I could only gather 13 different images of the “SG Mascot”. Since this is not enough to build a good model, I recurred to augment the dataset by generating new images from the exiting images. I did so by doing the following

  • Rotating images
  • Adjusting brightness and contrast
  • Scaling the mascot to smaller or larger sizes

This will give a larger set of images for the “Positive” scenarios, resulting in a model that’s more robust and able to identify the SG mascot under different conditions.

After a bit of help from chatGPT, I executed the following script which was suggested by it:

const sharp = require('sharp');
const fs = require('fs');
const path = require('path');

const inputDir = './positive_images';
const outputDir = './augmented_images';

// Ensure output directory exists
if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
}

// Augmentation settings
const rotations = [15, 45, 90, 180]; // Degrees to rotate
const scales = [0.5, 0.8, 1.2, 1.5]; // Scale factors
const brightnessFactors = [0.5, 1.5]; // Brightness adjustments

// Augment a single image
async function augmentImage(filePath, fileName) {
    const img = sharp(filePath);

    // Apply rotations
    for (const angle of rotations) {
        const outputPath = path.join(outputDir, `rotated_${angle}_${fileName}`);
        await img.rotate(angle).toFile(outputPath);
        console.log(`Generated: ${outputPath}`);
    }

    // Apply scaling
    const metadata = await img.metadata();
    for (const scale of scales) {
        const width = Math.round(metadata.width * scale);
        const height = Math.round(metadata.height * scale);
        const outputPath = path.join(outputDir, `scaled_${scale}_${fileName}`);
        await img.resize(width, height).toFile(outputPath);
        console.log(`Generated: ${outputPath}`);
    }

    // Adjust brightness
    for (const factor of brightnessFactors) {
        const outputPath = path.join(outputDir, `brightness_${factor}_${fileName}`);
        await img.modulate({ brightness: factor }).toFile(outputPath);
        console.log(`Generated: ${outputPath}`);
    }
}

// Process all images in the input directory
async function processImages() {
    const files = fs.readdirSync(inputDir);
    for (const file of files) {
        const filePath = path.join(inputDir, file);
        const fileName = path.basename(file);
        console.log(`Processing: ${fileName}`);
        await augmentImage(filePath, fileName);
    }
}

processImages()
    .then(() => console.log('Dataset augmentation completed.'))
    .catch((err) => console.error('Error during augmentation:', err));
A grid of cartoon mascots, each displayed with varying brightness and rotations. The images are labeled with different filenames indicating adjustments like "brightness_0.5" and "brightness_1.5" alongside the word "mascot" and different numbers. The mascots are colorful and situated on blue backgrounds, some appear on white backgrounds with playful, abstract designs.
Results of executing the “augment images” script. Original Images taken from https://sls.guru

Now the “Positive” dataset contains 130 images - way better than the previous 13 images. With this plus 130 “Negative” images taken from the COCO dataset, it’s time to train the model!

Training the Model in Rekognition

First thing we need to do is upload the dataset images to an S3 bucket. We can create a new bucket and add two folders: “Positive” and “Negative”. After uploading the respective images to each folder in the bucket, we go into the Rekognition console, “Use Custom Labels” and create a project. Then, after generating the project, we create a dataset and select “Import images from S3 bucket”. Also we need to make sure the “Automatically assign image-level labels to images” is checked. This will automate the labeling.

A grid of six images with text labels. Top three images: a group of people on a baseball field, a kitchen interior, and a man looking at a game console screen. Bottom three images: cartoon cloud mascots with a parachute, reading books, and blowing bubbles. Each image has a label marked "Negative" or "Positive.”
Dataset of images created and uploaded to the Rekognition Custom Labels. Original SG Mascot Images taken from https://sls.guru

Notice that the images were automatically labeled based on the folder name that we specified in the S3 bucket. That’s great as doing this process manually it’s quite tedious and time-consuming!

After having the dataset labeled, the project it’s ready to train the model! all we need to do is click on “Train model” and let it train for some time. In my case, it took approximately 45 minutes.

After the training is done, we need to “start” the model. To do this, in the console, we go to the “Use model” tab in the results of the training, then click on “Start”. And that’s it! We’re ready to start using the model to detect the SG mascot!

Using the Model

Architecture

For our use case, we can design a simple service that leverages Event-Driven architecture and Serverless services to use the model we just trained. For this, the process starts with a user uploading a picture to an S3 bucket (it can be through a web application). The S3 bucket triggers a Lambda function whenever an image gets uploaded. The Lambda function can then call the Amazon Rekognition “Detect Custom Labels” using the model we just trained, then store the results in a database like a DynamoDb Table:

Diagram illustrating a process flow for image recognition. A user takes a photo of a mascot and uploads it to an "Images Bucket." This triggers a "Recognize Image Lambda" function, which makes an API call to "Rekognition" to detect custom labels. The results are stored in an "Analysis Results Table.”
Image of the backend architecture for detecting the SG Mascot in images. Own Creation

For implementing this architecture we can leverage the AWS CDK, which allows us to define these resources as typescript code. Check out the full code in my GitHub Repository.

Testing

Since the project is created with the AWS CDK, we can easily create and connect these resources in the cloud using the commands “cdk bootstrap“ and “cdk deploy“.

After deploying the resources, we can upload images to the bucket manually and check the results. It seems it’s working as expected:

A JSON response containing metadata and custom labels. The metadata includes an HTTP status code of 200 and a request ID. Under "CustomLabels," there's a label named "Positive" with a confidence value of 98.09.
Cloudwatch logs for a “Positive” and a “Negative” image. Own creation
JSON output with metadata indicating an HTTP status code of 200, a request ID, and one custom label named "Negative" with a confidence score of 98.27.
Cloudwatch logs for a “Positive” and a “Negative” image. Own creation

Cost

If you’re following this blog post, it’s important to note the cost of the Amazon Rekognition for detecting custom labels. It’s amazingly easy and simple to use, however the cost it’s significant even for a short POC like the one presented in this blog post.

For this blog post POC, I tested the model for a little while. Once the model is turned-on (hitting that “Start” button on the project), it starts to charge per minute, so even using it for only a small amount of time the bill resulted in $8.91 USD.

A screenshot of Amazon Web Services billing details for Rekognition in the US East (N. Virginia) region, totaling USD 8.91. It includes USD 8.74 for inference minutes and USD 0.17 for training minutes, with specific rates per minute displayed for each.
Snippet of the billing for Rekognition in the AWS Console for the creation of the POC presented in this blog post. My own creation.

So if you’re using it to follow this tutorial, make sure to STOP THE MODEL by hitting the “Stop” button after you’re done to avoid extra unnecessary charges.

Conclusion

Automating the detection of a brand’s unique identity, like the “SG Mascot”, is a great example of how AI and machine learning can simplify and speed-up what can be a very tedious and manual process. Using Amazon Rekognition “Custom Labels”, this blog post covered the creation of a POC that analyses imaged uploaded by users and detects if the unique brand’s identity is found in the image, in this case, the “SG Mascot”.

By leveraging the use of scalable and serverless services like Lambda, S3, dynamodb, we can build an cost-effective solution that integrates the components in a seamless way using the AWS CDK. While the “Custom Labels” cost can add-up with time, it’s an excellent tool for prototyping and for production systems.

References

Serverless Handbook
Access free book

The dream team

At Serverless Guru, we're a collective of proactive solution finders. We prioritize genuineness, forward-thinking vision, and above all, we commit to diligently serving our members each and every day.

See open positions

Looking for skilled architects & developers?

Join businesses around the globe that trust our services. Let's start your serverless journey. Get in touch today!
Ryan Jones
Founder
Book a meeting
arrow
Founder
Eduardo Marcos
Chief Technology Officer
Chief Technology Officer
Book a meeting
arrow

Join the Community

Gather, share, and learn about AWS and serverless with enthusiasts worldwide in our open and free community.