boofcv.alg.segmentation.ms.MergeRegionMeanShift Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of feature Show documentation
Show all versions of feature Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
/*
* 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);
}
}
}
}
}
}
}