---
name: "libpuzzle"
section: "3"
platform: "linux"
package: "libpuzzle-dev"
version: "0.11-3+b2"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/libpuzzle"
---

# libpuzzle(3)

compute comparable signatures of bitmap images

## NAME

puzzle\_init\_cvec, puzzle\_init\_dvec, puzzle\_fill\_dvec\_from\_file, puzzle\_fill\_cvec\_from\_file, puzzle\_fill\_cvec\_from\_dvec, puzzle\_free\_cvec, puzzle\_free\_dvec, puzzle\_init\_compressed\_cvec, puzzle\_free\_compressed\_cvec, puzzle\_compress\_cvec, puzzle\_uncompress\_cvec, puzzle\_vector\_normalized\_distance - compute comparable signatures of bitmap images

## SYNOPSIS

\#include \<puzzle.h\>

int puzzle\_init\_context(PuzzleContext \**context*);

int puzzle\_free\_context(PuzzleContext \**context*);

int puzzle\_init\_cvec(PuzzleContext \**context*, PuzzleCvec \**cvec*);

int  puzzle\_init\_dvec(PuzzleContext \**context*, PuzzleDvec \**cvec*);

void puzzle\_fill\_dvec\_from\_file(PuzzleContext \**context*, PuzzleDvec \**dvec*, const char \**file*);

void puzzle\_fill\_cvec\_from\_file(PuzzleContext \**context*, PuzzleCvec \**cvec*, const char \**file*);

void puzzle\_fill\_cvec\_from\_dvec(PuzzleContext \**context*, PuzzleCvec \**cvec*, const PuzzleDvec \**dvec*);

void puzzle\_free\_cvec(PuzzleContext \**context*, PuzzleCvec \**cvec*);

void puzzle\_free\_dvec(PuzzleContext \**context*, PuzzleDvec \**cvec*);

void puzzle\_init\_compressed\_cvec(PuzzleContext \**context*, PuzzleCompressedCvec \**compressed\_cvec*);

void puzzle\_free\_compressed\_cvec(PuzzleContext \**context*, PuzzleCompressedCvec \**compressed\_cvec*);

int puzzle\_compress\_cvec(PuzzleContext \**context*, PuzzleCompressedCvec \**compressed\_cvec*, const PuzzleCvec \**cvec*);

int puzzle\_uncompress\_cvec(PuzzleContext \**context*, PuzzleCompressedCvec \**compressed\_cvec*, PuzzleCvec \**const cvec*);

double puzzle\_vector\_normalized\_distance(PuzzleContext \**context*, const PuzzleCvec \**cvec1*, const PuzzleCvec \**cvec2*, const int *fix\_for\_texts*);

## DESCRIPTION

The Puzzle library computes a signature out of a bitmap picture. Signatures are comparable and similar pictures have similar signatures.

After a picture has been loaded and uncompressed, featureless parts of the image are skipped (autocrop), unless that step has been explicitly disabled, see [**puzzle\_set**(3)](/puzzle_set/3.md)

## LIBPUZZLE CONTEXT

Every public function requires a *PuzzleContext* object, that stores every required tunables.

Any application using libpuzzle should initialize a *PuzzleContext* object with **puzzle\_init\_context()** and free it after use with **puzzle\_free\_context()**

```
  PuzzleContext context;
  puzzle_init_context(&context);
  [...]
  puzzle_free_context(&context);
```

## DVEC AND CVEC VECTORS

The next step is to divide the cropped image into a grid and to compute the average intensity of soft-edged pixels in every block. The result is a *PuzzleDvec* object.

*PuzzleDvec* objects should be initialized before use, with **puzzle\_init\_dvec()** and freed after use with **puzzle\_free\_dvec()**.

The *PuzzleDvec* structure has two important fields: *vec* is the pointer to the first element of the array containing the average intensities, and *sizeof\_compressed\_vec* is the number of elements.

*PuzzleDvec* objects are not comparable, so what you usually want is to transform these objects into *PuzzleCvec* objects.

A *PuzzleCvec* object is a vector with relationships between adjacent blocks from a *PuzzleDvec* object.

The **puzzle\_fill\_cvec\_from\_dvec()** fills a *PuzzleCvec* object from a *PuzzleDvec* object.

But just like the other structure, *PuzzleCvec* objects must be initialized and freed with **puzzle\_init\_cvec()** and **puzzle\_free\_cvec()**.

