在Android上玩转Opencv 系列:20.基础知识 利用霍夫变换检测直线和圆

Android 版 OpenCV 直线识别和圆识别

在 Android 上使用 OpenCV 进行直线识别 (Line Detection)和圆识别(Circle Detection)主要依赖 Hough 变换(Hough Transform),这是一种强大的几何检测方法,可用于检测边缘检测后的直线和圆形目标。

1. 直线识别(Hough 直线变换)

1.1 直线检测原理

Hough 直线检测主要用于在图像中寻找直线,其原理基于极坐标表示直线方程:

其中:

通过遍历所有可能的 组合,将投票数最高的参数对确定为直线。

1.2 直线识别步骤

  1. 读取图像并转换为灰度图

  2. 使用 Canny 算法提取边缘

  3. 使用 HoughLines 或 HoughLinesP 进行直线检测

  4. 绘制检测出的直线

1.3 直线检测代码(标准 Hough 变换)

ini 复制代码
import org.opencv.android.Utils;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import android.graphics.Bitmap;
import java.util.*;

public class LineDetection {
    public static Bitmap detectLines(Bitmap inputBitmap) {
        // 将 Bitmap 转换为 Mat
        Mat srcMat = new Mat();
        Utils.bitmapToMat(inputBitmap, srcMat);

        // 转换为灰度图
        Mat grayMat = new Mat();
        Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_BGR2GRAY);

        // 使用 Canny 进行边缘检测
        Mat edges = new Mat();
        Imgproc.Canny(grayMat, edges, 50, 150);

        // 进行 Hough 直线检测
        Mat lines = new Mat();
        Imgproc.HoughLines(edges, lines, 1, Math.PI / 180, 100);

        // 在原图上绘制检测到的直线
        for (int i = 0; i < lines.rows(); i++) {
            double[] data = lines.get(i, 0);
            double rho = data[0];
            double theta = data[1];
            double a = Math.cos(theta);
            double b = Math.sin(theta);
            double x0 = a * rho;
            double y0 = b * rho;
            Point pt1 = new Point(x0 + 1000 * (-b), y0 + 1000 * (a));
            Point pt2 = new Point(x0 - 1000 * (-b), y0 - 1000 * (a));
            Imgproc.line(srcMat, pt1, pt2, new Scalar(0, 255, 0), 2);
        }

        // 转换回 Bitmap
        Bitmap outputBitmap = Bitmap.createBitmap(srcMat.cols(), srcMat.rows(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(srcMat, outputBitmap);

        return outputBitmap;
    }
}

1.4 直线检测代码(概率 Hough 变换)

HoughLinesP() 是 HoughLines() 的优化版本,适用于断续线条的检测。

ini 复制代码
public static Bitmap detectProbabilisticLines(Bitmap inputBitmap) {
    // 转换 Bitmap 为 Mat
    Mat srcMat = new Mat();
    Utils.bitmapToMat(inputBitmap, srcMat);

    // 转换为灰度图
    Mat grayMat = new Mat();
    Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_BGR2GRAY);

    // Canny 边缘检测
    Mat edges = new Mat();
    Imgproc.Canny(grayMat, edges, 50, 150);

    // 进行概率 Hough 直线检测
    Mat lines = new Mat();
    Imgproc.HoughLinesP(edges, lines, 1, Math.PI / 180, 50, 50, 10);

    // 绘制检测到的直线
    for (int i = 0; i < lines.rows(); i++) {
        double[] points = lines.get(i, 0);
        Point pt1 = new Point(points[0], points[1]);
        Point pt2 = new Point(points[2], points[3]);
        Imgproc.line(srcMat, pt1, pt2, new Scalar(255, 0, 0), 2);
    }

    // 转换回 Bitmap
    Bitmap outputBitmap = Bitmap.createBitmap(srcMat.cols(), srcMat.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(srcMat, outputBitmap);

    return outputBitmap;
}

2. 圆识别(Hough 圆变换)

2.1 圆检测原理

Hough 圆检测利用标准方程:

通过遍历不同的 (a, b, r) 值,找出可能的圆形边缘。

2.2 圆识别步骤

  1. 读取图像并转换为灰度图

  2. 使用 GaussianBlur 平滑图像

  3. 使用 HoughCircles 进行圆检测

  4. 绘制检测出的圆

2.3 圆检测代码

ini 复制代码
import org.opencv.android.Utils;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import android.graphics.Bitmap;
import java.util.*;

public class CircleDetection {
    public static Bitmap detectCircles(Bitmap inputBitmap) {
        // 转换 Bitmap 为 Mat
        Mat srcMat = new Mat();
        Utils.bitmapToMat(inputBitmap, srcMat);

        // 转换为灰度图
        Mat grayMat = new Mat();
        Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_BGR2GRAY);

        // 进行高斯模糊,减少噪声
        Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 2, 2);

        // 进行 Hough 圆检测
        Mat circles = new Mat();
        Imgproc.HoughCircles(grayMat, circles, Imgproc.HOUGH_GRADIENT, 1, 30, 100, 30, 10, 100);

        // 在原图上绘制检测到的圆
        for (int i = 0; i < circles.cols(); i++) {
            double[] data = circles.get(0, i);
            Point center = new Point(data[0], data[1]);
            int radius = (int) data[2];
            Imgproc.circle(srcMat, center, radius, new Scalar(0, 255, 0), 2);
            Imgproc.circle(srcMat, center, 2, new Scalar(0, 0, 255), 3);
        }

        // 转换回 Bitmap
        Bitmap outputBitmap = Bitmap.createBitmap(srcMat.cols(), srcMat.rows(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(srcMat, outputBitmap);

        return outputBitmap;
    }
}

3. 直线 vs 圆检测

Hough 直线检测 Hough 圆检测
适用场景 道路检测、边缘检测 车轮检测、标志识别
输入参数 需要边缘检测 需要模糊处理
计算复杂度 低 高

总结

• HoughLines() 适用于规则直线(如道路边界)。

• HoughLinesP() 适用于断续线(如车道线)。

• HoughCircles() 适用于圆形检测(如硬币、车轮)。

• 预处理(如 Canny 和 GaussianBlur)能提高检测精度。

相关推荐
小徐不徐说6 小时前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
晨间晓3 天前
图片里的高频和低频是什么?用华为云码道开发 OpenCV 傅里叶频谱分析工具
opencv·计算机视觉·华为云
晨间晓3 天前
图片里的阴影能不能减弱?用华为云码道开发 OpenCV 光照校正工具
人工智能·opencv·华为云
晨间晓4 天前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭4 天前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓4 天前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云
晨间晓4 天前
二值图里的噪点怎么去掉?用华为云码道开发 OpenCV 形态学操作工具
人工智能·opencv·华为云
晨间晓4 天前
图片里的角点在哪里?用华为云码道开发 OpenCV Harris 角点检测工具
人工智能·opencv·华为云
晨间晓5 天前
图片细节丰富不丰富?用华为云码道开发 OpenCV 纹理复杂度分析工具
人工智能·opencv·华为云
richard_yuu5 天前
OpenCV 实战第 15 篇:G-API 图计算,工业流水线的 CPU/GPU 混合执行
人工智能·opencv·计算机视觉