boofcv.alg.segmentation.ImageSegmentationOps 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;
import boofcv.alg.InputSanityCheck;
import boofcv.alg.misc.ImageMiscOps;
import boofcv.struct.image.GrayS32;
import boofcv.struct.image.GrayU8;
import org.ddogleg.struct.GrowQueue_I32;
import java.util.Arrays;
/**
* Useful functions related to image segmentation
*
* @author Peter Abeles
*/
public class ImageSegmentationOps {
/**
* Counts the number of instances of 'which' inside the labeled image.
*
* @param labeled Image which has been labeled
* @param which The label being searched for
* @return Number of instances of 'which' in 'labeled'
*/
public static int countRegionPixels(GrayS32 labeled , int which ) {
int total = 0;
for( int y = 0; y < labeled.height; y++ ) {
int index = labeled.startIndex + y*labeled.stride;
for( int x = 0; x < labeled.width; x++ ) {
if( labeled.data[index++] == which ) {
total++;
}
}
}
return total;
}
/**
* Counts the number of pixels in all regions. Regions must be have labels from 0 to totalRegions-1.
*
* @param labeled (Input) labeled image
* @param totalRegions Total number of regions
* @param counts Storage for pixel counts
*/
public static void countRegionPixels(GrayS32 labeled , int totalRegions , int counts[] ) {
Arrays.fill(counts,0,totalRegions,0);
for( int y = 0; y < labeled.height; y++ ) {
int index = labeled.startIndex + y*labeled.stride;
for( int x = 0; x < labeled.width; x++ ) {
counts[labeled.data[index++]]++;
}
}
}
/**
* Compacts the region labels such that they are consecutive numbers starting from 0.
* The ID of a root node must the index of a pixel in the 'graph' image, taking in account the change
* in coordinates for sub-images.
*
* @param graph Input segmented image where the ID's are not compacted
* @param segmentId List of segment ID's. See comment above about what ID's are acceptable.
* @param output The new image after it has been compacted
*/
public static void regionPixelId_to_Compact(GrayS32 graph, GrowQueue_I32 segmentId, GrayS32 output) {
InputSanityCheck.checkSameShape(graph,output);
// Change the label of root nodes to be the new compacted labels
for( int i = 0; i < segmentId.size; i++ ) {
graph.data[segmentId.data[i]] = i;
}
// In the second pass assign all the children to the new compacted labels
for( int y = 0; y < output.height; y++ ) {
int indexGraph = graph.startIndex + y*graph.stride;
int indexOut = output.startIndex + y*output.stride;
for( int x = 0; x < output.width; x++ , indexGraph++,indexOut++) {
output.data[indexOut] = graph.data[graph.data[indexGraph]];
}
}
// need to do some clean up since the above approach doesn't work for the roots
for( int i = 0; i < segmentId.size; i++ ) {
int indexGraph = segmentId.data[i] - graph.startIndex;
int x = indexGraph%graph.stride;
int y = indexGraph/graph.stride;
output.data[output.startIndex + y*output.stride + x] = i;
}
}
/**
* Indicates border pixels between two regions. If two adjacent pixels (4-connect) are not from the same region
* then both pixels are marked as true (value of 1) in output image, all other pixels are false (0).
*
* @param labeled Input segmented image.
* @param output Output binary image. 1 for border pixels.
*/
public static void markRegionBorders(GrayS32 labeled , GrayU8 output ) {
InputSanityCheck.checkSameShape(labeled,output);
ImageMiscOps.fill(output,0);
for( int y = 0; y < output.height-1; y++ ) {
int indexLabeled = labeled.startIndex + y*labeled.stride;
int indexOutput = output.startIndex + y*output.stride;
for( int x = 0; x < output.width-1; x++ , indexLabeled++ , indexOutput++ ) {
int region0 = labeled.data[indexLabeled];
int region1 = labeled.data[indexLabeled+1];
int region2 = labeled.data[indexLabeled+labeled.stride];
if( region0 != region1 ) {
output.data[indexOutput] = 1;
output.data[indexOutput+1] = 1;
}
if( region0 != region2 ) {
output.data[indexOutput] = 1;
output.data[indexOutput+output.stride] = 1;
}
}
}
for( int y = 0; y < output.height-1; y++ ) {
int indexLabeled = labeled.startIndex + y*labeled.stride + output.width-1;
int indexOutput = output.startIndex + y*output.stride + output.width-1;
int region0 = labeled.data[indexLabeled];
int region2 = labeled.data[indexLabeled+labeled.stride];
if( region0 != region2 ) {
output.data[indexOutput] = 1;
output.data[indexOutput+output.stride] = 1;
}
}
int y = output.height-1;
int indexLabeled = labeled.startIndex + y*labeled.stride;
int indexOutput = output.startIndex + y*output.stride;
for( int x = 0; x < output.width-1; x++ , indexLabeled++ , indexOutput++ ) {
int region0 = labeled.data[indexLabeled];
int region1 = labeled.data[indexLabeled+1];
if( region0 != region1 ) {
output.data[indexOutput] = 1;
output.data[indexOutput+1] = 1;
}
}
}
}