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

boofcv.alg.segmentation.ImageSegmentationOps 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;

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;
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy