Android 版 OpenCV 直线识别和圆识别
在 Android 上使用 OpenCV 进行直线识别 (Line Detection)和圆识别(Circle Detection)主要依赖 Hough 变换(Hough Transform),这是一种强大的几何检测方法,可用于检测边缘检测后的直线和圆形目标。
1. 直线识别(Hough 直线变换)
1.1 直线检测原理
Hough 直线检测主要用于在图像中寻找直线,其原理基于极坐标表示直线方程:
其中:
通过遍历所有可能的 组合,将投票数最高的参数对确定为直线。
1.2 直线识别步骤
-
读取图像并转换为灰度图
-
使用 Canny 算法提取边缘
-
使用 HoughLines 或 HoughLinesP 进行直线检测
-
绘制检测出的直线
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 圆识别步骤
-
读取图像并转换为灰度图
-
使用 GaussianBlur 平滑图像
-
使用 HoughCircles 进行圆检测
-
绘制检测出的圆
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)能提高检测精度。