001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 * image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause).
006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved.
007 * Visit https://imagingbook.com for additional details.
008 ******************************************************************************/
009package imagingbook.common.image;
010
011import ij.process.ByteProcessor;
012import ij.process.ColorProcessor;
013import ij.process.FloatProcessor;
014import ij.process.ImageProcessor;
015import ij.process.ShortProcessor;
016
017/**
018 * <p>
019 * This class implements horizontal and vertical projections of scalar-valued images. See Sec. 8.7 of [1] for additional
020 * details.
021 * </p>
022 * <p>
023 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing &ndash; An Algorithmic Introduction</em>, 3rd ed, Springer
024 * (2022).
025 * </p>
026 *
027 * @author WB
028 * @version 2022/09/28
029 */
030public class Projection {
031        
032        private final double[] pHor, pVer;
033
034        /**
035         * Constructor, works only on images of type {@link ByteProcessor}, {@link ShortProcessor}, and
036         * {@link FloatProcessor}. Throws an exception if the specified image is of type {@link ColorProcessor}.
037         *
038         * @param ip the image to process
039         */
040        public Projection(ImageProcessor ip) {
041                this.pHor = new double[ip.getHeight()];
042                this.pVer = new double[ip.getWidth()];
043                
044                if (ip instanceof ByteProcessor || ip instanceof ShortProcessor) {
045                        makeProjectionsInt(ip);
046                }
047
048                else if (ip instanceof FloatProcessor) {
049                        makeProjectionsFloat((FloatProcessor) ip);
050                }
051                else {
052                        throw new IllegalArgumentException("projections not implemented for ColorProcessor");
053                }
054        }
055
056        /**
057         * Returns the horizontal projection of the associated image. The length of the returned array corresponds to the
058         * image height.
059         *
060         * @return the horizontal projection array
061         */
062        public double[] getHorizontal() {
063                return this.pHor;
064        }
065
066        /**
067         * Returns the vertical projection of the associated image. The length of the returned array corresponds to the
068         * image width.
069         *
070         * @return the vertical projection array
071         */
072        public double[] getVertical() {
073                return this.pVer;
074        }
075        
076        // ----------------------------------------------------------
077        
078        private void makeProjectionsInt(ImageProcessor ip) {
079                long[] lHor = new long[pHor.length];
080                long[] lVer = new long[pVer.length];
081                for (int v = 0; v < pHor.length; v++) {
082                        for (int u = 0; u < pVer.length; u++) {
083                                long p = ip.get(u, v);
084                                lHor[v] +=  p;
085                                lVer[u] +=  p;
086                        }
087                }
088                copyArray(lHor, pHor);
089                copyArray(lVer, pVer);
090        }
091        
092        private void makeProjectionsFloat(FloatProcessor ip) {
093                for (int v = 0; v < pHor.length; v++) {
094                        for (int u = 0; u < pVer.length; u++) {
095                                double p = ip.getf(u, v);
096                                pHor[v] +=  p;
097                                pVer[u] +=  p;
098                        }
099                }
100        }
101
102        private void copyArray(long[] la, double[] da) {
103                for (int i = 0; i < la.length; i++) {
104                        da[i] = la[i];
105                }
106        }
107
108}