Example #1
0
  /**
   * Try to recognize a clef in the compound of the provided glyphs.
   *
   * @param glyphs the parts of a clef candidate
   * @param staff the containing staff
   * @return true if successful
   */
  private boolean checkClef(Collection<Glyph> glyphs, StaffInfo staff) {
    if (glyphs.isEmpty()) {
      return false;
    }

    // Check if we already have a clef among the intersected glyphs
    Set<Glyph> clefs = Glyphs.lookupGlyphs(glyphs, clefGlyphPredicate);
    Glyph orgClef = null;

    if (!clefs.isEmpty()) {
      if (Glyphs.containsManual(clefs)) {
        return false; // Respect user decision
      } else {
        // Remember grade of the best existing clef
        for (Glyph glyph : clefs) {
          if ((orgClef == null) || (glyph.getGrade() > orgClef.getGrade())) {
            orgClef = glyph;
          }
        }
      }
    }

    // Remove potential aliens
    Glyphs.purgeManuals(glyphs);

    Glyph compound = system.buildTransientCompound(glyphs);

    // Check if a clef appears in the top evaluations
    Evaluation vote =
        GlyphNetwork.getInstance().vote(compound, system, Grades.clefMinGrade, clefShapePredicate);

    if ((vote != null) && ((orgClef == null) || (vote.grade > orgClef.getGrade()))) {
      // We now have a clef!
      // Look around for an even better result...
      logger.debug("{} built from {}", vote.shape, Glyphs.toString(glyphs));

      // Look for larger stuff
      Rectangle outer = compound.getBounds();
      outer.grow(xMargin, yMargin);

      // Remember the box, for visual debug
      staff.addAttachment("co", outer);

      List<Glyph> outerGlyphs = system.lookupIntersectedGlyphs(outer);
      outerGlyphs.removeAll(glyphs);
      Collections.sort(outerGlyphs, Glyph.byReverseWeight);

      final double minWeight = constants.minWeight.getValue();

      for (Glyph g : outerGlyphs) {
        // Consider only glyphs with a minimum weight
        if (g.getNormalizedWeight() < minWeight) {
          break;
        }

        logger.debug("Considering {}", g);

        Glyph newCompound = system.buildTransientCompound(Arrays.asList(compound, g));
        final Evaluation newVote =
            GlyphNetwork.getInstance()
                .vote(newCompound, system, Grades.clefMinGrade, clefShapePredicate);

        if ((newVote != null) && (newVote.grade > vote.grade)) {
          logger.debug("{} better built with {}", vote, g.idString());

          compound = newCompound;
          vote = newVote;
        }
      }

      // Register the last definition of the clef
      compound = system.addGlyph(compound);
      compound.setShape(vote.shape, Evaluation.ALGORITHM);

      logger.debug("{} rebuilt as {}", vote.shape, compound.idString());

      return true;
    } else {
      return false;
    }
  }
  /**
   * From the list of vertical sticks, this method uses several tests to provide the initial
   * collection of good barlines candidates.
   *
   * @param sticks the collection of candidate sticks
   */
  public void checkCandidates(Collection<? extends Glyph> sticks) {
    //        // Sort candidates according to their abscissa
    //        List<Glyph> sortedSticks = new ArrayList<Glyph>(sticks);
    //        Collections.sort(sortedSticks, Glyph.midPosComparator);
    double minResult = constants.minCheckResult.getValue();

    // Check each candidate stick in turn
    for (Glyph stick : sticks) {
      // Allocate the candidate context, and pass the whole check suite
      GlyphContext context = new GlyphContext(stick);

      double res = suite.pass(context);

      if (logger.isDebugEnabled() || stick.isVip()) {
        logger.info(
            "suite => {}{} for {}",
            (float) res,
            (stick.getResult() != null) ? (" " + stick.getResult()) : "",
            stick);
      }

      if ((stick.isBar() && stick.isManualShape()) || res >= minResult) {
        // OK, we flag this candidate with proper barline shape
        contexts.put(stick, context);
        if ((!stick.isBar() || !stick.isManualShape())) {
          stick.setShape(isThickBar(stick) ? Shape.THICK_BARLINE : Shape.THIN_BARLINE);
        }

        // Additional processing for Bars that define a system or a part
        // (they start AND end with precise staves horizontal limits)
        if ((context.topStaff != -1) && (context.botStaff != -1)) {
          // Here, we have both part & system defining bars
          // System bars occur first
          // (since glyphs are sorted by increasing abscissa)
          stick.setResult(BAR_PART_DEFINING);

          logger.debug(
              "Part-defining Barline from staff {} to staff {} {}",
              context.topStaff,
              context.botStaff,
              stick);
        } else {
          if (logger.isDebugEnabled()) {
            logger.debug(
                "Non-Part-defining Bar line {}{}",
                (context.topStaff != -1) ? (" topIdx=" + context.topStaff) : "",
                (context.botStaff != -1) ? (" botIdx=" + context.botStaff) : "");
          }

          stick.setResult(BAR_NOT_PART_DEFINING);
        }
      } else {
        if (stick.isBar()) {
          if (logger.isDebugEnabled() || stick.isVip()) {
            logger.info("Purged {} {}", stick.idString(), stick.getShape());
          }

          stick.setShape(null);
        }
      }
    }
  }
  /**
   * In a specified system, look for all stems that should not be kept, rebuild surrounding glyphs
   * and try to recognize them. If this action does not lead to some recognized symbol, then we
   * restore the stems.
   *
   * @return the number of symbols recognized
   */
  public int runStemPattern() {
    int nb = 0;

    // Collect all undue stems
    List<Glyph> SuspectedStems = new ArrayList<Glyph>();

    for (Glyph glyph : system.getGlyphs()) {
      if (glyph.isStem() && glyph.isActive()) {
        Set<Glyph> goods = new HashSet<Glyph>();
        Set<Glyph> bads = new HashSet<Glyph>();
        glyph.getSymbolsBefore(reliableStemSymbols, goods, bads);
        glyph.getSymbolsAfter(reliableStemSymbols, goods, bads);

        if (goods.isEmpty()) {
          if (logger.isFineEnabled()) {
            logger.finest("Suspected Stem " + glyph);
          }

          SuspectedStems.add(glyph);

          // Discard "bad" ones
          for (Glyph g : bads) {
            if (logger.isFineEnabled()) {
              logger.finest("Deassigning bad glyph " + g);
            }

            g.setShape((Shape) null);
          }
        }
      }
    }

    // Remove these stem glyphs since nearby stems are used for recognition
    for (Glyph glyph : SuspectedStems) {
      system.removeGlyph(glyph);
    }

    // Extract brand new glyphs (removeInactiveGlyphs + retrieveGlyphs)
    system.extractNewGlyphs();

    // Try to recognize each glyph in turn
    List<Glyph> symbols = new ArrayList<Glyph>();
    final GlyphEvaluator evaluator = GlyphNetwork.getInstance();
    final double maxDoubt = GlyphInspector.getPatternsMaxDoubt();

    for (Glyph glyph : system.getGlyphs()) {
      if (glyph.getShape() == null) {
        Evaluation vote = evaluator.vote(glyph, maxDoubt);

        if (vote != null) {
          glyph.setShape(vote.shape, vote.doubt);

          if (glyph.isWellKnown()) {
            if (logger.isFineEnabled()) {
              logger.finest("New symbol " + glyph);
            }

            symbols.add(glyph);
            nb++;
          }
        }
      }
    }

    // Keep stems that have not been replaced by symbols, definitively
    // remove the others
    for (Glyph stem : SuspectedStems) {
      // Check if one of its section is now part of a symbol
      boolean known = false;
      Glyph glyph = null;

      for (GlyphSection section : stem.getMembers()) {
        glyph = section.getGlyph();

        if ((glyph != null) && glyph.isWellKnown()) {
          known = true;

          break;
        }
      }

      if (!known) {
        // Remove the newly created glyph
        if (glyph != null) {
          system.removeGlyph(glyph);
        }

        // Restore the stem
        system.addGlyph(stem);
      }
    }

    return nb;
  }