从注意垫/图像中检测OpenCV Notehead

时间:2017-12-11 17:54:02

标签: java opencv image-recognition template-matching

我正在做一个项目,我需要从五线谱中检测音乐元素,而我正知道持续时间一个音符元素(quarter, octet, etc)我想知道什么检测音符头的中心,这样我就可以根据它在五线谱线上的位置找出注意它是(C, D, etc)的内容。

我遇到的问题是我不确切知道从哪里开始。 我正在考虑使用完整和空椭圆作为模板以及元素Mat作为源的模板匹配

有没有人有更好更好的解决方案?

我希望找到音符头的元素Mats的示例:

example1example2example3

GitHub上的项目,如果有人有兴趣的话 https://github.com/AmbroziePaval/OMR

3 个答案:

答案 0 :(得分:2)

一次使用模板匹配实现一个元素(注释)。

示例搜索所有区域并以绿色绘制中心点。

note-head template result

代码:

public Point getAproximateCenterNoteHeadPoint(Mat noteMat) {
    noteMat.convertTo(noteMat, CvType.CV_32FC1);

    Mat fullNoteHeadMat = Imgcodecs.imread(DatasetPaths.FULL_HEAD_TEMPLATE.getPath());
    if (fullNoteHeadMat.channels() == 3) {
        Imgproc.cvtColor(fullNoteHeadMat, fullNoteHeadMat, Imgproc.COLOR_BGR2GRAY);
    }
    fullNoteHeadMat.convertTo(fullNoteHeadMat, CvType.CV_32FC1);

    Mat result = new Mat();
    result.create(noteMat.width(), noteMat.height(), CvType.CV_32FC1);
    double threshold = 0.7;

    Imgproc.matchTemplate(noteMat, fullNoteHeadMat, result, Imgproc.TM_CCOEFF_NORMED);
    Imgproc.threshold(result, result, threshold, 255, Imgproc.THRESH_TOZERO);

    Core.MinMaxLocResult minMaxLocResult = Core.minMaxLoc(result);
    if (minMaxLocResult.maxVal > threshold) {
        Point maxLoc = minMaxLocResult.maxLoc;
        return new Point(maxLoc.x + fullNoteHeadMat.width() / 2, maxLoc.y + fullNoteHeadMat.height() / 2);
    }
    return null;
}

答案 1 :(得分:2)

一次使用模板匹配对所有元素进行实现,正如@Alexander Reynolds在问题评论中所建议的那样:

public List<Point> findAllNoteHeadCenters(Mat imageMat, List<Rect> elementRectangles) {
    imageMat.convertTo(imageMat, CvType.CV_32FC1);

    Mat fullNoteHeadMat = Imgcodecs.imread(DatasetPaths.FULL_HEAD_TEMPLATE.getPath());
    if (fullNoteHeadMat.channels() == 3) {
        Imgproc.cvtColor(fullNoteHeadMat, fullNoteHeadMat, Imgproc.COLOR_BGR2GRAY);
    }
    fullNoteHeadMat.convertTo(fullNoteHeadMat, CvType.CV_32FC1);

    Mat result = new Mat();
    result.create(imageMat.width(), imageMat.height(), CvType.CV_32FC1);
    double threshold = 0.75;

    Imgproc.matchTemplate(imageMat, fullNoteHeadMat, result, Imgproc.TM_CCOEFF_NORMED);
    Imgproc.threshold(result, result, threshold, 255, Imgproc.THRESH_TOZERO);

    List<Point> centers = new ArrayList<>();
    Set<Rect> foundCenterFor = new HashSet<>();

    while (true) {
        Core.MinMaxLocResult minMaxLocResult = Core.minMaxLoc(result);
        if (minMaxLocResult.maxVal > threshold) {
            Point maxLoc = minMaxLocResult.maxLoc;
            Optional<Rect> containingRect = getPointContainingRect(maxLoc, elementRectangles);

            if (containingRect.isPresent() && !foundCenterFor.contains(containingRect.get())) {
                centers.add(new Point(maxLoc.x + fullNoteHeadMat.width() / 2, maxLoc.y + fullNoteHeadMat.height() / 2));
                foundCenterFor.add(containingRect.get());
            }
            Imgproc.floodFill(result, new Mat(), minMaxLocResult.maxLoc, new Scalar(0));
        } else {
            break;
        }
    }
    return centers;
}

答案 2 :(得分:1)

尝试使用Chamfer based distance transform转换来查找点的中心。算法将图像传递2次以计算每个对象像素到最近边距的距离。对象的中心点将是指定距离最大的对象。