OpenCV使用霍夫变换检测图像中的形状

August 22, 2016


转载请说明出处! 作者:kqw攻城狮 出处:个人站 | CSDN


霍夫变换是一种被广泛使用的利用数学等式的参数形式在图像中检测形状的技术。 例如直线、椭圆、圆等形状。

霍夫变换可以检测任何能以参数形式表示的形状,随着形状的复杂(维数的增加,例如球体),计算的消耗也会增加。 我们通常只考虑简单的霍夫形状,例如直线和圆。

源码

KqwOpenCVFeaturesDemo

霍夫直线

效果图

效果图

原图

步骤

  1. 将图像置灰
  2. 调用Imgproc.HoughLinesP(cannyEdges, lines, 1, Math.PI / 180, 50, 20, 20) 方法获取直线的数据

    • 第一个参数:图像输入
    • 第二个参数:图像输出
    • 第三个参数:图像指定像素中r的解析度
    • 第四个参数:图像指定像素中θ的解析度
    • 第五个参数:直线上点数的阈值
    • 第六个参数:直线上点数的最小值
  3. 在图像上绘制直线

封装

/**
 * 霍夫直线
 *
 * @param bitmap 要检测的图片
 */
public void houghLines(Bitmap bitmap) {
    if (null != mSubscriber)
        Observable
                .just(bitmap)
                // 检测边缘
                .map(new Func1<Bitmap, Mat>() {
                    @Override
                    public Mat call(Bitmap bitmap) {
                        Mat grayMat = new Mat();
                        Mat cannyEdges = new Mat();

                        // Bitmap转为Mat
                        Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
                        Utils.bitmapToMat(bitmap, src);

                        // 原图置灰
                        Imgproc.cvtColor(src, grayMat, Imgproc.COLOR_BGR2GRAY);
                        // Canny边缘检测器检测图像边缘
                        Imgproc.Canny(grayMat, cannyEdges, 10, 100);

                        return cannyEdges;
                    }
                })
                // 霍夫直线
                .map(new Func1<Mat, Bitmap>() {

                    @Override
                    public Bitmap call(Mat cannyEdges) {

                        Mat lines = new Mat();

                        Imgproc.HoughLinesP(cannyEdges, lines, 1, Math.PI / 180, 50, 20, 20);

                        Mat houghLines = new Mat();
                        houghLines.create(cannyEdges.rows(), cannyEdges.cols(), CvType.CV_8UC1);

                        // 在图像上画直线
                        for (int i = 0; i < lines.cols(); i++) {
                            double[] points = lines.get(0, i);
                            double x1, y1, x2, y2;
                            x1 = points[0];
                            y1 = points[1];
                            x2 = points[2];
                            y2 = points[3];

                            Point pt1 = new Point(x1, y1);
                            Point pt2 = new Point(x2, y2);

                            // 绘制直线
                            Core.line(houghLines, pt1, pt2, new Scalar(255, 0, 0), 1);
                        }

                        // Mat转Bitmap
                        Bitmap processedImage = Bitmap.createBitmap(houghLines.cols(), houghLines.rows(), Bitmap.Config.ARGB_8888);
                        Utils.matToBitmap(houghLines, processedImage);

                        return processedImage;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(mSubscriber);
}

使用

// 图片特征提取的工具类
mFeaturesUtil = new FeaturesUtil(new Subscriber<Bitmap>() {
    @Override
    public void onCompleted() {
        // 图片处理完成
        dismissProgressDialog();
    }

    @Override
    public void onError(Throwable e) {
        // 图片处理异常
        dismissProgressDialog();
    }

    @Override
    public void onNext(Bitmap bitmap) {
        // 获取到处理后的图片
        mImageView.setImageBitmap(bitmap);
    }
});

// 霍夫直线
mFeaturesUtil.houghLines(mSelectImage);

霍夫圆

效果图

效果图

原图

步骤

霍夫圆与霍夫直线类似,只是等式改变了,调用

Imgproc.HoughCircles(cannyEdges, circles, Imgproc.CV_HOUGH_GRADIENT, 1, cannyEdges.rows() / 15);

获取圆的数据

封装

/**
 * 霍夫圆
 *
 * @param bitmap 要检测的图片
 */
public void houghCircles(Bitmap bitmap) {
    if (null != mSubscriber)
        Observable
                .just(bitmap)
                // 检测边缘
                .map(new Func1<Bitmap, Mat>() {
                    @Override
                    public Mat call(Bitmap bitmap) {
                        Mat grayMat = new Mat();
                        Mat cannyEdges = new Mat();

                        // Bitmap转为Mat
                        Mat src = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
                        Utils.bitmapToMat(bitmap, src);

                        // 原图置灰
                        Imgproc.cvtColor(src, grayMat, Imgproc.COLOR_BGR2GRAY);
                        // Canny边缘检测器检测图像边缘
                        Imgproc.Canny(grayMat, cannyEdges, 10, 100);

                        return cannyEdges;
                    }
                })
                // 霍夫圆
                .map(new Func1<Mat, Bitmap>() {

                    @Override
                    public Bitmap call(Mat cannyEdges) {

                        Mat circles = new Mat();
                        Imgproc.HoughCircles(cannyEdges, circles, Imgproc.CV_HOUGH_GRADIENT, 1, cannyEdges.rows() / 15);

                        Mat houghCircles = new Mat();
                        houghCircles.create(cannyEdges.rows(), cannyEdges.cols(), CvType.CV_8UC1);

                        // 在图像上画圆
                        for (int i = 0; i < circles.cols(); i++) {
                            double[] parameters = circles.get(0, i);
                            double x, y;
                            int r;

                            x = parameters[0];
                            y = parameters[1];
                            r = (int) parameters[2];

                            // 绘制圆
                            Point center = new Point(x, y);
                            Core.circle(houghCircles, center, r, new Scalar(255, 0, 0), 1);
                        }

                        // Mat转Bitmap
                        Bitmap processedImage = Bitmap.createBitmap(houghCircles.cols(), houghCircles.rows(), Bitmap.Config.ARGB_8888);
                        Utils.matToBitmap(houghCircles, processedImage);

                        return processedImage;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(mSubscriber);
}

使用

// 图片特征提取的工具类
mFeaturesUtil = new FeaturesUtil(new Subscriber<Bitmap>() {
    @Override
    public void onCompleted() {
        // 图片处理完成
        dismissProgressDialog();
    }

    @Override
    public void onError(Throwable e) {
        // 图片处理异常
        dismissProgressDialog();
    }

    @Override
    public void onNext(Bitmap bitmap) {
        // 获取到处理后的图片
        mImageView.setImageBitmap(bitmap);
    }
});

// 霍夫圆
mFeaturesUtil.houghCircles(mSelectImage);