如何使用MatOfKeyPoint在Java中绘制矩形以进行文本检测

3
我正在使用OpenCV4Android进行实时文本检测和识别。目前,识别部分已经完全完成。但是,我需要询问一些关于文本检测的问题。我正在使用MSER FeatureDetector来检测文本。
以下是实时调用方法的部分内容:
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    carrierMat = inputFrame.gray();
    carrierMat = General.MSER(carrierMat);
    return carrierMat;
}

以下是基本的MSER实现:

private static FeatureDetector fd = FeatureDetector.create(FeatureDetector.MSER);
private static MatOfKeyPoint mokp = new MatOfKeyPoint();
private static Mat edges = new Mat();

public static Mat MSER(Mat mat) {
    //for mask
    Imgproc.Canny(mat, edges, 400, 450);
    fd.detect(mat, mokp, edges);
    //for drawing keypoints
    Features2d.drawKeypoints(mat, mokp, mat);
    return mat;
}

对于找到边缘掩模的文本,它能够正常工作。

我想要为聚类绘制矩形,就像这样:

enter image description here

或者是这个:

enter image description here

您可以假设我有正确的点。

正如您所看到的,fd.detect()方法返回一个MatOfKeyPoint。因此,我尝试了以下方法来绘制矩形:

public static Mat MSER_(Mat mat) {
    fd.detect(mat, mokp);
    KeyPoint[] refKp = mokp.toArray();
    Point[] refPts = new Point[refKp.length];

    for (int i = 0; i < refKp.length; i++) {
        refPts[i] = refKp[i].pt;
    }
    MatOfPoint2f refMatPt = new MatOfPoint2f(refPts);
    MatOfPoint2f approxCurve = new MatOfPoint2f();

    //Processing on mMOP2f1 which is in type MatOfPoint2f
    double approxDistance = Imgproc.arcLength(refMatPt, true) * 0.02;
    Imgproc.approxPolyDP(refMatPt, approxCurve, approxDistance, true);

    //Convert back to MatOfPoint
    MatOfPoint points = new MatOfPoint(approxCurve.toArray());
    // Get bounding rect
    Rect rect = Imgproc.boundingRect(points);
    // draw enclosing rectangle (all same color, but you could use variable i to make them unique)
    Imgproc.rectangle(mat, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), Detect_Color_, 5);
    //Features2d.drawKeypoints(mat, mokp, mat);
    return mat;
}

但是当我尝试使用Imgproc.arcLength()方法时,它突然停止了。 我为Imgproc.approxPolyDP()方法提供了一个随机的approxDistanc值,如0.1,但它并没有真正有效地工作。
那么,我该如何为检测到的文本绘制矩形?

你好,你之前找到了解决方案吗? - Zy0n
1
不是的,我已经改变了整个算法 :) - Mehmet Taha Meral
1个回答

4
我测试了你的代码,并且遇到了完全相同的问题。目前我还没有找到问题所在。但是我找到了一个同时使用“MSER”和“形态学”的项目,你可以在这里找到它。
该项目结构非常简单,作者将文本检测放在了“onCameraFrame”方法中,就像你一样。我实现了那个项目的方法,它确实起作用了,但结果仍然不是很好。
如果你想要更好的文本检测工具,以下是两个选择:
  1. 笔画宽度变换(SWT):一种全新的查找文本区域的方法。它快速而高效,但只能在C++或Python中使用。你可以在这里找到一些例子。

  2. 基于类的极值区域使用类ERFilter:MSER的高级版本。不幸的是,它只在OpenCV 3.0.0-dev中可用。你不能在当前版本的OpenCV4Android中使用它。文档在这里

老实说,我在这个领域还很新(两个月),但我希望这些信息可以帮助你完成你的项目。
(更新:2015/9/13) 我从这篇文章中翻译了一个C++方法。它比我提到的第一个GitHub项目效果要好得多。以下是代码:
public void apply(Mat src, Mat dst) {
    if (dst != src) {
        src.copyTo(dst);
    }
    Mat img_gray,img_sobel, img_threshold, element;

    img_gray=new Mat();
    Imgproc.cvtColor(src, img_gray, Imgproc.COLOR_RGB2GRAY);

    img_sobel=new Mat();
    Imgproc.Sobel(img_gray, img_sobel, CvType.CV_8U, 1, 0, 3, 1, 0,Core.BORDER_DEFAULT);

    img_threshold=new Mat();
    Imgproc.threshold(img_sobel, img_threshold, 0, 255, Imgproc.THRESH_OTSU+Imgproc.THRESH_BINARY);

    element=new Mat();
    element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(17, 3) );
    Imgproc.morphologyEx(img_threshold, img_threshold, Imgproc.MORPH_CLOSE, element);
    //Does the trick
    List<MatOfPoint>  contours=new ArrayList<MatOfPoint>();
    Mat hierarchy = new Mat();
    Imgproc.findContours(img_threshold, contours, hierarchy, 0, 1);
    List<MatOfPoint> contours_poly=new ArrayList<MatOfPoint>(contours.size());
    contours_poly.addAll(contours);

    MatOfPoint2f mMOP2f1,mMOP2f2;
    mMOP2f1=new MatOfPoint2f();
    mMOP2f2=new MatOfPoint2f();

    for( int i = 0; i < contours.size(); i++ )

        if (contours.get(i).toList().size()>100)
        { 
            contours.get(i).convertTo(mMOP2f1, CvType.CV_32FC2);
            Imgproc.approxPolyDP(mMOP2f1,mMOP2f2, 3, true );
            mMOP2f2.convertTo(contours_poly.get(i), CvType.CV_32S);
            Rect appRect=Imgproc.boundingRect(contours_poly.get(i));
            if (appRect.width>appRect.height) 
            {
                Imgproc.rectangle(dst, new Point(appRect.x,appRect.y) ,new Point(appRect.x+appRect.width,appRect.y+appRect.height), new Scalar(255,0,0));
            }
        }   

}

1
谢谢你的回答。我只能写Java代码,所以不能使用第一和第二项。如果我可以使用C ++,我知道第二个选项是在Android上检测文本的最佳方法。我会检查GitHub项目并告诉你发生了什么。 - Mehmet Taha Meral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接