如何规范化OpenCV Android矩阵?

时间:2016-04-19 14:54:05

标签: android opencv opencv3.0

tl; dr 我的K最近的培训数据和实际数据没有相同的尺寸,导致我的应用崩溃。我怀疑我实例化训练数据的方式preProces方法(drawable resource => bitmap => opencv矩阵)是失败的原因。你们中有谁知道解决方案吗?

我一直试图通过OpenCV for Android获得一个简单的OCR应用程序的演示。我使用KNearest中的构建来识别字符。在KNearest对象能够检测到任何内容之前,必须对其进行训练。对于培训,我使用了几个字符轮廓。

A black background with the outline of a 0这是其中之一(零)。

这种训练似乎不足为奇,能够检测到训练图像的假设值。我希望它与其他图像一样(或者leas不会崩溃我的应用程序)。这就是我为训练KNearest模型所做的工作:

Map<Character, Integer> images = new HashMap<>();
images.put('0', R.drawable.training0);

// Prepare two sets of data, the images and their values.
Mat trainingImages = new Mat();
Mat trainingLabels = new Mat();
for (int i = 0; i < 50; i++) {
    for (Map.Entry<Character, Integer> entry : images.entrySet()) {
        Bitmap bitmapImage = BitmapFactory.decodeResource(
            this.getResources(), entry.getValue());
        Mat matImage = new Mat();
        Utils.bitmapToMat(bitmapImage, matImage);

        trainingLabels.push_back(new MatOfInt(entry.getKey() - '0'));
        trainingImages.push_back(
            preProces(
                matImage, new Rect(0, 0, matImage.width(), matImage.height())));
        }
    }

mKNearest.train(trainingImages, Ml.ROW_SAMPLE, trainingLabels);

preProces方法只是对矩阵进行标准化。这就是我的preProces方法:

 private Mat preProces(Mat image, Rect poi) {
    Mat cutout = new Mat(image, poi);
    Mat resized = new Mat(10, 10, CvType.CV_32F);
    Mat converted = new Mat();
    Imgproc.resize(cutout, resized, resized.size());
    resized.reshape(1, 1).convertTo(converted, CvType.CV_32F);
    return converted;
}

分割图像以找到(可能的)字符并不困难,我能够在(可能的)字符周围绘制矩形。完成后,我会通过preProces方法传递每个感兴趣的点,然后再将其传递给mKNearest.findNeareset(...)方法。这是崩溃发生的时候。训练数据和实际数据似乎没有相同的维度,preProces方法应该解决这个问题。

我的猜测是我的preProces方法失败或将可绘制资源加载为位图然后将它们转换为矩阵是失败的原因。我想知道你们中有些人是否有类似的问题,以及你们是如何解决的。

更新:似乎矩阵中存在相当多的噪声,这些噪声是由位图创建的。这可能是问题,如果是这样的话,如何消除噪音?

1 个答案:

答案 0 :(得分:0)

似乎这个问题的答案非常简单。我使用Imgproc.canny()来检测实际数据的边缘,但不检测训练数据。一旦我通过Imgproc.canny()传递了培训数据,问题就解决了。

...
Bitmap bitmapImage = BitmapFactory.decodeResource(
    this.getResources(), entry.getValue());
Mat matImage = new Mat();
Utils.bitmapToMat(bitmapImage, matImage);

// This was all I had to add to the training data preparation.
Mat cannyImage = new Mat();
Imgproc.Canny(matImage, cannyImage, 1.0, 255.0);

trainingLabels.push_back(new MatOfInt(entry.getKey() - '0'));
trainingImages.push_back(
    preProces(
        cannyImage, new Rect(0, 0, cannyImage.width(), cannyImage.height())));
}
...