Jako alternatywa dla ręcznego przekształcenia macierzy wejściowej, można użyć OpenCV reshape funkcji, aby osiągnąć podobny wynik z mniej kodu. Oto moja realizacja pracy redukcji kolorów liczyć metodą k-średnich (w Javie):
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 odczytuje obraz w 2 wymiarowej macierzy 3 kanałów. Pierwsze połączenie z reshape
- img.reshape(1, img.rows() * img.cols());
- zasadniczo rozwija 3 kanały w kolumny. W wynikowej macierzy jeden wiersz odpowiada jednemu pikselowi obrazu wejściowego, a 3 kolumny odpowiadają elementom RGB.
Po K-means algorytm zakończył swoją pracę, a odwzorowanie kolorów zostało zastosowane, nazywamy reshape
ponownie - imgMapped.reshape(3, img.rows())
, ale teraz toczenia kolumn z powrotem do kanałów, a zmniejszenie liczby wierszy z oryginalnym numerem obraz wiersza, a tym samym uzyskanie z powrotem oryginalny format matrycy, ale tylko ze zredukowanymi kolorami.
Chciałbym wiedzieć, co robisz w pętli przed deklaracją zmiennych clusterCount, a także co robisz na końcu w for po kmeans. Czy uważasz, że możliwe jest zaktualizowanie odpowiedzi za pomocą tych informacji? Dzięki! –
Pierwsza pętla zmienia kolejność danych z obrazu z macierzy (wiersze, cols, 3) na macierz (wiersze * cols, 3) (jeden wiersz na piksel). Pętla na końcu zastępuje każdy piksel na obrazie odpowiednim centrum klastra do wizualizacji. – sietschie
Czy jest możliwe użycie 'Mat :: reshape()' zamiast zagnieżdżonych dla pętli? – Jayesh