版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
1、训练数据:通过轮廓或者比例将字符分割mat.submat-缩放Imgproc.resize-转为浮点型-矩阵拉直reshape(1, 1),再存入Mat
2、定制训练结果:可以通过Map将字符结果和key进行映射
3、使用knn加入训练数据和结果,再通过查找匹配函数找出最相似的几个值
主要函数:
参考:https://answers.opencv.org/question/89927/how-to-use-knearest-in-java/
KNearest.train(Mat samples, int layout, Mat responses);
训练数据Mat, Ml.ROW_SAMPLE每行一个结果,Mat结果,可以使用int转mat函数
KNearest.findNearest(Mat samples, int k, Mat results);
输入测试数据Mat,找出k个相邻值,该函数返回预测结果,通过map.get(key)从而识别出对应的字符
package com.wx;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.ml.KNearest;
import org.opencv.ml.Ml;
import org.opencv.utils.Converters;
import org.testng.annotations.Test;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName TestImageOCR
* @Description //TODO
* @Author wuxi
* @Date 2019-06-24 22:01
* @Version 1.0
**/
public class TestImageOCR {
static { System.load(System.getProperty("user.dir") + "/src/main/resources/opencv_java342.dylib");}
private List<Integer> testLabs = new ArrayList<>();
private StringBuffer result=new StringBuffer();
@Test
public void TestImageKnn() {
Mat mat = Imgcodecs.imread("src/main/resources/numbers/upper_case_letter_1.jpg");
Mat Data = getImageTrain(mat);
KNearest knn = KNearest.create();
Map testMap=getImageLabs();
//训练数据,每行一个样本,第三个参数为训练样本对应的正确答案
knn.train(Data, Ml.ROW_SAMPLE, Converters.vector_int_to_Mat(testLabs));
//测试数据
Mat testData = Imgcodecs.imread("src/main/resources/numbers/upper_case_letter_2.jpg");
Mat imageTrain = getImageTrain(testData);
int err = 0;
for (int i = 0; i < testMap.keySet().size(); i++) {
// 读取一行
Mat one_feature = imageTrain.row(i);
//Imgcodecs.imwrite("/Users/wuxi/Pictures/testdata/" + "testData" + one_feature + ".jpg", one_feature);
// 预期答案
int testLabel = testLabs.get(i);
System.out.println("testLabel============" + testMap.get(testLabel));
Mat res = new Mat();
// 查找匹配:第一个参数为输入样本(可一次输入多个样本),第二个参数为需要返回的K个邻近(即KNearest的那个K),第三个参数为返回结果(res: result),结果为样本对应的Label值,每一个样本的匹配结果对应一行
// 如果输入仅有一个样本,则返回结果(p)就是预测结果。参数 1即为K-近邻算法的关键参数
float p = knn.findNearest(one_feature, 1, res);
System.out.println("result============"+ testMap.get((int)(p)) + " " + res.dump());
result.append(testMap.get((int)(p)));
int iRes = (int) p;
if (iRes != testLabel) {
err++;
}
}
System.out.println("识别结果============"+result);
float accuracy = (float) ((testMap.keySet().size() - (float)err) / testMap.keySet().size());
DecimalFormat df = new DecimalFormat("0.0000");
System.out.println("error count: " + err + ", accuracy is: " + df.format(accuracy));
}
//获取训练数据
public Mat getImageTrain(Mat mat) {
Mat trainData = new Mat();
Mat dst = mat.clone();
//灰度
Imgproc.cvtColor(mat, dst, Imgproc.COLOR_BGR2GRAY);
//二值化
Imgproc.threshold(dst, dst, 245, 255, 1);
List<MatOfPoint> contours = new ArrayList<>();
//在二值化图像中查找轮廓,最外层
Imgproc.findContours(dst, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
for (MatOfPoint cnt : contours) {
Rect rect = Imgproc.boundingRect(cnt);
//计算轮廓的垂直边界最小矩形,矩形是与图像上下边界平行的,points 读入的参数必须是vector或者Mat点集
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
if (w>6&&h>10) {
Imgproc.rectangle(mat, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 0, 255), 1); //线的宽度
//HighGui.imshow("mat",mat);
//HighGui.waitKey(50);
//输出图片查看
Rect image = new Rect(x, y, w, h);
//裁剪区域
Mat imgROI = new Mat(dst, image);
//无需轮廓手动切割
//Mat num = mat.submat(new Rect(20, 40, 20, 20));
//缩放
Imgproc.resize(imgROI, imgROI, new Size(20, 40));
// knn算法的输入为浮点型,在此转换
imgROI.convertTo(imgROI, CvType.CV_32F);
trainData.push_back(imgROI.reshape(1, 1));
//Imgcodecs.imwrite("/Users/wuxi/Pictures/picture/"+imgROI+".jpg", imgROI.reshape(1, 1));
}
}
//Imgcodecs.imwrite("/Users/wuxi/Pictures/picture/juxing.jpg", mat);
return trainData;
}
//获取训练结果
public Map<Integer, Character> getImageLabs() {
Map<Integer, Character> testMap=new HashMap<>();
String test = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < test.length(); i++) {
char fir = test.charAt(i);
testLabs.add(i);
testMap.put(i,fir);
}
return testMap;
}
}
运行结果: