如何使用 opencv4.2 (Android) 检测正方形

How can I detect squares using opencv4.2 (Android)

我正在检测一个矩形并将颜色与尿液试纸进行比较。

我怎样才能检测到所有的方块?我想检测下图中剩余的方块。我试过改变亮度和对比度

这是我的代码:

MainActivity.java

...
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        ...
                    Bitmap img = BitmapFactory.decodeStream(in);
                    in.close();
                    Bitmap changeImg = changeBitmapContrastBrightness(img, (float)1, 10);
                    Mat cMap = new Mat();
                    Utils.bitmapToMat(changeImg, cMap);
                    List<MatOfPoint> squres = processImage(cMap);

                    for (int i = 0; i < squres.size(); i++) {
                        setLabel(cMap, String.valueOf(i), squres.get(i));
                    }

                    Bitmap resultBitmap = Bitmap.createBitmap(cMap.cols(), cMap.rows(), Bitmap.Config.ARGB_8888);
                    Utils.matToBitmap(cMap, resultBitmap);
                    imgView.setImageBitmap(resultBitmap);
                ...
    }
...
private static List<MatOfPoint> processImage(Mat img){
        ArrayList<MatOfPoint> squares = new ArrayList<>();
        Mat matGray = new Mat();
        Mat matCny = new Mat();
        Mat matBlur = new Mat();
        Mat matThresh = new Mat();
        Mat close = new Mat();
        // 노이즈 제거위해 다운스케일 후 업스케일
//        Imgproc.pyrDown(matInit, matBase, matBase.size());
//        Imgproc.pyrUp(matBase, matInit, matInit.size());
        // GrayScale
        Imgproc.cvtColor(img, matGray, Imgproc.COLOR_BGR2GRAY);
        // Blur
        Imgproc.medianBlur(matGray, matBlur, 5);
        //        // Canny Edge 검출
//        Imgproc.Canny(matBlur, matCny, 0, 255);
//        // Binary
        Imgproc.threshold(matBlur, matThresh, 160, 255, Imgproc.THRESH_BINARY_INV);
        Imgproc.morphologyEx(matThresh, close, Imgproc.MORPH_CLOSE, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3)));
//        // 노이즈 제거
//        Imgproc.erode(matCny, matCny, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new org.opencv.core.Size(6, 6)));
//        Imgproc.dilate(matCny, matCny, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new org.opencv.core.Size(12, 12)));

        List<MatOfPoint> contours = new ArrayList<>();
        Mat hierarchy = new Mat();
        Imgproc.findContours(close, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
        double min_area = 0;
        double max_area = 10000;
        for(MatOfPoint cnt : contours){
            double contourArea = Imgproc.contourArea(cnt);

            if(contourArea > min_area && contourArea < max_area){
                squares.add(cnt);
            }
        }
        return squares;
    }

应用结果图片


原图

请帮帮我..

您的代码正确识别了较小的盒子并忽略了作为条带的非常大的盒子,因此基础知识都已到位。

它无法识别条带上较小的框 - 鉴于您的轮廓发现显然有效,这表明您的阈值函数中的阈值(上面代码中的 160)可能需要调整,以便它包括条带上没有黑色轮廓的彩框。黑色轮廓肯定会脱。

无论根本原因是什么,您可能会发现最简单的调试方法是输出并查看生成的中间图像 - 这将使您能够非常快速地亲自检查模糊和阈值处理的结果。

如果您正在处理多个图像并且发现阈值不是您可以预先可靠确定的东西,您也可以看看使用自适应阈值。文档在这里:https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html?highlight=adaptivethreshold and there is a very nice example in this answer here:

adaptiveThreshold 参数允许您微调其行为,值得对其进行试验,看看什么最适合给定类型,如果图像: