0

我对openCV很陌生,目前我正在尝试在android设备上运行对象检测。我基本上做的是在我的应用程序中显示一个相机预览,当我点击它时它会捕获一张图片。然后将这张图片提供给 runFeatureHomography - 方法,该方法首先抓取第二张图片,与拍摄的图片进行比较。然后该方法在两张图片中找到关键点,计算它们并将它们匹配到一个名为 img_matches 的 Mat 中。我猜尽可能基本。

我现在试图在这里检测的对象是某种卡,就像信用卡的格式一样。卡片是蓝色的,上面有很多白色和黄色的文字。我只能发一个链接,这就是为什么我不能显示他们的照片。

我不知道为什么,但是当我最后显示结果/或将结果作为位图保存到我的手机时,它总是看起来像这样:

http://oi44.tinypic.com/oaqel0.jpg <-- 完成所有操作后的结果图像。

这表明我想检测的对象确实被检测到了,但我不知道为什么有黑色背景而不是卡片的图片。为什么它不按原样显示我的两个图像,只显示它们的所有线条?

在我的代码中我使用这三个:

FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.ORB);
DescriptorMatchermatcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);

这是我的一些代码:

private void runFeatureHomography(Bitmap image)
{

    Mat img_object = getObjectImage();
    Mat img_scene = newEmptyMat();

    Bitmap myimg = image.copy(Bitmap.Config.ARGB_8888, true);

    Utils.bitmapToMat(myimg, img_scene);

    MatOfKeyPoint keyPoints_object = detectObjectKeyPoints();
    MatOfKeyPoint keyPoints_scene = new MatOfKeyPoint();

    this.detector.detect(img_scene, keyPoints_scene);

    Mat descriptors_object = calculateObjectDescriptor();
    Mat descriptors_scene = newEmptyMat();

    this.extractor.compute(img_scene, keyPoints_scene, descriptors_scene);

    MatOfDMatch matches = new MatOfDMatch();

    matcher.match(descriptors_object, descriptors_scene, matches);

    double min_dist = Double.MAX_VALUE;
    for (int i = -1; ++i < descriptors_object.rows();)
    {
        double dist = matches.toArray()[i].distance;
        if (dist < min_dist)
        {
            min_dist = dist;
        }
    }


    List<DMatch> good_matches = new ArrayList<DMatch>();
    for (int i = -1; ++i < descriptors_object.rows();)
    {
        if (matches.toArray()[i].distance <= 3 * min_dist)
        {
            good_matches.add(matches.toArray()[i]);
        }
    }

    System.out.println("4");
    Mat img_matches = newEmptyMat();
    Features2d.drawMatches(
            img_object,
            keyPoints_object,
            img_scene,
            keyPoints_scene,
            new MatOfDMatch(good_matches.toArray(new DMatch[good_matches
                    .size()])), img_matches, Scalar.all(-1),
            Scalar.all(-1), new MatOfByte(),
            Features2d.NOT_DRAW_SINGLE_POINTS);

    List<Point> object = new ArrayList<Point>();
    List<Point> scene = new ArrayList<Point>();
    for (int i = -1; ++i < good_matches.size();)
    {
        object.add(keyPoints_object.toArray()[good_matches.get(i).queryIdx].pt);
        scene.add(keyPoints_scene.toArray()[good_matches.get(i).trainIdx].pt);
    }

    Mat H = Calib3d.findHomography(
            new MatOfPoint2f(object.toArray(new Point[object.size()])),
            new MatOfPoint2f(scene.toArray(new Point[scene.size()])),
            Calib3d.RANSAC, 3);

    Point[] object_corners = new Point[4];
    object_corners[0] = new Point(0, 0);
    object_corners[1] = new Point(img_object.cols(), 0);
    object_corners[2] = new Point(img_object.cols(), img_object.rows());
    object_corners[3] = new Point(0, img_object.rows());

    MatOfPoint2f scene_corners2f = new MatOfPoint2f();
    Core.perspectiveTransform(new MatOfPoint2f(object_corners),
            scene_corners2f, H);

    Point[] scene_corners = scene_corners2f.toArray();
    Point[] scene_corners_norm = new Point[4];
    scene_corners_norm[0] = new Point(scene_corners[0].x
            + img_object.cols(), scene_corners[0].y);
    scene_corners_norm[1] = new Point(scene_corners[1].x
            + img_object.cols(), scene_corners[1].y);
    scene_corners_norm[2] = new Point(scene_corners[2].x
            + img_object.cols(), scene_corners[2].y);
    scene_corners_norm[3] = new Point(scene_corners[3].x
            + img_object.cols(), scene_corners[3].y);
    Core.line(img_matches, scene_corners_norm[0], scene_corners_norm[1],
            new Scalar(0, 255, 0), 4);
    Core.line(img_matches, scene_corners_norm[1], scene_corners_norm[2],
            new Scalar(0, 255, 0), 4);
    Core.line(img_matches, scene_corners_norm[2], scene_corners_norm[3],
            new Scalar(0, 255, 0), 4);
    Core.line(img_matches, scene_corners_norm[3], scene_corners_norm[0],
            new Scalar(0, 255, 0), 4);

    bmp = Bitmap.createBitmap(img_matches.cols(), img_matches.rows(),
            Bitmap.Config.ARGB_8888);


     Intent resultIntent = new Intent("com.example.capturetest.Result");
     startActivity(resultIntent);

}

