代码之家  ›  专栏  ›  技术社区  ›  Amine

如何在Android中使用Opencv有效地对图像进行Canny边缘检测?

  •  0
  • Amine  · 技术社区  · 6 年前

    我正在制作一个Android应用程序来检测图像中的多个对象,然后处理这些对象并将它们与参考对象进行比较,以检测异常。我用python测试了不同的图像边缘检测器,Prewitt操作符给出了最好的结果,如下所示 https://i.imgur.com/4iwOx9s.png 对于android,我使用了Canny edge detector,但结果不如Prewitt,如下所示 https://i.imgur.com/Bax1Wxw.png

    这是我试过的java代码

        Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.coffret);
    
        //compress bitmap
        bmp = getResizedBitmap(bmp, 500);
    
        Mat rgbMat = new Mat();
        Utils.bitmapToMat(bmp, rgbMat);
    
    
        Mat grayMat = new Mat();
        Mat bwMat = new Mat();
    
        Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);
        Imgproc.equalizeHist(grayMat, grayMat);
    
        //Imgproc.adaptiveThreshold(grayMat, grayMat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 15, 40);
        Imgproc.Canny(grayMat, bwMat, 50, 200, 3, false);
    
        //find largest contour
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
            Imgproc.findContours(bwMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
    
            double maxArea = -1;
            int maxAreaIdx = -1;
            if (contours.size() > 0) {
                MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point
                MatOfPoint2f approxCurve = new MatOfPoint2f();
                Mat largest_contour = contours.get(0);
                List<MatOfPoint> largest_contours = new ArrayList<MatOfPoint>();
                for (int idx = 0; idx < contours.size(); idx++) {
                    temp_contour = contours.get(idx);
                    double contourarea = Imgproc.contourArea(temp_contour);
                    //compare this contour to the previous largest contour found
                    if (contourarea > maxArea) {
                        //check if this contour is a square
                        MatOfPoint2f new_mat = new MatOfPoint2f( temp_contour.toArray() );
                        int contourSize = (int)temp_contour.total();
                        Imgproc.approxPolyDP(new_mat, approxCurve, contourSize*0.05, true);
                        if (approxCurve.total() == 4) {
                            maxArea = contourarea;
                            maxAreaIdx = idx;
                            largest_contours.add(temp_contour);
                            largest_contour = temp_contour;
                        }
                    }
                }
    
                if (largest_contours.size() >= 1) {
                    MatOfPoint temp_largest = largest_contours.get(largest_contours.size()-1);
                    largest_contours = new ArrayList<MatOfPoint>();
                    largest_contours.add(temp_largest);
                    Imgproc.cvtColor(bwMat, bwMat, Imgproc.COLOR_BayerBG2RGB);
                    Imgproc.drawContours(bwMat, largest_contours, -1, new Scalar(0, 255, 0), 1);
                }
            }
    
    
        Utils.matToBitmap(bwMat, bmp);
    
        Matrix matrix = new Matrix();
        matrix.postRotate(180);
    
        bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
    
        imgView.setImageBitmap(bmp);
    

    如您所注意到的,使用Prewitt操作符,文本更清晰,轮廓更清晰。 我认为我没有正确地应用Canny,这就是为什么没有检测到最大轮廓。我做错什么了?

    编辑: 这是原图 https://i.imgur.com/BtyZOvj.jpg

    1 回复  |  直到 6 年前
        1
  •  0
  •   Paulo Araujo    6 年前

    看来你用的是精明的边缘检测器。然而,有时,定义适当的最小值和最大值来阈值化边缘可能是一个技巧。

    可能你使用的间隔(即50到200)对你的目的来说比较大。您可以尝试更高的最小值和最大值,间隔很紧,例如175到200。

    Improvement on Canny edge detection . 在这一页的末尾,有一个关于如何 确定双阈值 .