def testSquareIncluded(self): # generate the image to be processed w, h = 2000, 2000 image = np.zeros((h, w), dtype=np.uint8) # locations of the 9 multi-squares positions = [(w // 7, h // 7), (3 * w // 7, h // 7), (5 * w // 7, h // 7), (w // 7, 3 * h // 7), (3 * w // 7, 3 * h // 7), (5 * w // 7, 3 * h // 7), (w // 7, 5 * h // 7), (3 * w // 7, 5 * h // 7), (5 * w // 7, 5 * h // 7)] for position in positions: image = draw_multisquare(image, position, w // 7, color_in=127) # Build workflow builder = SLDCWorkflowBuilder() # Build workflow 1 builder.set_segmenter(BigShapeSegmenter()) builder.add_catchall_classifier(DumbClassifier()) builder.set_tile_size(512, 512) workflow1 = builder.get() # Build workflow 2 builder.set_segmenter(SmallSquareSegmenter()) builder.add_catchall_classifier(DumbClassifier()) workflow2 = builder.get() # Build chaining chain_builder = WorkflowChainBuilder() chain_builder.set_first_workflow(workflow1, label="big_squares") chain_builder.add_executor(workflow2, label="small_squares") chain = chain_builder.get() # Launch chain_info = chain.process(NumpyImage(image)) # check results big_area = (w // 7)**2 small_area = (w / 35)**2 info1 = chain_info["big_squares"] self.assertEqual(9, len(info1)) for object_info in info1: self.assertTrue( relative_error(object_info.polygon.area, big_area) < 0.005) self.assertEqual("catchall", object_info.dispatch) self.assertEqual(1, object_info.label) self.assertAlmostEqual(1.0, object_info.proba) info2 = chain_info["small_squares"] self.assertEqual(36, len(info2)) for object_info in info2: self.assertTrue( relative_error(object_info.polygon.area, small_area) < 0.005) self.assertEqual("catchall", object_info.dispatch) self.assertEqual(1, object_info.label) self.assertAlmostEqual(1.0, object_info.proba)
def testSLDCWorkflowWithRuleDispatcher(self): # pre build components segmenter = DumbSegmenter() tile_builder = DefaultTileBuilder() dispatcher = DumbDispatcher() classifier1 = DumbClassifier() classifier2 = DumbClassifier() rule1 = DumbRule() rule2 = DumbRule() builder = SLDCWorkflowBuilder() builder.set_segmenter(segmenter) builder.set_tile_builder(tile_builder) builder.add_classifier(rule1, classifier1) builder.add_classifier(rule2, classifier2) with self.assertRaises(InvalidBuildingException): builder.set_one_shot_dispatcher(dispatcher, {"default": classifier1}) workflow = builder.get() self.assertIsInstance(workflow, SLDCWorkflow) self.assertEqual(len(workflow._dispatch_classifier._classifiers), 2) self.assertEqual(workflow._dispatch_classifier._classifiers[0], classifier1) self.assertEqual(workflow._dispatch_classifier._classifiers[1], classifier2) self.assertIsInstance(workflow._dispatch_classifier._dispatcher, RuleBasedDispatcher) self.assertEqual(len(workflow._dispatch_classifier._dispatcher._rules), 2) self.assertEqual(workflow._dispatch_classifier._dispatcher._rules[0], rule1) self.assertEqual(workflow._dispatch_classifier._dispatcher._rules[1], rule2)
def testDetectCircleParallel(self): """A test which executes a full workflow on image containing a white circle in the center of an black image in parallel """ # generate circle image w, h = 2000, 2000 image = np.zeros((w, h, 3), dtype="uint8") image = draw_circle(image, 750, (1000, 1000), [129, 129, 129]) # build workflow builder = SLDCWorkflowBuilder() builder.set_n_jobs(2) builder.set_segmenter(CircleSegmenter()) builder.add_catchall_classifier(CircleClassifier()) builder.set_parallel_dc(True) workflow = builder.get() # process image workflow_info = workflow.process(NumpyImage(image)) # Check results self.assertEqual(len(workflow_info.polygons), 1) # Check circle polygon = workflow_info.polygons[0] self.assertEqual( relative_error(polygon.area, np.pi * 750 * 750) <= 0.005, True) self.assertEqual( relative_error(polygon.centroid.x, 1000) <= 0.005, True) self.assertEqual( relative_error(polygon.centroid.y, 1000) <= 0.005, True) assert_array_equal(workflow_info.labels, [1]) assert_array_almost_equal(workflow_info.probas, [1.0]) assert_array_equal(workflow_info.dispatches, ["catchall"]) # check other information timing = workflow_info.timing self.assertEqual( timing.get_phases_hierarchy(), { "workflow.sldc": { "detect": { "load": None, "segment": None, "locate": None }, "merge": None, "dispatch_classify": { "dispatch": None, "classify": None } } })
def main(argv): with CytomineJob.from_cli(argv) as job: if not os.path.exists(job.parameters.working_path): os.makedirs(job.parameters.working_path) # create workflow component logger = StandardOutputLogger(Logger.INFO) random_state = check_random_state(int(job.parameters.rseed)) tile_builder = CytomineTileBuilder( working_path=job.parameters.working_path) segmenter = DemoSegmenter(job.parameters.threshold) area_rule = ValidAreaRule(job.parameters.min_area) classifier = PyxitClassifierAdapter.build_from_pickle( job.parameters.pyxit_model_path, tile_builder, logger, random_state=random_state, n_jobs=job.parameters.n_jobs, working_path=job.parameters.working_path) builder = SLDCWorkflowBuilder() builder.set_n_jobs(job.parameters.n_jobs) builder.set_logger(logger) builder.set_overlap(job.parameters.sldc_tile_overlap) builder.set_tile_size(job.parameters.sldc_tile_width, job.parameters.sldc_tile_height) builder.set_tile_builder(tile_builder) builder.set_segmenter(segmenter) builder.add_classifier(area_rule, classifier, dispatching_label="valid") workflow = builder.get() slide = CytomineSlide(job.parameters.cytomine_image_id) results = workflow.process(slide) # Upload results for polygon, label, proba, dispatch in results: if label is not None: # if image is a window, the polygon must be translated if isinstance(slide, ImageWindow): polygon = translate(polygon, slide.abs_offset_x, slide.abs_offset_y) # upload the annotation polygon = affine_transform( polygon, [1, 0, 0, -1, 0, slide.image_instance.height]) annotation = Annotation( location=polygon.wkt, id_image=slide.image_instance.id).save() AlgoAnnotationTerm(id_annotation=annotation.id, id_term=label, rate=float(proba)).save()
def testNoObjects(self): """Test detection on empty image""" w, h = 200, 200 image = np.zeros((h, w), dtype="uint8") builder = SLDCWorkflowBuilder() builder.set_segmenter(CustomSegmenter()) builder.add_classifier(CircleRule(), ColorClassifier(), dispatching_label="circle") builder.add_classifier(SquareRule(), ColorClassifier()) workflow = builder.get() # Execute results = workflow.process(NumpyImage(image)) self.assertEqual(len(results), 0)
def testWorkflowWithExcludedObjects(self): # generate circle image w, h = 300, 100 image = np.zeros((h, w,), dtype="uint8") image = draw_circle(image, 25, (100, 40), 255) # pi * 25 * 25 -> ~ 1963 image = draw_circle(image, 35, (200, 60), 255) # pi * 35 * 35 -> ~ 3858 # build the workflow builder = SLDCWorkflowBuilder() builder.set_segmenter(CustomSegmenter()) builder.add_classifier(MinAreaRule(2000), ColorClassifier(), "big") workflow = builder.get() # execute results = workflow.process(NumpyImage(image)) # validate number of results count = len(results) self.assertEqual(count, 2) # sort polygons sorted_idx = sorted(range(count), key=lambda i: (results.polygons[i].centroid.y, results.polygons[i].centroid.x)) # first shape (excluded) shape1 = results.polygons[sorted_idx[0]] self.assertLess(relative_error(shape1.area, np.pi * 25 * 25), 0.025) self.assertLess(relative_error(shape1.centroid.x, 100), 0.025) self.assertLess(relative_error(shape1.centroid.y, 40), 0.025) self.assertEqual(results.dispatches[sorted_idx[0]], None) self.assertEqual(results.labels[sorted_idx[0]], None) self.assertAlmostEqual(results.probas[sorted_idx[0]], 0.0) # second shape (include) shape2 = results.polygons[sorted_idx[1]] self.assertLess(relative_error(shape2.area, np.pi * 35 * 35), 0.025) self.assertLess(relative_error(shape2.centroid.x, 200), 0.025) self.assertLess(relative_error(shape2.centroid.y, 60), 0.025) self.assertEqual(results.dispatches[sorted_idx[1]], "big") self.assertEqual(results.labels[sorted_idx[1]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[1]], 1.0) # check other information timing = results.timing self.assertEqual(timing.get_phases_hierarchy(), {"workflow.sldc": { "detect": {"load": None, "segment": None, "locate": None}, "merge": None, "dispatch_classify": {"dispatch": None, "classify": None} }})
def testSLDCWorkflowWithOneShotDispatcher(self): # pre build components segmenter = DumbSegmenter() dispatcher = DumbDispatcher() classifier = DumbClassifier() rule = DumbRule() logger = StandardOutputLogger(Logger.DEBUG) builder = SLDCWorkflowBuilder() builder.set_tile_size(512, 768) builder.set_overlap(3) builder.set_distance_tolerance(5) builder.set_n_jobs(5) builder.set_logger(logger) builder.set_parallel_dc(True) builder.set_tile_builder(None) with self.assertRaises(MissingComponentException): builder.get() builder.set_segmenter(segmenter) with self.assertRaises(MissingComponentException): builder.get() builder.set_default_tile_builder() with self.assertRaises(MissingComponentException): builder.get() builder.set_one_shot_dispatcher(dispatcher, {"default": classifier}) with self.assertRaises(InvalidBuildingException): builder.add_classifier(rule, classifier, dispatching_label="default") with self.assertRaises(InvalidBuildingException): builder.add_catchall_classifier(classifier, dispatching_label="default") workflow = builder.get() self.assertIsInstance(workflow, SLDCWorkflow) self.assertEqual(workflow._segmenter, segmenter) self.assertEqual(workflow._n_jobs, 5) self.assertEqual(workflow._tile_overlap, 3) self.assertEqual(workflow._tile_max_height, 512) self.assertEqual(workflow._tile_max_width, 768) self.assertEqual(workflow.logger, logger) self.assertIsInstance(workflow._tile_builder, DefaultTileBuilder) self.assertEqual(workflow._dispatch_classifier._dispatcher, dispatcher) self.assertEqual(len(workflow._dispatch_classifier._classifiers), 1) self.assertEqual(workflow._dispatch_classifier._classifiers[0], classifier)
def testDetectCircleParallel(self): """A test which executes a full workflow on image containing a white circle in the center of an black image in parallel """ # generate circle image w, h = 2000, 2000 image = np.zeros((w, h, 3), dtype="uint8") image = draw_circle(image, 750, (1000, 1000), [129, 129, 129]) # build workflow builder = SLDCWorkflowBuilder() builder.set_n_jobs(2) builder.set_segmenter(CircleSegmenter()) builder.add_catchall_classifier(CircleClassifier()) builder.set_parallel_dc(True) workflow = builder.get() # process image workflow_info = workflow.process(NumpyImage(image)) # Check results self.assertEqual(len(workflow_info.polygons), 1) # Check circle polygon = workflow_info.polygons[0] self.assertEqual(relative_error(polygon.area, np.pi * 750 * 750) <= 0.005, True) self.assertEqual(relative_error(polygon.centroid.x, 1000) <= 0.005, True) self.assertEqual(relative_error(polygon.centroid.y, 1000) <= 0.005, True) assert_array_equal(workflow_info.labels, [1]) assert_array_almost_equal(workflow_info.probas, [1.0]) assert_array_equal(workflow_info.dispatches, ["catchall"]) # check other information timing = workflow_info.timing self.assertEqual(timing.get_phases_hierarchy(), {"workflow.sldc": { "detect": {"load": None, "segment": None, "locate": None}, "merge": None, "dispatch_classify": {"dispatch": None, "classify": None} }})
def testWorkflowChainBuilder(self): segmenter = DumbSegmenter() dispatcher = DumbDispatcher() classifier = DumbClassifier() builder = SLDCWorkflowBuilder() builder.set_segmenter(segmenter) builder.set_default_tile_builder() builder.set_one_shot_dispatcher(dispatcher, {"default": classifier}) workflow1 = builder.get() builder2 = SSLWorkflowBuilder() builder2.set_segmenter(segmenter) builder2.set_default_tile_builder() workflow2 = builder2.get() _filter = DefaultFilter() logger = StandardOutputLogger(Logger.DEBUG) chain_builder = WorkflowChainBuilder() chain_builder.set_logger(logger) with self.assertRaises(MissingComponentException): chain_builder.get() chain_builder.set_first_workflow(workflow1, label="first") chain_builder.add_executor(workflow2, label="second", filter=_filter, n_jobs=2, logger=logger) chain = chain_builder.get() self.assertIsInstance(chain, WorkflowChain) self.assertEqual(chain.logger, logger) self.assertEqual(chain._first_workflow, workflow1) self.assertEqual(len(chain._executors), 1) self.assertEqual(chain._executors[0]._workflow, workflow2) self.assertEqual(len(chain._labels), 2) self.assertEqual(tuple(chain._labels), ("first", "second")) self.assertEqual(len(chain._filters), 1) self.assertEqual(chain._filters[0], _filter)
def testSLDCWorkflowWithCatchAllClassifier(self): # pre build components segmenter = DumbSegmenter() tile_builder = DefaultTileBuilder() dispatcher = DumbDispatcher() classifier = DumbClassifier() builder = SLDCWorkflowBuilder() builder.set_segmenter(segmenter) builder.set_tile_builder(tile_builder) builder.add_catchall_classifier(classifier) with self.assertRaises(InvalidBuildingException): builder.set_one_shot_dispatcher(dispatcher, {"default": classifier}) workflow = builder.get() self.assertIsInstance(workflow, SLDCWorkflow) self.assertIsInstance(workflow._dispatch_classifier._dispatcher, RuleBasedDispatcher) self.assertEqual(len(workflow._dispatch_classifier._classifiers), 1) self.assertEqual(workflow._dispatch_classifier._classifiers[0], classifier) self.assertIsInstance(workflow._dispatch_classifier._dispatcher, RuleBasedDispatcher) self.assertEqual(len(workflow._dispatch_classifier._dispatcher._rules), 1) self.assertIsInstance(workflow._dispatch_classifier._dispatcher._rules[0], CatchAllRule)
def testSquareAndCircleIncluded(self): w, h = 2000, 2000 image = np.zeros((h, w), dtype=np.uint8) # locations of the 9 multi-squares shapes = [("c", (w // 7, h // 7)), ("s", (3 * w // 7, h // 7)), ("s", (5 * w // 7, h // 7)), ("s", (w // 7, 3 * h // 7)), ("c", (3 * w // 7, 3 * h // 7)), ("s", (5 * w // 7, 3 * h // 7)), ("c", (w // 7, 5 * h // 7)), ("s", (3 * w // 7, 5 * h // 7)), ("c", (5 * w // 7, 5 * h // 7))] for shape, position in shapes: if shape == "c": image = draw_multicircle(image, position, w // 7, color_in=87) elif shape == "s": image = draw_multisquare(image, position, w // 7, color_in=187) # Build workflows # 1st: find big shapes and dispatch them as circle or square # 2nd: find small circles in found circle shapes # 3rd: find small squares in found square shape builder = SLDCWorkflowBuilder() builder.set_segmenter(BigShapeSegmenter()) builder.add_classifier(CircleDispatch(), DumbClassifier(), dispatching_label="circle") builder.add_classifier(SquareDispatch(), DumbClassifier(), dispatching_label="square") builder.set_tile_size(512, 512) workflow1 = builder.get() builder.set_segmenter(SmallCircleSegmenter()) builder.add_catchall_classifier(DumbClassifier()) workflow2 = builder.get() builder.set_segmenter(SmallSquareSegmenter()) builder.add_catchall_classifier(DumbClassifier()) workflow3 = builder.get() # Build chain chain_builder = WorkflowChainBuilder() chain_builder.set_first_workflow(workflow1) chain_builder.add_executor(workflow2, filter=CircleShapeFilter()) chain_builder.add_executor(workflow3, filter=SquareShapeFilter(), n_jobs=2) chain = chain_builder.get() chain_info = chain.process(NumpyImage(image)) info1 = chain_info[0] self.assertEqual(9, len(info1)) self.assertEqual(4, len([d for d in info1.dispatches if d == "circle"])) self.assertEqual(5, len([d for d in info1.dispatches if d == "square"])) info2 = chain_info[1] self.assertEqual(16, len(info2)) info3 = chain_info[2] self.assertEqual(20, len(info3))
def testFindCircleAndSquare(self): """Test the workflow on an image containing both squares and circles of different colors Two squares of side: 200 - white centered in (1000, 1000) - grey centered in (3000, 3000) Two circles of side: 100 - white centered in (1000, 3000) - grey centered in (3000, 1000) Another white square of side 300 centered in (2000,2000) """ # square w, h = 2000, 2000 image = np.zeros((w, h,), dtype="uint8") image = draw_circle(image, 100, (500, 1500), 255) image = draw_circle(image, 100, (1500, 600), 127) image = draw_square(image, 200, (500, 500), 255) image = draw_square(image, 200, (1500, 1500), 127) image = draw_square(image, 300, (1000, 1000), 255) # Build the workflow builder = SLDCWorkflowBuilder() builder.set_segmenter(CustomSegmenter()) builder.add_classifier(CircleRule(), ColorClassifier(), dispatching_label="circle") builder.add_classifier(SquareRule(), ColorClassifier()) workflow = builder.get() # Execute results = workflow.process(NumpyImage(image)) # count check count = len(results) self.assertEqual(count, 5) # sort polygons sorted_idx = sorted(range(count), key=lambda i: (results.polygons[i].centroid.y, results.polygons[i].centroid.x)) # first square square1 = results.polygons[sorted_idx[0]] self.assertEqual(relative_error(square1.area, 200 * 200) < 0.005, True) self.assertEqual(relative_error(square1.centroid.x, 500) < 0.005, True) self.assertEqual(relative_error(square1.centroid.y, 500) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[0]], "1") # square self.assertEqual(results.labels[sorted_idx[0]], ColorClassifier.WHITE) # white self.assertAlmostEqual(results.probas[sorted_idx[0]], 1.0) # first circle circle1 = results.polygons[sorted_idx[1]] self.assertEqual(relative_error(circle1.area, np.pi * 100 * 100) < 0.005, True) self.assertEqual(relative_error(circle1.centroid.x, 1500) < 0.005, True) self.assertEqual(relative_error(circle1.centroid.y, 600) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[1]], "circle") # circle self.assertEqual(results.labels[sorted_idx[1]], ColorClassifier.GREY) # grey self.assertAlmostEqual(results.probas[sorted_idx[1]], 1.0) # second square (centered) square2 = results.polygons[sorted_idx[2]] self.assertEqual(relative_error(square2.area, 300 * 300) < 0.005, True) self.assertEqual(relative_error(square2.centroid.x, 1000) < 0.005, True) self.assertEqual(relative_error(square2.centroid.y, 1000) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[2]], "1") # square self.assertEqual(results.labels[sorted_idx[2]], ColorClassifier.WHITE) # white self.assertAlmostEqual(results.probas[sorted_idx[2]], 1.0) # second circle circle2 = results.polygons[sorted_idx[3]] self.assertEqual(relative_error(circle2.area, np.pi * 100 * 100) < 0.005, True) self.assertEqual(relative_error(circle2.centroid.x, 500) < 0.005, True) self.assertEqual(relative_error(circle2.centroid.y, 1500) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[3]], "circle") # circle self.assertEqual(results.labels[sorted_idx[3]], ColorClassifier.WHITE) # grey self.assertAlmostEqual(results.probas[sorted_idx[3]], 1.0) # third square square3 = results.polygons[sorted_idx[4]] self.assertEqual(relative_error(square3.area, 200 * 200) < 0.005, True) self.assertEqual(relative_error(square3.centroid.x, 1500) < 0.005, True) self.assertEqual(relative_error(square3.centroid.y, 1500) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[4]], "1") # square self.assertEqual(results.labels[sorted_idx[4]], ColorClassifier.GREY) # white self.assertAlmostEqual(results.probas[sorted_idx[4]], 1.0) # check other information timing = results.timing self.assertEqual(timing.get_phases_hierarchy(), {"workflow.sldc": { "detect": {"load": None, "segment": None, "locate": None}, "merge": None, "dispatch_classify": {"dispatch": None, "classify": None} }})
def testWorkflowWithExcludedObjects(self): # generate circle image w, h = 300, 100 image = np.zeros(( h, w, ), dtype="uint8") image = draw_circle(image, 25, (100, 40), 255) # pi * 25 * 25 -> ~ 1963 image = draw_circle(image, 35, (200, 60), 255) # pi * 35 * 35 -> ~ 3858 # build the workflow builder = SLDCWorkflowBuilder() builder.set_segmenter(CustomSegmenter()) builder.add_classifier(MinAreaRule(2000), ColorClassifier(), "big") workflow = builder.get() # execute results = workflow.process(NumpyImage(image)) # validate number of results count = len(results) self.assertEqual(count, 2) # sort polygons sorted_idx = sorted( range(count), key=lambda i: (results.polygons[i].centroid.y, results.polygons[i].centroid.x)) # first shape (excluded) shape1 = results.polygons[sorted_idx[0]] self.assertLess(relative_error(shape1.area, np.pi * 25 * 25), 0.025) self.assertLess(relative_error(shape1.centroid.x, 100), 0.025) self.assertLess(relative_error(shape1.centroid.y, 40), 0.025) self.assertEqual(results.dispatches[sorted_idx[0]], None) self.assertEqual(results.labels[sorted_idx[0]], None) self.assertAlmostEqual(results.probas[sorted_idx[0]], 0.0) # second shape (include) shape2 = results.polygons[sorted_idx[1]] self.assertLess(relative_error(shape2.area, np.pi * 35 * 35), 0.025) self.assertLess(relative_error(shape2.centroid.x, 200), 0.025) self.assertLess(relative_error(shape2.centroid.y, 60), 0.025) self.assertEqual(results.dispatches[sorted_idx[1]], "big") self.assertEqual(results.labels[sorted_idx[1]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[1]], 1.0) # check other information timing = results.timing self.assertEqual( timing.get_phases_hierarchy(), { "workflow.sldc": { "detect": { "load": None, "segment": None, "locate": None }, "merge": None, "dispatch_classify": { "dispatch": None, "classify": None } } })
def testWorkflowWithCustomDispatcher(self): # generate circle image w, h = 1000, 1000 image = np.zeros(( w, h, ), dtype="uint8") image = draw_circle(image, 10, (125, 125), 255) # pi * 10 * 10 -> ~ 314 image = draw_circle(image, 25, (250, 750), 255) # pi * 25 * 25 -> ~ 1963 image = draw_square(image, 26, (250, 250), 255) # 26 * 26 -> 676 image = draw_square(image, 50, (750, 750), 127) # 50 * 50 -> 2500 # build the workflow builder = SLDCWorkflowBuilder() builder.set_segmenter(CustomSegmenter()) builder.set_one_shot_dispatcher(CustomDispatcher(1000), { "BIG": ColorClassifier(), "SMALL": ColorClassifier() }) workflow = builder.get() # execute results = workflow.process(NumpyImage(image)) # validate number of results count = len(results) self.assertEqual(count, 4) # sort polygons sorted_idx = sorted( range(count), key=lambda i: (results.polygons[i].centroid.y, results.polygons[i].centroid.x)) # first circle circle1 = results.polygons[sorted_idx[0]] self.assertTrue(relative_error(circle1.area, np.pi * 10 * 10) < 0.025) self.assertTrue(relative_error(circle1.centroid.x, 125) < 0.025) self.assertTrue(relative_error(circle1.centroid.y, 125) < 0.025) self.assertEqual(results.dispatches[sorted_idx[0]], "SMALL") self.assertEqual(results.labels[sorted_idx[0]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[0]], 1.0) # first square square1 = results.polygons[sorted_idx[1]] self.assertTrue(relative_error(square1.area, 26 * 26) < 0.025) self.assertTrue(relative_error(square1.centroid.x, 250) < 0.025) self.assertTrue(relative_error(square1.centroid.y, 250) < 0.025) self.assertEqual(results.dispatches[sorted_idx[1]], "SMALL") self.assertEqual(results.labels[sorted_idx[1]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[1]], 1.0) # second circle circle2 = results.polygons[sorted_idx[2]] self.assertTrue(relative_error(circle2.area, np.pi * 25 * 25) < 0.025) self.assertTrue(relative_error(circle2.centroid.x, 250) < 0.025) self.assertTrue(relative_error(circle2.centroid.y, 750) < 0.025) self.assertEqual(results.dispatches[sorted_idx[2]], "BIG") self.assertEqual(results.labels[sorted_idx[2]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[2]], 1.0) # second square square2 = results.polygons[sorted_idx[3]] self.assertTrue(relative_error(square2.area, 50 * 50) < 0.025) self.assertTrue(relative_error(square2.centroid.x, 750) < 0.025) self.assertTrue(relative_error(square2.centroid.y, 750) < 0.025) self.assertEqual(results.dispatches[sorted_idx[3]], "BIG") self.assertEqual(results.labels[sorted_idx[3]], ColorClassifier.GREY) self.assertAlmostEqual(results.probas[sorted_idx[3]], 1.0) # check other information timing = results.timing self.assertEqual( timing.get_phases_hierarchy(), { "workflow.sldc": { "detect": { "load": None, "segment": None, "locate": None }, "merge": None, "dispatch_classify": { "dispatch": None, "classify": None } } })
def testSquareAndCircleIncluded(self): w, h = 2000, 2000 image = np.zeros((h, w), dtype=np.uint8) # locations of the 9 multi-squares shapes = [ ("c", (w // 7, h // 7)), ("s", (3 * w // 7, h // 7)), ("s", (5 * w // 7, h // 7)), ("s", (w // 7, 3 * h // 7)), ("c", (3 * w // 7, 3 * h // 7)), ("s", (5 * w // 7, 3 * h // 7)), ("c", (w // 7, 5 * h // 7)), ("s", (3 * w // 7, 5 * h // 7)), ("c", (5 * w // 7, 5 * h // 7)) ] for shape, position in shapes: if shape == "c": image = draw_multicircle(image, position, w // 7, color_in=87) elif shape == "s": image = draw_multisquare(image, position, w // 7, color_in=187) # Build workflows # 1st: find big shapes and dispatch them as circle or square # 2nd: find small circles in found circle shapes # 3rd: find small squares in found square shape builder = SLDCWorkflowBuilder() builder.set_segmenter(BigShapeSegmenter()) builder.add_classifier(CircleDispatch(), DumbClassifier(), dispatching_label="circle") builder.add_classifier(SquareDispatch(), DumbClassifier(), dispatching_label="square") builder.set_tile_size(512, 512) workflow1 = builder.get() builder.set_segmenter(SmallCircleSegmenter()) builder.add_catchall_classifier(DumbClassifier()) workflow2 = builder.get() builder.set_segmenter(SmallSquareSegmenter()) builder.add_catchall_classifier(DumbClassifier()) workflow3 = builder.get() # Build chain chain_builder = WorkflowChainBuilder() chain_builder.set_first_workflow(workflow1) chain_builder.add_executor(workflow2, filter=CircleShapeFilter()) chain_builder.add_executor(workflow3, filter=SquareShapeFilter(), n_jobs=2) chain = chain_builder.get() chain_info = chain.process(NumpyImage(image)) info1 = chain_info[0] self.assertEqual(9, len(info1)) self.assertEqual(4, len([d for d in info1.dispatches if d == "circle"])) self.assertEqual(5, len([d for d in info1.dispatches if d == "square"])) info2 = chain_info[1] self.assertEqual(16, len(info2)) info3 = chain_info[2] self.assertEqual(20, len(info3))
def testFindCircleAndSquare(self): """Test the workflow on an image containing both squares and circles of different colors Two squares of side: 200 - white centered in (1000, 1000) - grey centered in (3000, 3000) Two circles of side: 100 - white centered in (1000, 3000) - grey centered in (3000, 1000) Another white square of side 300 centered in (2000,2000) """ # square w, h = 2000, 2000 image = np.zeros(( w, h, ), dtype="uint8") image = draw_circle(image, 100, (500, 1500), 255) image = draw_circle(image, 100, (1500, 600), 127) image = draw_square(image, 200, (500, 500), 255) image = draw_square(image, 200, (1500, 1500), 127) image = draw_square(image, 300, (1000, 1000), 255) # Build the workflow builder = SLDCWorkflowBuilder() builder.set_segmenter(CustomSegmenter()) builder.add_classifier(CircleRule(), ColorClassifier(), dispatching_label="circle") builder.add_classifier(SquareRule(), ColorClassifier()) workflow = builder.get() # Execute results = workflow.process(NumpyImage(image)) # count check count = len(results) self.assertEqual(count, 5) # sort polygons sorted_idx = sorted( range(count), key=lambda i: (results.polygons[i].centroid.y, results.polygons[i].centroid.x)) # first square square1 = results.polygons[sorted_idx[0]] self.assertEqual(relative_error(square1.area, 200 * 200) < 0.005, True) self.assertEqual(relative_error(square1.centroid.x, 500) < 0.005, True) self.assertEqual(relative_error(square1.centroid.y, 500) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[0]], "1") # square self.assertEqual(results.labels[sorted_idx[0]], ColorClassifier.WHITE) # white self.assertAlmostEqual(results.probas[sorted_idx[0]], 1.0) # first circle circle1 = results.polygons[sorted_idx[1]] self.assertEqual( relative_error(circle1.area, np.pi * 100 * 100) < 0.005, True) self.assertEqual( relative_error(circle1.centroid.x, 1500) < 0.005, True) self.assertEqual(relative_error(circle1.centroid.y, 600) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[1]], "circle") # circle self.assertEqual(results.labels[sorted_idx[1]], ColorClassifier.GREY) # grey self.assertAlmostEqual(results.probas[sorted_idx[1]], 1.0) # second square (centered) square2 = results.polygons[sorted_idx[2]] self.assertEqual(relative_error(square2.area, 300 * 300) < 0.005, True) self.assertEqual( relative_error(square2.centroid.x, 1000) < 0.005, True) self.assertEqual( relative_error(square2.centroid.y, 1000) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[2]], "1") # square self.assertEqual(results.labels[sorted_idx[2]], ColorClassifier.WHITE) # white self.assertAlmostEqual(results.probas[sorted_idx[2]], 1.0) # second circle circle2 = results.polygons[sorted_idx[3]] self.assertEqual( relative_error(circle2.area, np.pi * 100 * 100) < 0.005, True) self.assertEqual(relative_error(circle2.centroid.x, 500) < 0.005, True) self.assertEqual( relative_error(circle2.centroid.y, 1500) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[3]], "circle") # circle self.assertEqual(results.labels[sorted_idx[3]], ColorClassifier.WHITE) # grey self.assertAlmostEqual(results.probas[sorted_idx[3]], 1.0) # third square square3 = results.polygons[sorted_idx[4]] self.assertEqual(relative_error(square3.area, 200 * 200) < 0.005, True) self.assertEqual( relative_error(square3.centroid.x, 1500) < 0.005, True) self.assertEqual( relative_error(square3.centroid.y, 1500) < 0.005, True) self.assertEqual(results.dispatches[sorted_idx[4]], "1") # square self.assertEqual(results.labels[sorted_idx[4]], ColorClassifier.GREY) # white self.assertAlmostEqual(results.probas[sorted_idx[4]], 1.0) # check other information timing = results.timing self.assertEqual( timing.get_phases_hierarchy(), { "workflow.sldc": { "detect": { "load": None, "segment": None, "locate": None }, "merge": None, "dispatch_classify": { "dispatch": None, "classify": None } } })
def testSquareIncluded(self): # generate the image to be processed w, h = 2000, 2000 image = np.zeros((h, w), dtype=np.uint8) # locations of the 9 multi-squares positions = [ (w // 7, h // 7), (3 * w // 7, h // 7), (5 * w // 7, h // 7), (w // 7, 3 * h // 7), (3 * w // 7, 3 * h // 7), (5 * w // 7, 3 * h // 7), (w // 7, 5 * h // 7), (3 * w // 7, 5 * h // 7), (5 * w // 7, 5 * h // 7) ] for position in positions: image = draw_multisquare(image, position, w // 7, color_in=127) # Build workflow builder = SLDCWorkflowBuilder() # Build workflow 1 builder.set_segmenter(BigShapeSegmenter()) builder.add_catchall_classifier(DumbClassifier()) builder.set_tile_size(512, 512) workflow1 = builder.get() # Build workflow 2 builder.set_segmenter(SmallSquareSegmenter()) builder.add_catchall_classifier(DumbClassifier()) workflow2 = builder.get() # Build chaining chain_builder = WorkflowChainBuilder() chain_builder.set_first_workflow(workflow1, label="big_squares") chain_builder.add_executor(workflow2, label="small_squares") chain = chain_builder.get() # Launch chain_info = chain.process(NumpyImage(image)) # check results big_area = (w // 7) ** 2 small_area = (w / 35) ** 2 info1 = chain_info["big_squares"] self.assertEqual(9, len(info1)) for object_info in info1: self.assertTrue(relative_error(object_info.polygon.area, big_area) < 0.005) self.assertEqual("catchall", object_info.dispatch) self.assertEqual(1, object_info.label) self.assertAlmostEqual(1.0, object_info.proba) info2 = chain_info["small_squares"] self.assertEqual(36, len(info2)) for object_info in info2: self.assertTrue(relative_error(object_info.polygon.area, small_area) < 0.005) self.assertEqual("catchall", object_info.dispatch) self.assertEqual(1, object_info.label) self.assertAlmostEqual(1.0, object_info.proba)
def testWorkflowWithCustomDispatcher(self): # generate circle image w, h = 1000, 1000 image = np.zeros((w, h,), dtype="uint8") image = draw_circle(image, 10, (125, 125), 255) # pi * 10 * 10 -> ~ 314 image = draw_circle(image, 25, (250, 750), 255) # pi * 25 * 25 -> ~ 1963 image = draw_square(image, 26, (250, 250), 255) # 26 * 26 -> 676 image = draw_square(image, 50, (750, 750), 127) # 50 * 50 -> 2500 # build the workflow builder = SLDCWorkflowBuilder() builder.set_segmenter(CustomSegmenter()) builder.set_one_shot_dispatcher(CustomDispatcher(1000), { "BIG": ColorClassifier(), "SMALL": ColorClassifier() }) workflow = builder.get() # execute results = workflow.process(NumpyImage(image)) # validate number of results count = len(results) self.assertEqual(count, 4) # sort polygons sorted_idx = sorted(range(count), key=lambda i: (results.polygons[i].centroid.y, results.polygons[i].centroid.x)) # first circle circle1 = results.polygons[sorted_idx[0]] self.assertTrue(relative_error(circle1.area, np.pi * 10 * 10) < 0.025) self.assertTrue(relative_error(circle1.centroid.x, 125) < 0.025) self.assertTrue(relative_error(circle1.centroid.y, 125) < 0.025) self.assertEqual(results.dispatches[sorted_idx[0]], "SMALL") self.assertEqual(results.labels[sorted_idx[0]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[0]], 1.0) # first square square1 = results.polygons[sorted_idx[1]] self.assertTrue(relative_error(square1.area, 26 * 26) < 0.025) self.assertTrue(relative_error(square1.centroid.x, 250) < 0.025) self.assertTrue(relative_error(square1.centroid.y, 250) < 0.025) self.assertEqual(results.dispatches[sorted_idx[1]], "SMALL") self.assertEqual(results.labels[sorted_idx[1]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[1]], 1.0) # second circle circle2 = results.polygons[sorted_idx[2]] self.assertTrue(relative_error(circle2.area, np.pi * 25 * 25) < 0.025) self.assertTrue(relative_error(circle2.centroid.x, 250) < 0.025) self.assertTrue(relative_error(circle2.centroid.y, 750) < 0.025) self.assertEqual(results.dispatches[sorted_idx[2]], "BIG") self.assertEqual(results.labels[sorted_idx[2]], ColorClassifier.WHITE) self.assertAlmostEqual(results.probas[sorted_idx[2]], 1.0) # second square square2 = results.polygons[sorted_idx[3]] self.assertTrue(relative_error(square2.area, 50 * 50) < 0.025) self.assertTrue(relative_error(square2.centroid.x, 750) < 0.025) self.assertTrue(relative_error(square2.centroid.y, 750) < 0.025) self.assertEqual(results.dispatches[sorted_idx[3]], "BIG") self.assertEqual(results.labels[sorted_idx[3]], ColorClassifier.GREY) self.assertAlmostEqual(results.probas[sorted_idx[3]], 1.0) # check other information timing = results.timing self.assertEqual(timing.get_phases_hierarchy(), {"workflow.sldc": { "detect": {"load": None, "segment": None, "locate": None}, "merge": None, "dispatch_classify": {"dispatch": None, "classify": None} }})