private volatile Mat cachedObjectDescriptor = null;
private volatile MatOfKeyPoint cachedObjectKeyPoints = null;
private volatile Mat cachedObjectImage = null;

private Mat calculateObjectDescriptor()
{
    Mat objectDescriptor = this.cachedObjectDescriptor;
    if (objectDescriptor == null)
    {
        Mat objectImage = getObjectImage();
        MatOfKeyPoint objectKeyPoints = detectObjectKeyPoints();
        objectDescriptor = newEmptyMat();
        this.extractor.compute(objectImage, objectKeyPoints,
                objectDescriptor);
        this.cachedObjectDescriptor = objectDescriptor;
    }
    return objectDescriptor;
}

private MatOfKeyPoint detectObjectKeyPoints()
{
    MatOfKeyPoint objectKeyPoints = this.cachedObjectKeyPoints;
    if (objectKeyPoints == null)
    {
        Mat objectImage = getObjectImage();
        objectKeyPoints = new MatOfKeyPoint();
        this.detector.detect(objectImage, objectKeyPoints);
        this.cachedObjectKeyPoints = objectKeyPoints;
    }
    return objectKeyPoints;
}

private Mat getObjectImage()
{
    Mat objectImage = this.cachedObjectImage;
    if (objectImage == null)
    {
        objectImage = newEmptyMat();
        Bitmap bitmap = ((BitmapDrawable) iv.getDrawable()).getBitmap();
        Bitmap img = bitmap.copy(Bitmap.Config.ARGB_8888, false);
        Utils.bitmapToMat(img, objectImage);

        this.cachedObjectImage = objectImage;
    }
    return objectImage;
}

private Mat newEmptyMat()
{
    return new Mat();
}

在这一行之后 matcher.match(descriptors_object, descriptors_scene, matches); 我尝试将三个 Mat img_object、img_scene 和匹配转换为位图并将它们保存到我的 android 设备中以供检查。他们看起来都像他们应该的样子,所以直到这一点一切都很好。

但是在这部分之后...

 Mat img_matches = newEmptyMat();
    Features2d.drawMatches(
            img_object,
            keyPoints_object,
            img_scene,
            keyPoints_scene,
            new MatOfDMatch(good_matches.toArray(new DMatch[good_matches
                    .size()])), img_matches, Scalar.all(-1),
            Scalar.all(-1), new MatOfByte(),
            Features2d.NOT_DRAW_SINGLE_POINTS);

...我尝试将 Mat img_matches (如果我做对了,它应该具有两个输入图片的所有信息)转换为位图并将其保存在我的 android 设备上,但图片看起来像图片上面的链接(带线条的黑色图片而不是带线条的卡片图片)。

你们有谁知道我在这里做错了什么?此刻我似乎陷入了困境。

提前谢谢各位。

编辑:

只是想让您知道,我在桌面上运行和工作的代码与普通的 java 程序相同。图片是从那里的网络摄像头拍摄的。结果图像在桌面程序中显示绝对正确,用卡片和线条代替黑色和线条;)

4

1 回答 1

0

好吧,找到了一种工作方式:

Imgproc.cvtColor(img_object, img_object, Imgproc.COLOR_RGBA2RGB);
Imgproc.cvtColor(img_scene, img_scene, Imgproc.COLOR_RGBA2RGB);

似乎在我将位图转换为 Mats 后,我必须使用上述两行将它们从 RGBA 转换为 RGB。如果您更喜欢灰色图片,它也适用于 RGBA 到 GREY。

在这种情况下,RGBA 格式似乎不起作用。

希望这可以帮助任何从谷歌来到这里的人。

于 2013-08-14T11:36:55.990 回答