*PuzzleCvec* objects have a vector whoose first element is in the *vec* field, and the number of elements is in the *sizeof\_vec* field.

## LOADING PICTURES

*PuzzleDvec* and *PuzzleCvec* objects can be computed from a bitmap picture file, with **puzzle\_fill\_dvec\_from\_file()** and **puzzle\_fill\_cvec\_from\_file()**.

*GIF*, *PNG* and *JPEG* files formats are currently supported and automatically recognized.

Here's a simple example that creates a *PuzzleCvec* objects out of a file.

```
  PuzzleContext context;
  PuzzleCvec cvec;
  puzzle_init_context(&context);
  puzzle_init_cvec(&context, &cvec);
  puzzle_fill_cvec_from_file(&context, &cvec, "test-picture.jpg");
  [...]
  puzzle_free_cvec(&context, &cvec);
  puzzle_free_context(&context);
```

## COMPARING VECTORS

In order to check whether two pictures are similar, you need to compare their *PuzzleCvec* signatures, using **puzzle\_vector\_normalized\_distance()**.

That function returns a distance, between 0.0 and 1.0. The lesser, the nearer.

Tests on common pictures show that a normalized distance of 0.6 (also defined as *PUZZLE\_CVEC\_SIMILARITY\_THRESHOLD*) means that both pictures are visually similar.

If that threshold is not right for your set of pictures, you can experiment with *PUZZLE\_CVEC\_SIMILARITY\_HIGH\_THRESHOLD*, *PUZZLE\_CVEC\_SIMILARITY\_LOW\_THRESHOLD* and *PUZZLE\_CVEC\_SIMILARITY\_LOWER\_THRESHOLD* or with your own value.

If the *fix\_for\_texts* of **puzzle\_vector\_normalized\_distance()** is 1, a fix is applied to the computation in order to deal with bitmap pictures that contain text. That fix is recommended, as it allows using the same threshold for that kind of picture as for generic pictures.

If *fix\_for\_texts* is *0*, that special way of computing the normalized distance is disabled.

```
  PuzzleContext context;
  PuzzleCvec cvec1, cvec2;
  double d;
  puzzle_init_context(&context);
  puzzle_init_cvec(&context, &cvec1);
  puzzle_init_cvec(&context, &cvec2);
  puzzle_fill_cvec_from_file(&context, &cvec1, "test-picture-1.jpg");
  puzzle_fill_cvec_from_file(&context, &cvec2, "test-picture-2.jpg");
  d = puzzle_vector_normalized_distance(&context, &cvec1, &cvec2, 1);
  if (d < PUZZLE_CVEC_SIMILARITY_THRESHOLD) {
    puts("Pictures are similar");
  }
  puzzle_free_cvec(&context, &cvec2);
  puzzle_free_cvec(&context, &cvec1);
  puzzle_free_context(&context);
```

## CVEC COMPRESSION

In order to reduce storage needs, *PuzzleCvec* objects can be compressed to 1/3 of their original size.

*PuzzleCompressedCvec* structures hold the compressed data. Before and after use, these structures have to be passed to **puzzle\_init\_compressed\_cvec()** and **puzzle\_free\_compressed\_cvec()**.

**puzzle\_compress\_cvec()** compresses a *PuzzleCvec* object into a *PuzzleCompressedCvec* object.

And **puzzle\_uncompress\_cvec()** uncompresses a *PuzzleCompressedCvec* object into a *PuzzleCvec* object.

```
  PuzzleContext context;
  PuzzleCvec cvec;
  PuzzleCompressedCvec c_cvec;
  [...]
  puzzle_init_compressed_cvec(&context, &c_cvec);
  puzzle_compress_cvec(&context, &c_cvec, &cvec);
  [...]
  puzzle_free_compressed_cvec(&context, &c_cvec);
```

The *PuzzleCompressedCvec* structure has two important fields: *vec* that is a pointer to the first element of the compressed data, and *sizeof\_compressed\_vec* that contains the number of elements.

## RETURN VALUE

Functions return *0* on success, and *-1* if something went wrong.

## AUTHORS

Frank DENIS libpuzzle at pureftpd dot org

## ACKNOWLEDGMENTS

Xerox Research Center H. CHI WONG Marschall BERN David GOLDBERG Sameh SCHAFIK

## SEE ALSO

[**puzzle\_set**(3)](/puzzle_set/3.md), **puzzle-diff**(8)
