Código de ejemplo de OpenCV + Java KNN ( algoritmo vecino más cercano KNearest-K )
Este artículo ofrece un ejemplo del algoritmo vecino más cercano de aprendizaje automático OpenCV K implementado en el lenguaje Java .
Versión de OpenCV : 3.4.0 . No hay tutoriales ni ejemplos sobre el lenguaje Java ML en los documentos oficiales . Solo hay ejemplos de código de C++ y Python . Encontré un ejemplo en Internet, pasé la prueba real y adjunté notas en chino.
Dirección original: https://stackoverflow.com/questions/32612058/java-opencv-find-k-nearest-neighbor-c-to-java-conversion
Código de muestra:
importar java.texto.DecimalFormat; importar java.util.*;
importar org.opencv.core.*; importar org.opencv.imgcodecs.Imgcodecs; importar org.opencv.ml.KNearest; importar org.opencv.ml.Ml; importar org.opencv.utils.Converters;
clase pública Principal { public static void main(String[] args ) { // TODO stub de método generado automáticamente // carga la biblioteca nativa de OpenCV Sistema. loadLibrary (Core. NATIVE_LIBRARY_NAME );
// La ruta del conjunto de datos de prueba después de descomprimir el paquete de instalación de OpenCV: samples/data/digits.png // Utilice el conjunto de datos de imágenes digitales adjunto al paquete de instalación de OpenCV . El conjunto de datos tiene un total de 5000 muestras / muestras digitales del 0 al 9 , y la resolución de la imagen es de 2000x1000 . // El tamaño de cada muestra digital es 20x20 , por lo que hay 2000/20=100 muestras digitales en cada línea, cada número del 0 al 9 ocupa 5 líneas a su vez, y 10 números tienen un total de 50 líneas. // Preste atención a la ruta de la imagen, puede usar una ruta absoluta Mat dígitos = Imgcodecs. imread ( "E:\\...\\imagenes\\digitos.png" , 0);
// configurar tren/datos de prueba: Mat trainData = new Mat(); Mat testData = new Mat(); List<Integer> trainLabs = new ArrayList<Integer>(); List<Integer> testLabs = new ArrayList<Integer>();
// 10 digits a 5 rows: // 一次行读入所有数据,训练数据和测试数据各一半 // 数据集共 50 行 for (int r=0; r<50; r++) { // 100 digits per row: // 每行 100 个数字样例 for (int c=0; c<100; c++) { // crop out 1 digit: // 每次读入一个数字样本,大小:20x20 Mat num = digits.submat(new Rect(c*20,r*20,20,20)); // we need float data for knn: // knn算法的输入为浮点型,在此转换 num.convertTo(num, CvType.CV_32F); // 50/50 train/test split: if (c % 2 == 0) { // 偶数行作为训练样本 // for opencv ml, each feature has to be a single row: // OpenCV中的ml算法要求输入训练数据的每一个样本(此例中可理解为样本特征:feature)占据一行 // num 本身为 20x20 的矩阵,转换为 1 行 n列的矩阵,其中 n=20x20=400 trainData.push_back(num.reshape(1,1)); // add a label for that feature (the digit number): // 对应每个训练样本建立对应的Label(正确答案) trainLabs.add(r/5); } else { // 奇数行作为测试数据 testData.push_back(num.reshape(1,1)); testLabs.add(r/5); } } }
// make a Mat of the train labels, and train knn: // 构建 KNearest 对象,3.0版本之前似乎可以直接 new 一个 KNearest knn = KNearest.create(); // train函数原型定义为:public boolean train(Mat samples, int layout, Mat responses) // 其中第一个参数自不必说,是输入的训练数据,其中每一行代表一个样本(特征);第二个参数是指定样本的布局,是每行一个样本, // 还是每列一个样本,没有默认值;第三个参数为训练样本对应的正确答案(label) // 扩展:Converters类中有OpenCV提供的许多数据(类型)转换工具,非常实用 knn.train(trainData, Ml.ROW_SAMPLE, Converters.vector_int_to_Mat(trainLabs));
// 使用测试数据集进行测试 // 测试数据也是每行一个样本 // now test predictions: int err = 0; for (int i=0; i<testData.rows(); i++) { // 读取一行(一个测试样本) Mat one_feature = testData.row(i); // 预期的(标准/正确)答案 int testLabel = testLabs.get(i);
Mat res = new Mat(); // 查找匹配:第一个参数为输入样本(可一次输入多个样本),第二个参数为需要返回的K个邻近(即KNearest的那个K),第三个参数为返回 // 结果(res: result),结果为样本对应的Label值,每一个样本的匹配结果对应一行。 // 如果输入仅有一个样本,则返回结果(p)就是预测结果。参数 1即为K-近邻算法的关键参数 K! float p = knn.findNearest(one_feature, 1, res); System.out.println(testLabel + " " + p + " " + res.dump());
// 统计识别误差 int iRes = (int) p; if(iRes != testLabel) { err++; } }
// 输出(屏幕提示)识别精度 float accuracy = (float) ((2500 - (float)err) / 2500.0); DecimalFormat df = new DecimalFormat("0.0000"); System.out.println("error count: " + err + ", accuracy is: " + df.format(accuracy));
// 以下为源作者一些说明,大意是如果在实际应用中需要借助OpenCV自带的数字样本集训练的模型识别数字,需要做的一些工作 // 在此不作具体解释,有疑问的可以留言 hmm, the 'real world' test case probably looks more like this: make sure, you follow the very same pre-processing steps used in the train phase: // Mat one_feature = Imgcodecs.imread("one_digit.png", 0); // Mat feature; // one_feature.convertTo(feature, CvTypes.CV_32F); // Imgproc.resize(feature, feature, Size(20,20)); // int predicted = knn.findNearest(feature.reshape(1,1), 1);
}
}
|
代码在本人主机上的输出结果为: error count: 154, accuracy is: 0.9384
可见识别正确率仅有约 93.8%