You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android平台OpenCV透视变换及矩形检测优化问题咨询

Android OpenCV:透视变换实现与矩形检测优化

嘿,作为OpenCV Android新手能成功检测出矩形已经迈出了很棒的一步!我来帮你搞定透视变换的实现,同时给你一些矩形检测的优化建议~


问题背景

我是Android平台OpenCV新手,已成功检测出图像中的矩形,但不清楚如何使用getPerspectiveTransform()和warpPerspective()函数完成透视变换(含旋转操作);同时希望获取矩形检测的优化建议。

以下是我的矩形检测函数:

Mat tempMat = new Mat();
Mat src = new Mat();
Utils.bitmapToMat(image, tempMat);

Imgproc.cvtColor(tempMat, src, Imgproc.COLOR_BGR2RGB);

Mat blurred = src.clone();
Imgproc.medianBlur(src, blurred, 9);

Mat gray0 = new Mat(blurred.size(), CvType.CV_8U), gray = new Mat();

List<MatOfPoint> contours = new ArrayList<MatOfPoint>();

List<Mat> blurredChannel = new ArrayList<Mat>();
blurredChannel.add(blurred);
List<Mat> gray0Channel = new ArrayList<Mat>();
gray0Channel.add(gray0);

MatOfPoint2f approxCurve = new MatOfPoint2f();

double maxArea = 0;
int maxId = -1;

for (int c = 0; c < 3; c++) {
    int ch[] = { c, 0 };
    Core.mixChannels(blurredChannel, gray0Channel, new MatOfInt(ch));

    int thresholdLevel = 1;
    for (int t = 0; t < thresholdLevel; t++) {
        if (t == 0) {
            Imgproc.Canny(gray0, gray, 50, 50, 3, true); // true ?
            Imgproc.dilate(gray, gray, new Mat(), new Point(-1, -1), 1); // 1 ?
        } else {
            Imgproc.adaptiveThreshold(gray0, gray, thresholdLevel,
                    Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
                    Imgproc.THRESH_BINARY,
                    (src.width() + src.height()) / 200, t);
        }

        Imgproc.findContours(gray, contours, new Mat(),
                Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

        for (MatOfPoint contour : contours) {
            MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());

            double area = Imgproc.contourArea(contour);
            approxCurve = new MatOfPoint2f();
            Imgproc.approxPolyDP(temp, approxCurve,
                    Imgproc.arcLength(temp, true) * 0.02, true);

            if (approxCurve.total() == 4 && area >= maxArea) {
                double maxCosine = 0;

                List<Point> curves = approxCurve.toList();
                for (int j = 2; j < 5; j++) {

                    double cosine = Math.abs(angle(curves.get(j % 4),
                            curves.get(j - 2), curves.get(j - 1)));
                    maxCosine = Math.max(maxCosine, cosine);
                }

                if (maxCosine < 0.45) {
                    maxArea = area;
                    maxId = contours.indexOf(contour);
                }
            }
        }
    }
}

绘制矩形的代码:

if (maxId >= 0) {
    Rect rect = Imgproc.boundingRect(contours.get(maxId));

    Imgproc.rectangle(src, rect.tl(), rect.br(), new Scalar(255, 0, 0,
            .8), 4);

}

之后将Mat转换为Bitmap并显示在ImageView中。

使用版本:OpenCV Android SDK 3.4.1、Android Studio 3.0.1


一、实现透视变换(含旋转矫正)

你当前用boundingRect得到的是轴对齐的矩形,但透视变换需要检测到的四边形的四个原始顶点,而不是轴对齐的边界框。以下是完整的实现步骤:

1. 获取并排序四边形顶点

轮廓检测得到的四个点顺序可能是随机的,必须先按左上、右上、右下、左下的顺序排序,否则透视变换会出现变形。添加一个排序方法:

private Point[] sortQuadPoints(List<Point> points) {
    Point[] sorted = new Point[4];
    // 按x+y和排序,最小为左上,最大为右下
    Collections.sort(points, (p1, p2) -> Double.compare(p1.x + p1.y, p2.x + p2.y));
    sorted[0] = points.get(0); // 左上
    sorted[2] = points.get(3); // 右下

    // 剩余两点按x排序,小的为左下,大的为右上
    List<Point> remaining = points.subList(1, 3);
    Collections.sort(remaining, (p1, p2) -> Double.compare(p1.x, p2.x));
    sorted[3] = remaining.get(0); // 左下
    sorted[1] = remaining.get(1); // 右上

    return sorted;
}

