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

boofcv.alg.segmentation.ms.MergeRegionMeanShift Maven / Gradle / Ivy

/*
 * Copyright (c) 2011-2016, 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.alg.segmentation.ms;

import boofcv.struct.image.GrayS32;
import georegression.struct.point.Point2D_I32;
import org.ddogleg.struct.FastQueue;
import org.ddogleg.struct.GrowQueue_I32;

/**
 * Merges together regions which have modes close to each other and have a similar color.
 *
 * @author Peter Abeles
 */
public class MergeRegionMeanShift extends RegionMergeTree {

	// maximum distance squared in pixels that two nodes can be apart to be merged
	private int maxSpacialDistanceSq;
	// Maximum Euclidean distance squared two colors can be for them to be considered similar
	private float maxColorDistanceSq;

	// Search radius in pixels when looking for regions to merge with
	private int searchRadius;

	/**
	 * Configures MergeRegionMeanShift
	 *
	 * @param maxSpacialDistance The maximum spacial distance (pixels) at which two modes can be for their
	 *                           regions to be merged together.
	 * @param maxColorDistance The maximum Euclidean distance two colors can be from each other for them to be merged.
	 */
	public MergeRegionMeanShift(int maxSpacialDistance, float maxColorDistance ) {

		this.searchRadius = maxSpacialDistance;
		this.maxSpacialDistanceSq = maxSpacialDistance*maxSpacialDistance;
		this.maxColorDistanceSq = maxColorDistance*maxColorDistance;
	}

	/**
	 * Merges together similar regions which are in close proximity to each other.  After merging
	 * most of the input data structures are modified to take in account the  changes.
	 *
	 * @param pixelToRegion (Input/output) Image that specifies the segmentation.  Modified.
	 * @param regionMemberCount (Input/output) Number of pixels in each region. Modified.
	 * @param regionColor (Input/output) Color of each region. Modified.
	 * @param modeLocation (Input) Location of each region's mode. Not modified.
	 */
	public void process( GrayS32 pixelToRegion ,
						 GrowQueue_I32 regionMemberCount,
						 FastQueue regionColor ,
						 FastQueue modeLocation ) {
		initializeMerge(regionMemberCount.size);

		markMergeRegions(regionColor,modeLocation,pixelToRegion);

		performMerge(pixelToRegion, regionMemberCount);
	}

	/**
	 * Takes the mode of a region and searches the local area around it for other regions.  If the region's mode
	 * is also within the local area its color is checked to see if it's similar enough.  If the color is similar
	 * enough then the two regions are marked for merger.
	 */
	protected void markMergeRegions(FastQueue regionColor,
									FastQueue modeLocation,
									GrayS32 pixelToRegion  ) {
		for( int targetId = 0; targetId < modeLocation.size; targetId++ ) {

			float[] color = regionColor.get(targetId);
			Point2D_I32 location = modeLocation.get(targetId);

			int x0 = location.x-searchRadius;
			int x1 = location.x+searchRadius+1;
			int y0 = location.y-searchRadius;
			int y1 = location.y+searchRadius+1;

			// ensure that all pixels it examines are inside the image
			if( x0 < 0 ) x0 = 0;
			if( x1 > pixelToRegion.width ) x1 = pixelToRegion.width;
			if( y0 < 0 ) y0 = 0;
			if( y1 > pixelToRegion.height ) y1 = pixelToRegion.height;

			// look at the local neighborhood
			for( int y = y0; y < y1; y++ ) {
				for( int x = x0; x < x1; x++ ) {
					int candidateId = pixelToRegion.unsafe_get(x,y);

					// see if it is the same region
					if( candidateId == targetId )
						continue;

					// see if the mode is near by
					Point2D_I32 p = modeLocation.get(candidateId);
					if( p.distance2(location) <= maxSpacialDistanceSq ) {

						// see if the color is similar
						float[] candidateColor = regionColor.get(candidateId);
						float colorDistance = SegmentMeanShiftSearch.distanceSq(color,candidateColor);

						if( colorDistance <= maxColorDistanceSq ) {
							// mark the two regions as merged
							markMerge(targetId, candidateId);
						}
					}
				}
			}

		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy