Skip to main content
Multiband blending is a sophisticated technique that blends images across multiple frequency bands, resulting in seamless transitions without visible seams. This example demonstrates how to blend two images (apple and orange) using the Stitcher library.

Overview

The multiband blending algorithm decomposes images into multiple frequency bands using Laplacian pyramids, blends each band separately, and reconstructs the final image. This approach produces superior results compared to simple alpha blending, especially at seam boundaries.

Complete Example

This example is based on the test_multiband() function from examples/stitch.c:9.
1
Load the images
2
First, load the two images you want to blend:
3
#include "blending.h"
#include "utils.h"

void test_multiband() {
    struct timespec start, end;
    double duration;

    Image img_buf1 = create_image("../files/apple.jpeg");
    Image img_buf2 = create_image("../files/orange.jpeg");
4
The create_image() function loads JPEG images and returns an Image structure containing the pixel data, width, height, and channel count.
5
Create masks for each image
6
Masks define which portions of each image contribute to the final blend:
7
    Image mask1 = create_image_mask(img_buf1.width, img_buf1.height, 0.1f, 0, 1);
    Image mask2 = create_image_mask(img_buf2.width, img_buf2.height, 0.1f, 1, 0);
8
The create_image_mask() parameters:
9
  • Width and height of the mask
  • 0.1f - Range parameter (10% of width for transition zone)
  • Last two parameters control gradient direction:
    • mask1: 0, 1 creates a left-to-right gradient (dark to bright)
    • mask2: 1, 0 creates a right-to-left gradient (bright to dark)
  • 10
    Calculate output dimensions
    11
    Determine the size of the blended output:
    12
        int out = (img_buf1.width * 0.1f);
        int out_width = (img_buf1.width * 2) - (out * 2);
        StitchRect out_size = {0, 0, out_width, img_buf1.height};
    
    13
    This calculation:
    14
  • Computes the overlap region (out = 10% of image width)
  • Subtracts the overlap from both sides to get final width
  • StitchRect structure: {x, y, width, height}
  • 15
    Configure the blender
    16
    Create a multiband blender with the specified number of frequency bands:
    17
        int num_bands = 5;
        
        clock_gettime(CLOCK_MONOTONIC, &start);
        Blender *b = create_blender(MULTIBAND, out_size, num_bands);
        clock_gettime(CLOCK_MONOTONIC, &end);
        duration = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
        printf("Elapsed time for creating blender: %.2f seconds\n", duration);
    
    18
    Parameters:
    19
  • MULTIBAND - Blender type (vs. FEATHER)
  • out_size - Output rectangle dimensions
  • num_bands - Number of frequency bands (typically 4-7 for best results)
  • 20
    Feed images to the blender
    21
    Add each image with its corresponding mask and position:
    22
        clock_gettime(CLOCK_MONOTONIC, &start);
        StitchPoint pt1 = {0, 0};
        feed(b, &img_buf1, &mask1, pt1);
        clock_gettime(CLOCK_MONOTONIC, &end);
        duration = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
        printf("Elapsed time for feed 1: %.2f seconds\n", duration);
    
        clock_gettime(CLOCK_MONOTONIC, &start);
        StitchPoint pt2 = {img_buf2.width - out * 2 - 100, 0};
        feed(b, &img_buf2, &mask2, pt2);
        clock_gettime(CLOCK_MONOTONIC, &end);
        duration = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
        printf("Elapsed time for feed 2: %.2f seconds\n", duration);
    
    23
    The feed() function:
    24
  • Takes the blender, image, mask, and top-left position
  • pt1 places the first image at origin (0, 0)
  • pt2 positions the second image with appropriate overlap
  • Each feed call builds the Laplacian pyramid for that image
  • 25
    Perform the blend
    26
    Execute the multiband blending algorithm:
    27
        clock_gettime(CLOCK_MONOTONIC, &start);
        blend(b);
        clock_gettime(CLOCK_MONOTONIC, &end);
        duration = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
        printf("Elapsed time for blend: %.2f seconds\n", duration);
    
    28
    The blend() function:
    29
  • Combines all Laplacian pyramids weighted by mask values
  • Reconstructs the final image from the blended pyramids
  • Stores the result in b->result
  • 30
    Save and cleanup
    31
    Save the blended result and free all allocated memory:
    32
        if (b->result.data != NULL) {
            if (save_image(&b->result, "merge.jpg")) {
                printf("Merged image saved\n");
            }
        }
    
        destroy_blender(b);
        destroy_image(&img_buf1);
        destroy_image(&img_buf2);
        destroy_image(&mask1);
        destroy_image(&mask2);
    }
    
    33
    Always destroy resources in reverse order of creation to prevent memory leaks.

    Expected Output

    When you run this example, you’ll see timing information:
    Elapsed time for creating blender: 0.01 seconds
    Elapsed time for feed 1: 0.15 seconds
    Elapsed time for feed 2: 0.14 seconds
    Elapsed time for blend: 0.23 seconds
    Merged image saved
    
    The output file merge.jpg will show a seamless blend of the two input images with no visible seam at the transition zone.

    Key Parameters

    • num_bands: Higher values (5-7) produce smoother blends but take longer to process
    • mask range: The 0.1f parameter controls the transition zone width (10% of image width)
    • positioning: Careful calculation of pt2 ensures proper overlap between images

    Performance Considerations

    • Multiband blending is more computationally intensive than feather blending
    • The algorithm uses parallel processing where available
    • Memory usage scales with the number of bands and image size
    • Typical processing time for 1920×1080 images: 0.3-0.5 seconds on modern hardware

    Build docs developers (and LLMs) love