omr.sheet.ScaleBuilder.java Source code

Java tutorial

Introduction

Here is the source code for omr.sheet.ScaleBuilder.java

Source

//----------------------------------------------------------------------------//
//                                                                            //
//                          S c a l e B u i l d e r                           //
//                                                                            //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr">                          //
//  Copyright (C) Herve Bitteur 2000-2010. All rights reserved.               //
//  This software is released under the GNU General Public License.           //
//  Goto http://kenai.com/projects/audiveris to report bugs or suggestions.   //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.sheet;

import omr.Main;

import omr.constant.Constant;
import omr.constant.ConstantSet;

import omr.lag.RunsBuilder;

import omr.log.Logger;

import omr.sheet.picture.Picture;

import omr.step.StepException;

import omr.util.Implement;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RefineryUtilities;

import java.awt.Rectangle;

import javax.swing.WindowConstants;

/**
 * Class <code>ScaleBuilder</code> encapsulates the computation of a sheet
 * scale. This is kept separate from the simple <code>Scale</code> class, to
 * save the loading of this when computation is not required.
 *
 * @see omr.sheet.Scale
 *
 * @author Herv Bitteur
 */
public class ScaleBuilder {
    //~ Static fields/initializers ---------------------------------------------

    /** Specific application parameters */
    private static final Constants constants = new Constants();

    /** Usual logger utility */
    private static final Logger logger = Logger.getLogger(ScaleBuilder.class);

    //~ Instance fields --------------------------------------------------------

    /** Adapter for reading runs */
    private Adapter adapter;

    /** Related sheet */
    private Sheet sheet;

    /** Most frequent background vertical run */
    private int mainBack = -1;

    /**
     * Most frequent run lengths for foreground & background runs as read from
     * the sheet picture. They are initialized to -1, so as to detect if they
     * have been computed or not.
     */
    private int mainFore = -1;

    //~ Constructors -----------------------------------------------------------

    //--------------//
    // ScaleBuilder //
    //--------------//
    /**
     * (package private) constructor, to enable scale computation on a given
     * sheet
     *
     * @param sheet the sheet at hand
     */
    ScaleBuilder(Sheet sheet) {
        this.sheet = sheet;
    }

    //~ Methods ----------------------------------------------------------------

    //--------------//
    // displayChart //
    //--------------//
    /**
     * Build and display the scale histogram
     */
    public void displayChart() {
        if (adapter != null) {
            adapter.writePlot();
        } else {
            logger.warning("No scale adapter available");
        }
    }

    //-------------//
    // getMainBack //
    //-------------//
    /**
     * A (package private) lazy method to retrieve the main length of background
     * runs of pixels
     *
     * @return the main back length
     * @throws StepException
     */
    int getMainBack() throws StepException {
        if (mainBack == -1) {
            retrieveScale();
        }

        if (mainBack == -1) {
            logger.warning("Unable to retrieve white runs, check your image format");
            throw new StepException("Illegal background values");
        }

        return mainBack;
    }

    //-------------//
    // getMainFore //
    //-------------//
    /**
     * A (package private) lazy method to retrieve the main length of foreground
     * runs of pixels
     *
     * @return the main fore length
     * @throws StepException
     */
    int getMainFore() throws StepException {
        if (mainFore == -1) {
            retrieveScale();
        }

        if (mainFore == -1) {
            logger.warning("Unable to retrieve black runs, check your image format");
            throw new StepException("Illegal foreground values");
        }

        return mainFore;
    }

    //---------------//
    // retrieveScale //
    //---------------//
    /**
     * Create a scale entity, by processing the provided sheet picture.
     */
    private void retrieveScale() {
        Picture picture = sheet.getPicture();
        adapter = new Adapter(sheet, picture.getHeight() - 1);

        // Read the picture runs
        RunsBuilder runsBuilder = new RunsBuilder(adapter);
        runsBuilder.createRuns(new Rectangle(0, 0, picture.getHeight(), picture.getWidth()));

        logger.info("Scale black is " + mainFore + ", white is " + mainBack + ", interline is "
                + (mainFore + mainBack));

        // Check picture resolution
        if ((mainFore + mainBack) < constants.minInterline.getValue()) {
            String msg = "With only " + (mainFore + mainBack) + " pixels between two staff lines,"
                    + " your picture resolution is too low!"
                    + "\nPlease rescan at higher resolution (300dpi should be OK)";

            logger.warning(msg);

            if (Main.getGui() != null) {
                Main.getGui().displayWarning(msg);
            }
        }
    }

