web-dev-qa-db-fra.com

Quantification rapide des couleurs dans OpenCV

Comment puis-je réduire le nombre de couleurs distinctes dans les images en utilisant OpenCV (+ C++) de la manière la plus rapide possible? Je ne veux pas le code complet. Je le fais déjà en utilisant kmeans mais ce n'est pas très rapide. C'est la partie de mon code qui est lente:

kmeans(samples, clusterCount, labels,
    TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 10.0),
    1, KMEANS_RANDOM_CENTERS, centers);

Ce code prend quelques secondes à traiter, ce qui est très très lent pour moi. J'utilisais Matlab pour cela (rgb2ind) Qui était rapide. Presque 0,01 seconde.

Je veux utiliser mon code pour la production où les utilisateurs s'attendent à ce que le programme soit rapide.

Existe-t-il une alternative aux kmeans pour la quantification des couleurs? Existe-t-il un moyen d'exécuter kmeans plus rapidement (ce que je ne pense pas car j'ai essayé de nombreux paramètres différents)?

Modifier:
Il s'est avéré que la quantification des couleurs est un sujet très complexe et prend du temps pour en écrire un bien optimisé. J'ai décidé d'utiliser Magick++ (ImageMagick API) pour cela.
Pour cette raison, je n'ai pas essayé la nouvelle réponse (éditée) de Cris Luengo. Mais je le marque comme réponse (consultez également les commentaires) afin que les autres ne pensent pas que cette question ne trouve pas de réponse.

12
J. Mando

Il existe de nombreuses façons de quantifier les couleurs. Ici, j'en décris quatre.

Quantification uniforme

Ici, nous utilisons une carte de couleurs avec des couleurs uniformément distribuées, qu'elles existent ou non dans l'image. Dans MATLAB-speak, vous écririez

qimg = round(img*(N/255))*(255/N);

