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.
Il existe de nombreuses façons de quantifier les couleurs. Ici, j'en décris quatre.
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.
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.
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.
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:
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.
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:
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]:
K-signifie avec 8 couleurs:
Nouvelle "variance minimale" avec 8 couleurs:
J'aime ce dernier résultat mieux que le résultat K-means, bien qu'ils soient assez similaires.
Algorithme basé sur le voisin le plus proche par paire rapide avec 8 couleurs
Haute qualité et rapide
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
Quantification spatiale des couleurs avec 8 couleurs
Qualité supérieure pour 32 couleurs ou moins mais la plus lente
Exemple de code c ++
Pour la vitesse, cela peut dépendre de programmation parallèle GPU C/C++ .