    //~ Inner Classes ----------------------------------------------------------

    //---------//
    // Adapter //          Needed for createRuns
    //---------//
    private class Adapter implements RunsBuilder.Reader {
        //~ Instance fields ----------------------------------------------------

        private Picture picture;
        private Sheet sheet;
        private int[] back;
        private int[] fore;
        private int maxForeground;

        //~ Constructors -------------------------------------------------------

        //---------//
        // Adapter //
        //---------//
        public Adapter(Sheet sheet, int hMax) {
            this.sheet = sheet;
            this.picture = sheet.getPicture();

            maxForeground = sheet.getMaxForeground();

            // Allocate histogram counters
            fore = new int[hMax + 2];
            back = new int[hMax + 2];

            for (int i = fore.length - 1; i >= 0; i--) {
                fore[i] = 0;
                back[i] = 0;
            }
        }

        //~ Methods ------------------------------------------------------------

        //--------//
        // isFore //
        //--------//
        @Implement(RunsBuilder.Reader.class)
        public boolean isFore(int level) {
            // Assuming black=0, white=255
            return level <= maxForeground;
        }

        //----------//
        // getLevel //
        //----------//
        @Implement(RunsBuilder.Reader.class)
        public int getLevel(int coord, int pos) {
            return picture.getPixel(pos, coord); // swap pos & coord
        }

        //---------//
        // backRun //
        //---------//
        @Implement(RunsBuilder.Reader.class)
        public void backRun(int w, int h, int length) {
            back[length]++;
        }

        //---------//
        // foreRun //
        //---------//
        @Implement(RunsBuilder.Reader.class)
        public void foreRun(int w, int h, int length, int cumul) {
            fore[length]++;
        }

        //-----------//
        // terminate //
        //-----------//
        @Implement(RunsBuilder.Reader.class)
        public void terminate() {
            // Determine the biggest buckets
            int maxFore = 0;
            int maxBack = 0;

            for (int i = fore.length - 1; i >= 0; i--) {
                if (fore[i] > maxFore) {
                    maxFore = fore[i];
                    mainFore = i;
                }

                if (back[i] > maxBack) {
                    maxBack = back[i];
                    mainBack = i;
                }
            }

            // Print plot if needed
            if (constants.plotting.getValue()) {
                writePlot();
            }
        }

        //-----------//
        // writePlot //
        //-----------//
        public void writePlot() {
            XYSeriesCollection dataset = new XYSeriesCollection();
            int upper = Math.min(fore.length, mainBack + (mainBack / 2));

            // Foreground
            XYSeries foreSeries = new XYSeries("Foreground" + " [" + mainFore + "]");

            for (int i = 0; i < upper; i++) {
                foreSeries.add(i, fore[i]);
            }

            dataset.addSeries(foreSeries);

            // Background
            XYSeries backSeries = new XYSeries("Background" + " [" + mainBack + "]");

            for (int i = 0; i < upper; i++) {
                backSeries.add(i, back[i]);
            }

            dataset.addSeries(backSeries);

            // Chart
            JFreeChart chart = ChartFactory.createXYLineChart(sheet.getRadix() + " (Run Lengths)", // Title
                    "Lengths", // X-Axis label
                    "Numbers", // Y-Axis label
                    dataset, // Dataset
                    PlotOrientation.VERTICAL, // orientation,
                    true, // Show legend
                    false, // Show tool tips
                    false // urls
            );

            // Hosting frame
            ChartFrame frame = new ChartFrame(sheet.getRadix() + " - Runs", chart, true);
            frame.pack();
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            RefineryUtilities.centerFrameOnScreen(frame);
            frame.setVisible(true);
        }
    }

    //-----------//
    // Constants //
    //-----------//
    private static final class Constants extends ConstantSet {
        //~ Instance fields ----------------------------------------------------

        /** Should we produce a chart on computed scale data ? */
        Constant.Boolean plotting = new Constant.Boolean(false,
                "Should we produce a chart on computed scale data ?");

        /** Minimum number of pixels per interline */
        Constant.Integer minInterline = new Constant.Integer("Pixels", 15,
                "Minimum number of pixels per interline");
    }
}