class TestHistogramFeatureExtractor: channel1 = np.arange(12).reshape([3, 4]) channel2 = np.arange(100, 112).reshape([3, 4]) channel3 = np.array([100, ] * 6 + [200, ] * 6).reshape([3, 4]) test_image = np.stack([channel1, channel2, channel3], axis=2) test_image_1d = np.stack([channel1], axis=2) descr1 = Descriptor([0.1 / 16, 1 / 16]) descr2 = Descriptor([0.2 / 16, 4]) descr3 = Descriptor([5, 6]) mocked_calc_histo_1d = MockingNPFunction([channel1, channel2, channel3], [descr1, descr2, descr3]) def test_calculate_histogram_shape(self): histo = HistogramFeatureExtractor().calculate(self.test_image) assert isinstance(histo, Descriptor) assert histo.vector.shape == (EXPECTED_1D_HISTO_LENGTH * 3,) def test_for_3_channel(self): with mock.patch('impl.feature_engine.histogram_feature_extractor.calculate_histogram_1d', new=self.mocked_calc_histo_1d): histo = HistogramFeatureExtractor().calculate(self.test_image) assert np.allclose(histo.vector, np.array([0.1, 1, 0.2, 1, 1, 1])) def test_for_1_channel(self): with mock.patch('impl.feature_engine.histogram_feature_extractor.calculate_histogram_1d', new=self.mocked_calc_histo_1d): histo = HistogramFeatureExtractor().calculate(self.test_image_1d) assert np.allclose(histo.vector, [0.1, 1] * 3) def test_for_2d_image(self): with mock.patch('impl.feature_engine.histogram_feature_extractor.calculate_histogram_1d', new=self.mocked_calc_histo_1d): histo = HistogramFeatureExtractor().calculate(self.channel1) assert np.allclose(histo.vector, [0.1, 1] * 3)
def calculate(self, image: np.ndarray) -> Descriptor: channels = get_channels(image) descriptors_1d = [calculate_histogram_1d(channel).vector for channel in channels] vector = np.hstack(descriptors_1d) vector_clipped = np.clip(vector * self._SCALE_FACTOR, 0.0, 1.0) descriptor = Descriptor(vector=vector_clipped) return descriptor
class TestSearchTermsCreator: descriptor = Descriptor([1, 2, 3, 4, 5, 6]) quantized_vector = np.array([0, 1, 2, 3, 3, 3]) composed_values = np.array([0, 10, 20]) def test_get_dictionary_of_words(self, mocked_words_composer, mocked_quantizer): mocked_words_composer.return_value.compose.return_value = self.composed_values mocked_quantizer.return_value.quantize_vector.return_value = self.quantized_vector quantizer = SearchTermsCreator(DESCRIPTOR_LENGTH) words = quantizer.get_dictionary_of_words(self.descriptor) assert isinstance(words, dict) assert all([type(value) == int for value in words.values()]) assert words == { "word_0000": self.composed_values[0], "word_0001": self.composed_values[1], "word_0002": self.composed_values[2], } mocked_words_composer.assert_called_once_with( np.prod(DESCRIPTOR_LENGTH), mocked_config.LENGTH_OF_WORD, mocked_config.NUMBER_OF_LEVELS) mocked_words_composer.return_value.compose.assert_called_once_with( self.quantized_vector) mocked_quantizer.assert_called_once_with( mocked_config.NUMBER_OF_LEVELS) mocked_quantizer.return_value.quantize_vector.assert_called_once_with( self.descriptor.vector)
def calculate_histogram_1d(image: np.array) -> Descriptor: def shape_is_good(img): return len(img.shape) == 2 or (len(img.shape) == 3 and img.shape[-1] == 1) if not shape_is_good(image): raise HistogramBasedFeatureExtractorException("only 1 channel images are supported here") image_clipped = np.clip(image, 0, 255) h = np.histogram(a=image_clipped, bins=16, range=[0, 256])[0] histogram_normalized = h / image_clipped.size return Descriptor(vector=histogram_normalized)
class TestDescriptorSearch: descriptor = Descriptor([1]) image_region = ImageRegion(descriptor) expected_result1 = { SearchResult.FIELD_DESCRIPTOR: [1], SearchResult.FIELD_SOURCE_ID: "some_id1" } expected_result2 = { SearchResult.FIELD_DESCRIPTOR: [2], SearchResult.FIELD_SOURCE_ID: "some_id2" } repo_find_results = [expected_result1, expected_result2] descriptor_shape = (16 * 3, ) @mock.patch('impl.search.descriptor_search.RegionRepository', autospec=True) @mock.patch('impl.search.descriptor_search.CleanedSearchResult', autospec=True) def test_find_similar_behaviour(self, cleaned_search_result, region_repository): cleaned_search_result.return_value = search_result region_repository.return_value.find.return_value = self.repo_find_results similar = DescriptorSearch( descriptor_shape=self.descriptor_shape).find_similar_for_region( self.image_region) assert similar == search_result region_repository.assert_called_once_with((48, ), flush_data=False) region_repository.return_value.find.assert_called_once_with( self.descriptor) region_repository.return_value.save.assert_not_called() cleaned_search_result.assert_called_once_with(self.image_region, self.repo_find_results) @mock.patch('impl.search.descriptor_search.RegionRepository', autospec=True) def test_add_region(self, region_repository): region_repository.return_value.save.return_value = "region_reference" reference_to_source = "ref1" similar = DescriptorSearch( descriptor_shape=self.descriptor_shape).add_region( self.image_region, reference_to_source) assert similar == "region_reference" region_repository.assert_called_once_with(self.descriptor_shape, flush_data=False) region_repository.return_value.find.assert_not_called() region_repository.return_value.save.assert_called_once_with( self.image_region, reference_to_source)
class TestSubimageFeatureEngine: descriptor1 = Descriptor([1]) descriptor2 = Descriptor([2]) expected_image_regions = [ ImageRegion(descriptor1), ImageRegion(descriptor2), ] ref_source = "some reference to source" feature_extractor = mock.create_autospec(FeatureExtractor) subimage_extractor = mock.create_autospec(SubimageExtractor) def test_should_have_extract_features_method(self): extractor = SubimageFeatureEngine(FeatureExtractor, SubimageExtractor) assert hasattr(extractor, 'extract_features') @mock.patch('impl.feature_engine.subimage_feature_engine.ImageEncoder', spec=True) @mock.patch( 'impl.feature_engine.subimage_feature_engine.SubimagesProcessor', spec=True) def test_steps(self, mocked_subimage_processor, mocked_image_encoder): mocked_image_encoder.return_value.binary_to_array.return_value = whole_image mocked_subimage_processor.return_value.extract_features_and_create_regions.return_value = self.expected_image_regions extracted_subimages = ["subimage1", "subimage2"] self.subimage_extractor.extract.return_value = extracted_subimages engine = SubimageFeatureEngine(self.feature_extractor, self.subimage_extractor) image_regions = engine.extract_features(binary_image) assert image_regions == self.expected_image_regions mocked_image_encoder.assert_called_once_with(image_format="jpeg") mocked_image_encoder.return_value.binary_to_array.assert_called_once_with( binary_image) self.subimage_extractor.extract.assert_called_once_with(whole_image) mocked_subimage_processor.assert_called_once_with( self.feature_extractor) mocked_subimage_processor.return_value.extract_features_and_create_regions.assert_called_once_with( extracted_subimages)
def calculate(self, image: np.ndarray) -> Descriptor: channels = get_channels(image) average_per_channel = [np.mean(channel) / 255. for channel in channels] descriptor = Descriptor(vector=np.array(average_per_channel)) return descriptor
import numpy as np from kolasimagecommon import Descriptor from impl.domain.image_region import ImageRegion from impl.feature_engine.histogram_feature_extractor import FeatureExtractor from kolasimagecommon import SubImage from impl.feature_engine.subimage_processor import SubimagesProcessor mocked_feature_extractor = mock.create_autospec(spec=FeatureExtractor) img1 = np.ones([3, 4]) img2 = np.ones([3, 4]) * 123 subimage1 = SubImage(img1) subimage2 = SubImage(img2) some_reference = "some_refg" descriptor1 = Descriptor([12, 3]) descriptor2 = Descriptor([4, 5]) class TestSubimagesProcessor: def test_subimages_processor_process(self): mocked_feature_extractor.calculate.side_effect = [ descriptor1, descriptor2 ] processor = SubimagesProcessor(mocked_feature_extractor) regions = processor.extract_features_and_create_regions( [subimage1, subimage2]) assert regions == [ImageRegion(descriptor1), ImageRegion(descriptor2)] mocked_feature_extractor.calculate.assert_has_calls(
def __init__(self, data): self._data = data self._descriptor = Descriptor(self._data[self.FIELD_DESCRIPTOR]) self._source_id = str(self._data[self.FIELD_SOURCE_ID])
class TestRegionRepository: descriptor_as_list = [[1, 2, 3], [12, 12, 34]] descriptor1 = Descriptor(descriptor_as_list) reference_to_source = "ref1" image_region = ImageRegion(descriptor1) expected_image_region_elastic_id = "some_image_region_elastic_id" serialized_dict = {"key": "value"} words = {"word1": "value1", "word2": "value2"} expected_search_results = [ mock.MagicMock(SearchResult), mock.MagicMock(SearchResult) ] @mock.patch('impl.storage.region_repository.config') @mock.patch('impl.storage.region_repository.ElasticSearchDriver', autospec=True) @mock.patch('impl.storage.region_repository.SearchTermsCreator', autospec=True) def test_save(self, mock_search_terms_creator, mock_elastic_search_driver, mock_config): mock_config.ELASTIC_DESCRIPTOR_INDEX = "ELASTIC_DESCRIPTOR_INDEX" mock_config.ELASTIC_DESCRIPTOR_TYPE = "ELASTIC_DESCRIPTOR_TYPE" mock_search_terms_creator.return_value.get_dictionary_of_words.return_value = self.serialized_dict mock_elastic_search_driver.return_value.index.return_value = self.expected_image_region_elastic_id result = RegionRepository(descriptor_shape).save( self.image_region, self.reference_to_source) assert result == self.expected_image_region_elastic_id mock_search_terms_creator.assert_called_once_with(descriptor_shape) mock_search_terms_creator.return_value.get_dictionary_of_words.assert_called_once_with( self.image_region.descriptor) mock_elastic_search_driver.assert_called_once_with( index=mock_config.ELASTIC_DESCRIPTOR_INDEX, doc_type=mock_config.ELASTIC_DESCRIPTOR_TYPE, flush_data=False) mock_elastic_search_driver.return_value.index.assert_called_once_with({ 'descriptor': self.descriptor_as_list, 'key': 'value', 'source_id': self.reference_to_source }) @mock.patch('impl.storage.region_repository.config') @mock.patch('impl.storage.region_repository.ElasticSearchDriver', autospec=True) @mock.patch('impl.storage.region_repository.SearchTermsCreator', autospec=True) def test_find(self, mock_search_terms_creator, mock_elastic_search_driver, mock_config): mock_config.ELASTIC_DESCRIPTOR_INDEX = "ELASTIC_DESCRIPTOR_INDEX" mock_config.ELASTIC_DESCRIPTOR_TYPE = "ELASTIC_DESCRIPTOR_TYPE" mock_search_terms_creator.return_value.get_dictionary_of_words.return_value = self.words mock_elastic_search_driver.return_value.search_by_words.return_value = self.expected_search_results result = RegionRepository(descriptor_shape).find(self.descriptor1) assert result == self.expected_search_results mock_search_terms_creator.assert_called_once_with(descriptor_shape) mock_search_terms_creator.return_value.get_dictionary_of_words.assert_called_once_with( self.descriptor1) mock_elastic_search_driver.assert_called_once_with( index=mock_config.ELASTIC_DESCRIPTOR_INDEX, doc_type=mock_config.ELASTIC_DESCRIPTOR_TYPE, flush_data=False) mock_elastic_search_driver.return_value.search_by_words.assert_called_once_with( self.words, list(self.words.keys())) @mock.patch('impl.storage.region_repository.config') @mock.patch('impl.storage.region_repository.ElasticSearchDriver', autospec=True) def test_with_flush_data(self, mock_elastic_search_driver, mock_config): RegionRepository(descriptor_shape, True) mock_elastic_search_driver.assert_called_once_with( index=mock_config.ELASTIC_DESCRIPTOR_INDEX, doc_type=mock_config.ELASTIC_DESCRIPTOR_TYPE, flush_data=True)