pour quantifier chaque canal en niveaux N (en supposant que l'entrée est dans la plage [0,255]. Vous pouvez également utiliser floor, ce qui est plus approprié dans certains cas. Cela conduit à N^3 Couleurs différentes. Par exemple avec N=8 vous obtenez 512 couleurs RVB uniques.

Clustering K-means

Il s'agit de la méthode "classique" pour générer une palette adaptative. De toute évidence, ce sera le plus cher. L'OP applique k-means sur la collection de tous les pixels. Au lieu de cela, k-means peut être appliqué à l'histogramme des couleurs. Le processus est identique, mais au lieu de 10 millions de points de données (une image typique de nos jours), vous n'en avez peut-être que 32 ^ 3 = 33 mille. La quantification causée par l'histogramme avec un nombre réduit de casiers a peu d'effet ici lorsqu'il s'agit de photographies naturelles. Si vous quantifiez un graphique, qui a un ensemble limité de couleurs, vous n'avez pas besoin de faire un clustering k-means.

Vous faites un seul passage à travers tous les pixels pour créer l'histogramme. Ensuite, vous exécutez le clustering k-means normal, mais en utilisant les cases d'histogramme. Désormais, chaque point de données a également un poids (le nombre de pixels dans ce bac) que vous devez prendre en compte. L'étape de l'algorithme qui détermine les centres de cluster est affectée. Vous devez calculer la moyenne pondérée des points de données, au lieu de la moyenne régulière.

Le résultat est affecté par l'initialisation.

Quantification d'octree

Un octree est une structure de données pour l'indexation spatiale, où le volume est récursivement divisé en 8 sous-volumes en coupant chaque axe en deux. L'arbre est ainsi formé de nœuds de 8 enfants chacun. Pour la quantification des couleurs, le cube RVB est représenté par un octree, et le nombre de pixels par nœud est compté (cela équivaut à construire un histogramme de couleur et à construire un octree en plus de cela). Ensuite, les nœuds foliaires sont supprimés jusqu'à ce qu'il en reste le nombre souhaité. La suppression des nœuds foliaires se produit 8 à la fois, de sorte qu'un nœud d'un niveau supérieur devient une feuille. Il existe différentes stratégies pour choisir les nœuds à élaguer, mais ils tournent généralement autour des nœuds d'élagage avec un faible nombre de pixels.

C'est la méthode utilisée par Gimp.

Parce que l'octree divise toujours les nœuds au milieu, il n'est pas aussi flexible que le clustering k-means ou la méthode suivante.

Quantification de la variance minimale

MATLAB's rgb2ind , que l'OP mentionne, effectue une quantification uniforme et ce qu'ils appellent la "quantification de la variance minimale":

La quantification de la variance minimale coupe le cube de couleur RVB en boîtes plus petites (pas nécessairement des cubes) de différentes tailles, selon la façon dont les couleurs sont réparties dans l'image.

Je ne sais pas ce que cela signifie. Cette page ne donne rien de plus, mais elle a une figure qui ressemble à une partition d'arbre k-d du cube RVB. Les arbres K-d sont des structures d'indexation spatiale qui divisent les données spatiales en deux de manière récursive. À chaque niveau, vous choisissez la dimension là où il y a le plus de séparation, et vous vous divisez le long de cette dimension, conduisant à un nœud feuille supplémentaire. Contrairement aux octrees, le fractionnement peut se produire à un emplacement optimal, il n'est pas au milieu du nœud.

L'avantage d'utiliser une structure d'indexation spatiale (soit des arbres k-d ou des octrees) est que la recherche de couleur est vraiment rapide. Vous commencez à la racine et prenez une décision binaire basée sur la valeur R, G ou B jusqu'à ce que vous atteigniez un nœud feuille. Il n'est pas nécessaire de calculer les distances à chaque cluster prototype, comme c'est le cas pour les k-moyennes.

[Modifier deux semaines plus tard] J'ai pensé à une implémentation possible, et en ai proposé une . Voici l'algorithme:

  • L'histogramme en couleur est considéré comme une partition. Ce sera la racine d'un arbre k-d, qui est actuellement le nœud feuille car il n'y a pas encore d'autres nœuds.
  • Une file d'attente prioritaire est créée. Il contient tous les nœuds foliaires de l'arbre k-d. La priorité est donnée par la variance de la partition le long d'un axe, moins les variances des deux moitiés si nous devions diviser la partition le long de cet axe. L'emplacement divisé est choisi de telle sorte que les variances des deux moitiés sont minimes (en utilisant l'algorithme d'Otsu). C'est-à-dire que plus la priorité est grande, plus la variance totale que nous réduisons en effectuant la division est grande. Pour chaque nœud feuille, nous calculons cette valeur pour chaque axe et utilisons le résultat le plus grand.
  • Nous traitons les partitions dans la file d'attente jusqu'à ce que nous ayons le nombre de partitions souhaité:
    • Nous avons divisé la partition avec la priorité la plus élevée le long de l'axe et à l'emplacement calculé lors de la détermination de la priorité.
    • Nous calculons la priorité pour chacune des deux moitiés et les mettons dans la file d'attente.

Ceci est un algorithme relativement simple lorsqu'il est décrit de cette façon, le code est un peu plus complexe, car j'ai essayé de le rendre efficace mais générique.

Comparaison

Sur un histogramme RVB 256x256x256 j'ai obtenu ces timings comparant le clustering k-means et ce nouvel algorithme:

# clusters    kmeans (s)    minvar (s)
     5          3.98         0.34
    20         17.9          0.48
    50        220.8          0.59

Notez que k-means a besoin de plus d'itérations à mesure que le nombre de clusters augmente, d'où l'augmentation exponentielle du temps. Normalement, on n'utilisait pas un si gros histogramme, je voulais avoir des données volumineuses pour rendre les timings plus robustes.

Voici un exemple de ces trois méthodes appliquées à une image de test:

Contribution:

Input

Uniforme avec N=4 conduisant à 64 couleurs différentes [avec N=2 pour obtenir 8 couleurs différentes et comparables aux autres méthodes, le résultat est très moche]:

Uniform

K-signifie avec 8 couleurs:

K-means

Nouvelle "variance minimale" avec 8 couleurs:

New "minimum variance"

J'aime ce dernier résultat mieux que le résultat K-means, bien qu'ils soient assez similaires.

17
Cris Luengo

Algorithme basé sur le voisin le plus proche par paire rapide avec 8 couleurs
Haute qualité et rapide
enter image description here

Efficace, sensible aux bords, quantification et tramage des couleurs combinées avec 8 couleurs
Qualité supérieure pour 32 couleurs ou moins mais plus lent
enter image description here

Quantification spatiale des couleurs avec 8 couleurs
Qualité supérieure pour 32 couleurs ou moins mais la plus lente
enter image description here

Exemple de code c ++
Pour la vitesse, cela peut dépendre de programmation parallèle GPU C/C++ .

5
Miller Cy Chan