You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android中使用OpenCV计数堆叠的卡片?

堆叠薄卡片计数问题

我有一张相机拍摄的堆叠卡片原图,想用OpenCV计数其中的卡片数量,但尝试后结果始终为1。已经完成灰度化+阈值处理,也试过形态学操作与Canny边缘检测,但处理后图像损坏。当前使用的代码如下:

Imgproc.cvtColor(srcMat, gray2, Imgproc.COLOR_BGR2GRAY);
//Imgproc.threshold(gray2, ada, 0, 255, Imgproc.THRESH_OTSU);
Imgproc.threshold(gray2,thresh,165,255,THRESH_BINARY);

Imgproc.HoughLinesP(thresh, lines, 1.0, Math.PI / 180, 50, 100.0, 10.0);
double num_lines = lines.cols();

for(int j =0; j <= lines.rows();j++){
    if(lines.get(j,0) != null){
        double [] dArr = lines.get(j,0);
        Point point1 = new Point(dArr[0],dArr[1]);
        Point point2 = new Point(dArr[2],dArr[3]);
        Imgproc.line(
                thresh,
                point1,
                point2,
                new Scalar(0.0, 255.0, 0.0),
                1
        );
    }
}

想咨询是否能对这类较薄的堆叠物体进行计数,且实际要计数的物体更薄,希望得到代码修正方案或可行的解决代码。


解决方案与代码修正

薄堆叠物体(比如卡片)完全可以通过OpenCV实现计数,核心是精准提取每张卡片的边缘线条,关键在于优化预处理流程和线条检测参数。

原代码问题分析

  1. 固定阈值165适应性差,光照变化时会丢失薄边缘细节
  2. 未做噪声去除,直接用阈值图做霍夫线检测易误检/漏检
  3. 霍夫线参数(阈值、最小线长、最大间隙)设置不合理,无法捕捉薄边缘
  4. 循环边界错误:j <= lines.rows()会导致数组越界,应为j < lines.rows()

修正后的可行代码

以下是针对薄堆叠卡片优化的Java代码,核心流程:灰度化→自适应阈值降噪→形态学增强边缘→霍夫线检测→统计有效边缘数

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;

public class StackedCardsCounter {
    public static int countStackedCards(Mat srcMat) {
        // 1. 灰度化
        Mat gray = new Mat();
        Imgproc.cvtColor(srcMat, gray, Imgproc.COLOR_BGR2GRAY);

        // 2. 自适应阈值处理(适配光照不均,保留薄边缘)
        Mat thresh = new Mat();
        Imgproc.adaptiveThreshold(gray, thresh, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
                Imgproc.THRESH_BINARY_INV, 11, 2);

        // 3. 形态学操作:腐蚀+膨胀,去噪同时增强边缘
        Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(2, 2));
        Imgproc.erode(thresh, thresh, kernel);
        Imgproc.dilate(thresh, thresh, kernel);

        // 4. 霍夫线检测:调整参数捕捉薄边缘
        Mat lines = new Mat();
        // 参数:rho=1, theta=π/180, 检测阈值=30, 最小线长=50, 最大间隙=5
        Imgproc.HoughLinesP(thresh, lines, 1, Math.PI / 180, 30, 50, 5);

        // 5. 统计有效水平边缘(卡片堆叠边缘为水平方向)
        int validEdges = 0;
        if (!lines.empty()) {
            for (int j = 0; j < lines.rows(); j++) {
                double[] dArr = lines.get(j, 0);
                if (dArr != null) {
                    // 过滤非水平线条:计算线条斜率,只保留接近水平的
                    double yDiff = Math.abs(dArr[1] - dArr[3]);
                    double xDiff = Math.abs(dArr[0] - dArr[2]);
                    if (xDiff > 0 && (yDiff / xDiff) < 0.1) {
                        validEdges++;
                        // 可选:在原图绘制检测到的边缘
                        Imgproc.line(srcMat, new Point(dArr[0], dArr[1]), 
                                     new Point(dArr[2], dArr[3]), 
                                     new Scalar(0, 255, 0), 2);
                    }
                }
            }
        }

        // 6. 计算卡片数量:每张卡片对应一条上/下边缘,数量=有效边缘数 +1
        return validEdges + 1;
    }
}

针对更薄物体的优化建议

  • 调整自适应阈值参数:将blockSize改为7,C值改为1,增强薄边缘的提取效果
  • 替换预处理步骤:用Canny边缘检测替代自适应阈值,参数设置为Imgproc.Canny(gray, edges, 50, 150),再对边缘图做霍夫线检测
  • 拍摄时保证光照均匀,避免阴影干扰,能大幅提升检测精度

内容的提问来源于stack exchange,提问作者Handy Siswanto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:27:06