In alternativa al rimodellare la matrice di ingresso manualmente, è possibile utilizzare la funzione OpenCV reshape realizzare risultato simile con meno codice. Qui è la mia implementazione di lavoro di ridurre il numero di colori con il metodo K-Means (in Java):
private final static int MAX_ITER = 10;
private final static int CLUSTERS = 16;
public static Mat colorMapKMeans(Mat img, int K, int maxIterations) {
Mat m = img.reshape(1, img.rows() * img.cols());
m.convertTo(m, CvType.CV_32F);
Mat bestLabels = new Mat(m.rows(), 1, CvType.CV_8U);
Mat centroids = new Mat(K, 1, CvType.CV_32F);
Core.kmeans(m, K, bestLabels,
new TermCriteria(TermCriteria.COUNT | TermCriteria.EPS, maxIterations, 1E-5),
1, Core.KMEANS_RANDOM_CENTERS, centroids);
List<Integer> idx = new ArrayList<>(m.rows());
Converters.Mat_to_vector_int(bestLabels, idx);
Mat imgMapped = new Mat(m.size(), m.type());
for(int i = 0; i < idx.size(); i++) {
Mat row = imgMapped.row(i);
centroids.row(idx.get(i)).copyTo(row);
}
return imgMapped.reshape(3, img.rows());
}
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Highgui.imwrite("result.png",
colorMapKMeans(Highgui.imread(args[0], Highgui.CV_LOAD_IMAGE_COLOR),
CLUSTERS, MAX_ITER));
}
OpenCV legge immagine in 2 bidimensionale a matrice, 3 canali. Prima chiamata a reshape
- img.reshape(1, img.rows() * img.cols());
- essenzialmente srotola 3 canali in colonne. Nella matrice risultante una riga corrisponde a un pixel dell'immagine di input e 3 colonne corrisponde a componenti RGB.
Dopo che l'algoritmo K-Means ha terminato il suo lavoro e la mappatura dei colori è stata applicata, chiamiamo nuovamente reshape
- imgMapped.reshape(3, img.rows())
, ma ora riportiamo le colonne ai canali e riduciamo i numeri di riga al numero di riga dell'immagine originale, tornando indietro formato matrice originale, ma solo con colori ridotti.
Mi piacerebbe sapere cosa si sta facendo nel ciclo prima della dichiarazione della variabile clusterCount e anche cosa si sta facendo alla fine nel dopo per i kmea. Pensi che sia possibile aggiornare la risposta con queste informazioni? Grazie! –
Il primo ciclo riordina i dati dall'immagine da una matrice (righe, colonne, 3) a una matrice (righe * colonne, 3) (una riga per pixel). Il loop all'estremità sostituisce ogni pixel dell'immagine con il centro del cluster corrispondente per la visualizzazione. – sietschie
È possibile utilizzare 'Mat :: reshape()' invece di cicli nidificati? – Jayesh