Disons que je l'image suivante:Déterminer la couleur la plus fréquente dans une image (OpenCV & C++)
Ce que je cherche est un moyen de déterminer programatically que le rouge est le plus couleur commune dans l'image. Jusqu'ici, j'ai essayé quelques approches, avec divers résultats de pauvres à abysmaux pour accomplir ceci. Mon approche actuelle consiste à réduire d'abord les couleurs de l'image.
Cela se fait avec le code suivant:
Mat samples(src.rows * src.cols, 3, CV_32F);
for(int y = 0; y < src.rows; y++)
for(int x = 0; x < src.cols; x++)
for(int z = 0; z < 3; z++)
samples.at<float>(y + x * src.rows, z) = src.at<Vec3b>(y,x)[z];
int clusterCount = 16;
Mat labels;
int attempts = 2;
Mat centers;
kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers);
Mat reduced(src.size(), src.type());
for(int y = 0; y < src.rows; y++)
for(int x = 0; x < src.cols; x++)
{
int cluster_idx = labels.at<int>(y + x * src.rows,0);
reduced.at<Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
reduced.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
reduced.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
}
Il y a un problème ennuyeux avec elle où il a un problème avec mise à l'échelle qui laisse une partie du droit, mais je peux vivre avec ça pour le moment.
Ensuite, j'ai essayé quelques approches où je veux obtenir les couleurs mappées, comme avec les histogrammes.
Mat image_hsv;
cvtColor(src, image_hsv, CV_BGR2HSV);
// Quanta Ratio
int scale = 10;
int hbins = 36, sbins = 25, vbins = 25;
int histSize[] = {hbins, sbins, vbins};
float hranges[] = { 0, 360 };
float sranges[] = { 0, 256 };
float vranges[] = { 0, 256 };
const float* ranges[] = { hranges, sranges, vranges };
MatND hist;
int channels[] = {0, 1, 2};
calcHist(&image_hsv, 1, channels, Mat(), // do not use mask
hist, 3, histSize, ranges,
true, // the histogram is uniform
false);
int maxVal = 0;
int hue = 0;
int saturation = 0;
int value = 0;
for(int h = 0; h < hbins; h++)
for(int s = 0; s < sbins; s++)
for(int v = 0; v < vbins; v++)
{
int binVal = hist.at<int>(h, s, v);
if(binVal > maxVal)
{
maxVal = binVal;
hue = h;
saturation = s;
value = v;
}
}
hue = hue * scale * scale; // angle 0 - 360
saturation = saturation * scale; // 0 - 255
value = value * scale; // 0 - 255
Le problème est, pour cette image que je reçois les valeurs suivantes:
- Hue: 240
- Saturation: 0
- Valeur: 0
Cependant, je J'attends des valeurs HSV plus proches de ceci:
- Hue: 356
- Saturation: 94
- Valeur: 58
Espérons que quelqu'un peut signaler où je suis allé mal.
trop paresseux pour analyser votre code mais juste un indice pour tester est-ce que vous gérez correctement votre format de pixel d'image? Mon pari est que vous avez RVB et le gérer comme BGR ou vice versa quelque part comme la teinte 240 est bleue au lieu de rouge (je suis habitué à ce GDI/Canvas a généralement l'ordre inverse des canaux que les données d'image brutes pour certains formats de pixels). , V mis à zéro est en effet étrange. Jetez également un coup d'oeil à ceci: [histogramme HSV] (https://stackoverflow.com/a/29286584/2521214) – Spektre
Juste curieux, que diriez-vous de calculer l'histogramme de couleur en utilisant [calcHist] (https://docs.opencv.org /2.4/modules/imgproc/doc/histograms.html#calchist) et trouver le pic? Bien sûr, pas la réponse à votre question avec les valeurs HSV. calcHist sera beaucoup plus rapide que kmeans. – dhanushka
@dhanushka la vitesse dépend de l'implémentation de l'histogramme des couleurs, du nombre de bins etc ... donc il ne peut pas être nécessairement plus rapide que k-means avec la même précision. Mais oui j'utiliserais aussi l'histogramme, c'est pourquoi je suggère le lien dans le commentaire précédent car il y a mon implémentation C++ qui fait la conversion RGB -> HSV, calculer et rendre l'histogramme HSV (pas openCV) – Spektre