All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.gui.feature.AssociationScorePanel Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

The newest version!
/*
 * Copyright (c) 2011-2013, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.gui.feature;

import boofcv.abst.feature.associate.ScoreAssociation;
import georegression.struct.point.Point2D_F64;

import java.awt.*;
import java.awt.event.MouseListener;
import java.util.List;


/**
 * Displays relative association scores for different features.  When a feature is clicked on in
 * an image the best fit scores are show in the other image.
 *
 * @author Peter Abeles
 */
public class AssociationScorePanel
		extends CompareTwoImagePanel implements MouseListener  {
	// adjusts how close to the optimal answer a point needs to be before it is plotted
	double containmentFraction;

	// how big circles are drawn in association window
	int maxCircleRadius = 15;

	// left and right window information
	List leftDesc,rightDesc;
	double associationScore[];

	// computes association score
	ScoreAssociation scorer;

	// statistical information on score distribution
	int indexBest;
	double worst;
	double best;

	public AssociationScorePanel( double containmentFraction ) {
		super(20,false);
		if( containmentFraction <= 0  )
			throw new IllegalArgumentException("containmentFraction must be more than zero");
		this.containmentFraction = containmentFraction;
	}


	public void setScorer(ScoreAssociation scorer) {
		this.scorer = scorer;
	}

	public void setLocation(List leftPts , List rightPts ,
							List leftDesc, List rightDesc ) {
		setLocation(leftPts,rightPts);
		this.leftDesc = leftDesc;
		this.rightDesc = rightDesc;
	}

	protected void computeScore( boolean isTargetLeft , int targetIndex ) {
		int N = Math.max(leftPts.size(),rightPts.size());
		if( associationScore == null || associationScore.length < N ) {
			associationScore = new double[ N ];
		}
		if( isTargetLeft ) {
			D t = leftDesc.get(targetIndex);
			for( int i = 0; i < rightDesc.size(); i++ ) {
				D d = rightDesc.get(i);
				associationScore[i] = scorer.score(t,d);
			}
		} else {
			D t = rightDesc.get(targetIndex);
			for( int i = 0; i < leftDesc.size(); i++ ) {
				D d = leftDesc.get(i);
				associationScore[i] = scorer.score(t,d);
			}
		}
	}
	
	@Override
	protected void drawFeatures(Graphics2D g2,
							 double scaleLeft, int leftX, int leftY,
							 double scaleRight, int rightX, int rightY)
	{
		if( leftPts == null || rightPts == null ) {
			System.out.println("is null");
			return;
		}

		// draw all the found features in both images since nothing has been selected yet
		if( selected.isEmpty() ) {
			drawPoints(g2,leftPts,leftX,leftY,scaleLeft);
			drawPoints(g2,rightPts,rightX,rightY,scaleRight);
			return;
		} else if( selected.size() != 1 ) {
			System.err.println("Selected more than one feature!");
			return;
		}
		
		int selectedIndex = selected.get(0);
		
		// compute association score
		computeScore(selectedIsLeft,selectedIndex);

		// a feature has been selected.  In the image it was selected draw an X
		if( selectedIsLeft ) {
			drawCrossHair(g2,leftPts.get(selectedIndex),leftX,leftY,scaleLeft);
		} else {
			drawCrossHair(g2,rightPts.get(selectedIndex),rightX,rightY,scaleRight);
		}

		// draw circles of based on how similar a feature is to the selected one
		if( selectedIsLeft ) {
	   		drawDistribution(g2,rightPts,rightX,rightY,scaleRight);
		} else {
			drawDistribution(g2,leftPts,leftX,leftY,scaleLeft);
		}
	}

	/**
	 * Visualizes score distribution.  Larger circles mean its closer to the best
	 * fit score.
	 */
	private void drawDistribution( Graphics2D g2 , List candidates ,
					  int offX, int offY , double scale) {
		findStatistics();

		// draw all the features, adjusting their size based on the first score
		g2.setColor(Color.RED);
		g2.setStroke(new BasicStroke(3));

		double normalizer;
		if( scorer.getScoreType().isZeroBest() )
			normalizer = best*containmentFraction;
		else
			normalizer = Math.abs(best)*(Math.exp(-1.0/containmentFraction));

		for( int i = 0; i < candidates.size(); i++ ) {
			Point2D_F64 p = candidates.get(i);

			double s = associationScore[i];

			// scale the circle based on how bad it is
			double ratio = 1-Math.abs(s-best)/normalizer;
			if( ratio < 0 )
				continue;

			int r = maxCircleRadius - (int)(maxCircleRadius*ratio);
			if( r > 0 ) {
				int x = (int)(p.x*scale+offX);
				int y = (int)(p.y*scale+offY);
				g2.drawOval(x-r,y-r,r*2+1,r*2+1);
			}
		}

		// draw the best feature
		g2.setColor(Color.GREEN);
		g2.setStroke(new BasicStroke(10));
		int w = maxCircleRadius*2+1;
		Point2D_F64 p = candidates.get(indexBest);
		int x = (int)(p.x*scale+offX);
		int y = (int)(p.y*scale+offY);
		g2.drawOval(x-maxCircleRadius,y-maxCircleRadius,w,w);
	}

	private void drawPoints( Graphics2D g2 , List points ,
							 int startX , int startY , double scale ) {
		for( Point2D_F64 p : points ) {
			int x1 = (int)(scale*p.x)+startX;
			int y1 = (int)(scale*p.y)+startY;

			VisualizeFeatures.drawPoint(g2,x1,y1,Color.BLUE);
		}
	}

	private void drawCrossHair( Graphics2D g2 , Point2D_F64 target ,
								int startX , int startY , double scale) {

		int x = startX + (int)(target.x*scale);
		int y = startY + (int)(target.y*scale);

		int r = 10;
		g2.setColor(Color.BLACK);
		g2.setStroke(new BasicStroke(11));
		g2.drawLine(x-r,y,x+r,y);
		g2.drawLine(x,y-r,x,y+r);
		g2.setColor(Color.RED);
		g2.setStroke(new BasicStroke(5));
		g2.drawLine(x-r,y,x+r,y);
		g2.drawLine(x,y-r,x,y+r);
	}

	@Override
	protected boolean isValidPoint(int index) {
		return true;
	}

	private void findStatistics( ) {
		final int N = selectedIsLeft ? rightPts.size() : leftPts.size();

		indexBest = -1;
		worst = -Double.MAX_VALUE;
		best = Double.MAX_VALUE;
		for( int i = 0; i < N; i++ ) {
			double s = associationScore[i];
			if( s > worst )
				worst = s;
			if( s < best ) {
				best = s;
				indexBest = i;
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy