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-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.pub.matching;
011import ij.process.ByteProcessor;
012import imagingbook.pub.matching.DistanceTransform.Norm;
013
014import java.awt.Point;
015
016/**
017 * This class performs chamfer matching on binary images.
018 * @author W. Burger
019 * @version 2014-04-20
020 */
021public class ChamferMatcher {
022        
023        private final ByteProcessor I;
024        private final int MI, NI;
025        private final float[][] D;                              // distance transform of I
026        
027        public ChamferMatcher(ByteProcessor I) {
028                this(I, Norm.L2);
029        }
030        
031        public ChamferMatcher(ByteProcessor I, Norm norm) {
032                this.I = I;
033                this.MI = this.I.getWidth();
034                this.NI = this.I.getHeight();
035                this.D = (new DistanceTransform(I, norm)).getDistanceMap();
036        }
037        
038        public float[][] getMatch(ByteProcessor R) {
039                final int MR = R.getWidth();
040                final int NR = R.getHeight();
041                final int[][] Ra = R.getIntArray();
042                float[][] Q = new float[MI - MR + 1][NI - NR + 1];
043                for (int r = 0; r <= MI - MR; r++) {
044                        for (int s = 0; s <= NI - NR; s++) {
045                                float q = getMatchValue(Ra, r, s);
046                                Q[r][s] = q;
047                        }       
048                }       
049                return Q;
050        }
051
052        private float getMatchValue(int[][] R, int r, int s) {
053                float q = 0.0f;
054                for (int i = 0; i < R.length; i++) {
055                        for (int j = 0; j < R[i].length; j++) {
056                                if (R[i][j] > 0) {      // foreground pixel in reference image
057                                        q = q + D[r + i][s + j];
058                                }
059                        }
060                }
061                return q;
062        }       
063        
064        public float[][] getMatch(Point[] points, int width, int height) {
065                float[][] Q = new float[width][height];
066                for (int r = 0; r <= width; r++) {
067                        for (int s = 0; s <= height; s++) {
068                                float q = getMatchValue(points, r, s);
069                                Q[r][s] = q;
070                        }       
071                }       
072                return Q;
073        }
074        
075        private float getMatchValue(Point[] points, int r, int s) {
076                float q = 0.0f;
077                for (Point p : points) {
078                        final int u = r + p.x;
079                        final int v = s + p.y;
080                        if (0 <= u && u < MI && 0 <= v && v < NI) {
081                                q = q + D[u][v];
082                        }
083                }
084                return q;
085        }
086
087}