001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj.image;
009
010import edu.wpi.first.wpilibj.util.SortedVector;
011import com.ni.vision.NIVision;
012
013/**
014 * An image where each pixel is treated as either on or off.
015 *
016 * @author dtjones
017 */
018public class BinaryImage extends MonoImage {
019    private int numParticles = -1;
020
021    BinaryImage() throws NIVisionException {
022    }
023
024    BinaryImage(BinaryImage sourceImage) {
025        super(sourceImage);
026    }
027
028    /**
029     * Returns the number of particles.
030     *
031     * @return The number of particles
032     */
033    public int getNumberParticles() throws NIVisionException {
034        if (numParticles < 0)
035            numParticles = NIVision.imaqCountParticles(image, 1);
036        return numParticles;
037    }
038
039
040    private class ParticleSizeReport {
041        final int index;
042        final double size;
043
044        public ParticleSizeReport(int index) throws NIVisionException {
045            if ((!(index < BinaryImage.this.getNumberParticles())) || index < 0)
046                throw new IndexOutOfBoundsException();
047            this.index = index;
048            size = ParticleAnalysisReport.getParticleToImagePercent(BinaryImage.this, index);
049        }
050
051        public ParticleAnalysisReport getParticleAnalysisReport() throws NIVisionException {
052            return new ParticleAnalysisReport(BinaryImage.this, index);
053        }
054    }
055
056    /**
057     * Get a particle analysis report for the particle at the given index.
058     *
059     * @param index The index of the particle to report on.
060     * @return The ParticleAnalysisReport for the particle at the given index
061     */
062    public ParticleAnalysisReport getParticleAnalysisReport(int index) throws NIVisionException {
063        if (!(index < getNumberParticles())) throw new IndexOutOfBoundsException();
064        return new ParticleAnalysisReport(this, index);
065    }
066
067    /**
068     * Gets all the particle analysis reports ordered from largest area to smallest.
069     *
070     * @param size The number of particles to return
071     * @return An array of ParticleReports from largest area to smallest
072     */
073    public ParticleAnalysisReport[] getOrderedParticleAnalysisReports(int size) throws NIVisionException {
074        if (size > getNumberParticles())
075            size = getNumberParticles();
076        ParticleSizeReport[] reports = new ParticleSizeReport[size];
077        SortedVector sorter = new SortedVector(new SortedVector.Comparator() {
078            public int compare(Object object1, Object object2) {
079                ParticleSizeReport p1 = (ParticleSizeReport) object1;
080                ParticleSizeReport p2 = (ParticleSizeReport) object2;
081                if (p1.size < p2.size)
082                    return -1;
083                else if (p1.size > p2.size)
084                    return 1;
085                return 0;
086            }
087        });
088        for (int i = 0; i < getNumberParticles(); i++)
089            sorter.addElement(new ParticleSizeReport(i));
090        sorter.setSize(size);
091        sorter.copyInto(reports);
092        ParticleAnalysisReport[] finalReports = new ParticleAnalysisReport[reports.length];
093        for (int i = 0; i < finalReports.length; i++)
094            finalReports[i] = reports[i].getParticleAnalysisReport();
095        return finalReports;
096    }
097
098    /**
099     * Gets all the particle analysis reports ordered from largest area to smallest.
100     *
101     * @return An array of ParticleReports from largest are to smallest
102     */
103    public ParticleAnalysisReport[] getOrderedParticleAnalysisReports() throws NIVisionException {
104        return getOrderedParticleAnalysisReports(getNumberParticles());
105    }
106
107
108    public void write(String fileName) throws NIVisionException {
109        NIVision.RGBValue colorTable = new NIVision.RGBValue(0, 0, 255, 0);
110        try {
111            NIVision.imaqWriteFile(image, fileName, colorTable);
112        } finally {
113            colorTable.free();
114        }
115    }
116
117    /**
118     * removeSmallObjects filters particles based on their size.
119     * The algorithm erodes the image a specified number of times and keeps the
120     * particles from the original image that remain in the eroded image.
121     *
122     * @param connectivity8 true to use connectivity-8 or false for connectivity-4 to determine
123     *                      whether particles are touching. For more information about connectivity, see Chapter 9,
124     *                      Binary Morphology, in the NI Vision Concepts manual.
125     * @param erosions      the number of erosions to perform
126     * @return a BinaryImage after applying the filter
127     * @throws NIVisionException
128     */
129    public BinaryImage removeSmallObjects(boolean connectivity8, int erosions) throws NIVisionException {
130        BinaryImage result = new BinaryImage();
131        NIVision.imaqSizeFilter(result.image, image, connectivity8 ? 1 : 0, erosions, NIVision.SizeType.KEEP_LARGE, null);
132        result.free();
133        return result;
134    }
135
136    /**
137     * removeLargeObjects filters particles based on their size.
138     * The algorithm erodes the image a specified number of times and discards the
139     * particles from the original image that remain in the eroded image.
140     *
141     * @param connectivity8 true to use connectivity-8 or false for connectivity-4 to determine
142     *                      whether particles are touching. For more information about connectivity, see Chapter 9,
143     *                      Binary Morphology, in the NI Vision Concepts manual.
144     * @param erosions      the number of erosions to perform
145     * @return a BinaryImage after applying the filter
146     * @throws NIVisionException
147     */
148    public BinaryImage removeLargeObjects(boolean connectivity8, int erosions) throws NIVisionException {
149        BinaryImage result = new BinaryImage();
150        NIVision.imaqSizeFilter(result.image, image, connectivity8 ? 1 : 0, erosions, NIVision.SizeType.KEEP_SMALL, null);
151        return result;
152    }
153
154    public BinaryImage convexHull(boolean connectivity8) throws NIVisionException {
155        BinaryImage result = new BinaryImage();
156        NIVision.imaqConvexHull(result.image, image, connectivity8 ? 1 : 0);
157        return result;
158    }
159
160    public BinaryImage particleFilter(NIVision.ParticleFilterCriteria2[] criteria) throws NIVisionException {
161        BinaryImage result = new BinaryImage();
162        NIVision.ParticleFilterOptions2 options = new NIVision.ParticleFilterOptions2(0, 0, 0, 1);
163        NIVision.imaqParticleFilter4(result.image, image, criteria, options, null);
164        options.free();
165        return result;
166    }
167}