2. 计算透视变换矩阵并执行变换

在绘制矩形的代码后添加以下逻辑:

if (maxId >= 0) {
    // 获取检测到的四边形顶点
    MatOfPoint contour = contours.get(maxId);
    MatOfPoint2f srcQuad = new MatOfPoint2f(contour.toArray());
    // 对顶点排序
    Point[] sortedPoints = sortQuadPoints(srcQuad.toList());
    srcQuad = new MatOfPoint2f(sortedPoints);

    // 定义目标矩形的尺寸(根据你的需求调整)
    int targetWidth = 400;
    int targetHeight = 600;
    MatOfPoint2f dstQuad = new MatOfPoint2f(
        new Point(0, 0),
        new Point(targetWidth, 0),
        new Point(targetWidth, targetHeight),
        new Point(0, targetHeight)
    );

    // 计算透视变换矩阵
    Mat transformMatrix = Imgproc.getPerspectiveTransform(srcQuad, dstQuad);

    // 执行透视变换(自动矫正旋转和透视变形)
    Mat warpedMat = new Mat();
    Imgproc.warpPerspective(src, warpedMat, transformMatrix, new Size(targetWidth, targetHeight));

    // 将变换后的Mat转为Bitmap显示
    Bitmap warpedBitmap = Bitmap.createBitmap(warpedMat.cols(), warpedMat.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(warpedMat, warpedBitmap);
    // 设置到你的ImageView
    // imageView.setImageBitmap(warpedBitmap);
}

关键说明

  • getPerspectiveTransform:接收源四边形顶点和目标矩形顶点,生成3x3的变换矩阵。
  • warpPerspective:使用变换矩阵将源图像映射到目标矩形,自动处理旋转、拉伸等透视变形。

二、矩形检测的优化建议

针对你的代码,这里有几个实用的优化点,既能提升检测精度又能降低性能消耗:

  • 过滤小轮廓,减少计算量:在遍历轮廓时,先跳过面积过小的轮廓,避免无效计算:

    double minArea = src.width() * src.height() * 0.05; // 过滤小于图像5%面积的轮廓
    if (area < minArea) continue;
    
  • 调整Canny和阈值参数:当前Canny的双阈值都是50,可改为更合理的范围(比如30/100);adaptiveThreshold的blockSize必须是奇数,建议改成固定值:

    // 修改Canny参数
    Imgproc.Canny(gray0, gray, 30, 100, 3, true);
    // 修改adaptiveThreshold的blockSize为奇数
    Imgproc.adaptiveThreshold(gray0, gray, thresholdLevel,
            Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
            Imgproc.THRESH_BINARY,
            31, t); // 31是奇数,适合大多数场景
    
  • 减少Mat对象的创建:Android设备内存有限,尽量复用Mat对象,比如把循环内的MatOfPoint2f temp = new MatOfPoint2f(...)提到循环外复用。

  • 使用RETR_EXTERNAL轮廓检索模式:只检测最外层轮廓,避免内部轮廓干扰:

    Imgproc.findContours(gray, contours, new Mat(),
            Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
    
  • 绘制原始四边形而非轴对齐矩形:方便调试,直观看到检测的真实轮廓:

    if (maxId >= 0) {
        MatOfPoint2f approxCurve = new MatOfPoint2f(contours.get(maxId).toArray());
        Imgproc.approxPolyDP(approxCurve, approxCurve, Imgproc.arcLength(approxCurve, true)*0.02, true);
        // 绘制多边形
        Imgproc.polylines(src, Collections.singletonList(new MatOfPoint(approxCurve.toArray())), true, new Scalar(255,0,0,0.8),4);
    }
    
  • 优化角度判断阈值:当前maxCosine < 0.45,这个值越小,对矩形的直角要求越严格,可根据场景调整为0.3,减少梯形误判。


内容的提问来源于stack exchange,提问作者Melih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:28:16