/* * 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.fh04; import boofcv.alg.misc.ImageMiscOps; import boofcv.alg.segmentation.fh04.impl.FhEdgeWeights4_U8; import boofcv.struct.image.GrayS32; import boofcv.struct.image.GrayU8; import boofcv.testing.BoofTesting; import org.ddogleg.struct.GrowQueue_I32; import org.junit.Test; import java.util.Collections; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestSegmentFelzenszwalbHuttenlocher04 { Random rand = new Random(234); /** * Test it on a trivial segmentation problem */ @Test public void process() { GrayU8 image = new GrayU8(20,25); ImageMiscOps.fillRectangle(image,100,0,0,10,25); GrayS32 output = new GrayS32(20,25); // normal images process(image, output); // sub-images process(BoofTesting.createSubImageOf(image), output); } private void process(GrayU8 image, GrayS32 output) { ImageMiscOps.fillUniform(output,rand,0,100); FhEdgeWeights<GrayU8> edgeWeights = new FhEdgeWeights4_U8(); SegmentFelzenszwalbHuttenlocher04<GrayU8> alg = new SegmentFelzenszwalbHuttenlocher04<>(200,10,edgeWeights); alg.process(image,output); int valA = output.get(0,0); int valB = output.get(19,0); assertTrue(valA != valB); for( int y = 0; y < 25; y++ ) { for( int x =0; x < 10; x++ ) assertEquals(valA, output.get(x, y)); for( int x =10; x < 20; x++ ) assertEquals(valB,output.get(x,y)); } } @Test public void mergeRegions() { // K is zero to make it easier to figure out if two edges should be merged or not SegmentFelzenszwalbHuttenlocher04 alg = new SegmentFelzenszwalbHuttenlocher04(0,10,null); // add edges. Design it such that order is important and to make sure the equality checks // are done correctly alg.edges.add( edge(1, 0, 20)); alg.edges.add( edge(2, 0, 25)); alg.edges.add( edge(14, 0, 40)); alg.edges.add( edge(3,4,20)); alg.edges.add( edge(5,4,20)); alg.edges.add( edge(10,11,20)); alg.edges.add( edge(12,11,5)); alg.edges.add( edge(13,11,5)); // randomize their order Collections.shuffle(alg.edges.toList(),rand); // NOTE the order after sorting is undefined. So the checks below could be incorrect if they are processed // in a different order alg.graph = new GrayS32(4,5); alg.graph.data = new int[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11, 12,13,14,15, 16,17,18,19}; alg.regionSize.reset(); alg.threshold.reset(); for( int i = 0; i < 20; i++ ) { alg.regionSize.add(i); alg.threshold.add(1000); // high value so that all first matches are accepted } // make sure that the regions are merged correctly alg.mergeRegions(); // check the graph assertEquals(1,alg.graph.data[0]); assertEquals(1,alg.graph.data[1]); assertEquals(2,alg.graph.data[2]); assertEquals(5,alg.graph.data[3]); assertEquals(5,alg.graph.data[4]); assertEquals(5,alg.graph.data[5]); assertEquals(10,alg.graph.data[10]); assertEquals(13,alg.graph.data[11]); assertEquals(13,alg.graph.data[12]); assertEquals(13,alg.graph.data[13]); assertEquals(14,alg.graph.data[14]); // see if thresholds were updated as expected assertEquals(20,alg.threshold.data[1],1e-4f); assertEquals(20,alg.threshold.data[5],1e-4f); assertEquals(1000,alg.threshold.data[10],1e-4f); assertEquals(5,alg.threshold.data[13],1e-4f); assertEquals(1000,alg.threshold.data[14],1e-4f); // ditto for size assertEquals(1,alg.regionSize.data[1]); assertEquals(2,alg.regionSize.data[2]); assertEquals(12,alg.regionSize.data[5]); assertEquals(10,alg.regionSize.data[10]); assertEquals(11+12+13,alg.regionSize.data[13]); assertEquals(14, alg.regionSize.data[14]); } @Test public void mergeSmallRegions() { SegmentFelzenszwalbHuttenlocher04 alg = new SegmentFelzenszwalbHuttenlocher04(0,10,null); alg.regionSize.resize(20); alg.regionSize.set(2, 10); alg.regionSize.set(5, 20); alg.regionSize.set(15, 9); // regions: 2,5,15 alg.graph = new GrayS32(4,5); alg.graph.data = new int[]{ 2, 0, 2, 5, 3, 5, 4, 6, 2, 2, 2, 1, 15,15,15,15, 15,15,15,15}; alg.edgesNotMatched.add( new SegmentFelzenszwalbHuttenlocher04.Edge(1,5)); alg.edgesNotMatched.add( new SegmentFelzenszwalbHuttenlocher04.Edge(12,8)); alg.mergeSmallRegions(); // see if the regions were merged assertEquals(15,alg.find(15)); assertEquals(15, alg.find(2)); assertEquals(5,alg.find(5)); } @Test public void find() { SegmentFelzenszwalbHuttenlocher04 alg = new SegmentFelzenszwalbHuttenlocher04(300,20,null); alg.graph = new GrayS32(4,5); alg.graph.data = new int[]{ 2, 0, 2, 5, 3, 5, 4, 6, 2, 2, 2, 1, 15,15,15,15, 15,15,15,15}; assertEquals(2, alg.find(11)); assertEquals(2,alg.graph.data[11]); assertEquals(0,alg.graph.data[1]); assertEquals(2,alg.find(2)); } @Test public void computeOutput() { SegmentFelzenszwalbHuttenlocher04 alg = new SegmentFelzenszwalbHuttenlocher04(300,20,null); alg.graph = new GrayS32(4,5); alg.graph.data = new int[]{ 2, 0, 2, 5, 3, 5, 4, 6, 2, 2, 2, 1, 15,15,15,15, 15,15,15,15}; for( int i = 0; i < alg.graph.data.length; i++ ) alg.regionSize.add(i+1); alg.computeOutput(); GrowQueue_I32 regionId = alg.getRegionId(); assertEquals(3,regionId.size); assertEquals(2,regionId.get(0)); assertEquals(5,regionId.get(1)); assertEquals(15,regionId.get(2)); GrowQueue_I32 outputRegionSize = alg.getRegionSizes(); assertEquals(3,outputRegionSize.size); assertEquals(3,outputRegionSize.get(0)); assertEquals(6,outputRegionSize.get(1)); assertEquals(16,outputRegionSize.get(2)); GrayS32 expected = new GrayS32(4,5); expected.data = new int[]{ 2, 2, 2, 5, 5, 5, 5, 5, 2, 2, 2, 2, 15,15,15,15, 15,15,15,15}; BoofTesting.assertEquals(expected, alg.graph, 1e-4); } private SegmentFelzenszwalbHuttenlocher04.Edge edge( int indexA , int indexB , float weight ) { SegmentFelzenszwalbHuttenlocher04.Edge e = new SegmentFelzenszwalbHuttenlocher04.Edge(); e.indexA = indexA; e.indexB = indexB; e.sortValue = weight; return e; } }