def test_xform_merge_validation(self): e1 = GenericImageEntity(np.random.randint(0, 20, 10)) e2 = GenericImageEntity(np.random.randint(0, 20, 10)) imglist = [e1, e2] xform_list = [[[DummyTransform_Add(1)], [DummyTransform_Multiply(1)]]] merge_list = [DummyMerge()] pipeline_obj = XFormMergePipeline.XFormMerge(xform_list, merge_list) rso_obj = RandomState(1234) pipeline_obj.process(imglist, rso_obj) xform_list = [[DummyTransform_Add(1)], [DummyTransform_Multiply(1)]] merge_list = [DummyMerge()] pipeline_obj = XFormMergePipeline.XFormMerge(xform_list, merge_list) rso_obj = RandomState(1234) self.assertRaises(ValueError, pipeline_obj.process, imglist, rso_obj) xform_list = [[[DummyTransform_Add(1)], [DummyTransform_Multiply(1)], [DummyTransform_Multiply(1)]]] merge_list = [DummyMerge()] pipeline_obj = XFormMergePipeline.XFormMerge(xform_list, merge_list) self.assertRaises(ValueError, pipeline_obj.process, imglist, rso_obj) xform_list = [[[DummyTransform_Add(1)], [DummyTransform_Multiply(1)]]] merge_list = [DummyMerge(), DummyMerge()] pipeline_obj = XFormMergePipeline.XFormMerge(xform_list, merge_list) self.assertRaises(ValueError, pipeline_obj.process, imglist, rso_obj)
def test_process_xform_list(self): """ Tests that all supplied list of serial transforms are processed :return:None """ img = GenericImageEntity(np.linspace(0, 10, 100)) xforms = [DummyTransform_Add(1), DummyTransform_Multiply(2)] img_expected = (img.get_data() + 1) * 2 img_actual = utils.process_xform_list(img, xforms, RandomState()) self.assertTrue(np.allclose(img_actual.get_data(), img_expected))
def test_insert_at_location1(self): img = GenericImageEntity(np.ones((20, 20, 1))) pattern = GenericImageEntity(np.ones((5, 5, 1)) * 3) inserter = InsertAtLocation(np.array([[0, 0]])) img_actual = inserter.do(img, pattern, RandomState()) img_expected = np.ones((20, 20, 1)) img_expected[0:5, 0:5, 0] = 3 self.assertTrue(np.array_equal(img_actual.get_data(), img_expected))
def test_insert_nontransparent_random_location1(self): img = np.zeros((5, 5, 4)) img[0, 0, 3] = 1 pattern = np.ones((2, 2, 4)) * 3 inserter = InsertRandomLocationNonzeroAlpha() img_actual = inserter.do(GenericImageEntity(img), GenericImageEntity(pattern), RandomState()) img_expected = np.zeros((5, 5, 4)) img_expected[0:2, 0:2, :] = 3 self.assertTrue(np.array_equal(img_actual.get_data(), img_expected))
def setUp(self): self.random_state = RandomState(1234) self.rgb_entity = GenericImageEntity(self.random_state.rand(1000, 1000, 3).astype(np.uint8)) self.rgba_entity = GenericImageEntity(self.random_state.rand(500, 500, 4).astype(np.uint8)) self.noop = NoOpFilterXForm() self.noop_down = NoOpFilterXForm("BGR", True, False) self.gotham = GothamFilterXForm() self.nashville = NashvilleFilterXForm() self.kelvin = KelvinFilterXForm() self.lomo = LomoFilterXForm() self.toaster = ToasterXForm()
def test_channel_order(self): bgr_lomo = LomoFilterXForm('BGR') rgb_lomo = LomoFilterXForm('RGB') bgr_img = np.concatenate((np.ones((5, 5, 1)), np.zeros((5, 5, 2))), axis=2).astype(np.uint8) rgb_img = np.concatenate((np.zeros((5, 5, 2)), np.ones((5, 5, 1))), axis=2).astype(np.uint8) bgr_result = bgr_lomo.do(GenericImageEntity(bgr_img), random_state_obj=self.random_state) rgb_result = rgb_lomo.do(GenericImageEntity(rgb_img), random_state_obj=self.random_state) self.assertTrue(np.array_equal(bgr_result.get_data()[:, :, 0], rgb_result.get_data()[:, :, 2])) bgr_switched_result = rgb_lomo.do(GenericImageEntity(bgr_img), random_state_obj=self.random_state) rgb_switched_result = bgr_lomo.do(GenericImageEntity(rgb_img), random_state_obj=self.random_state) # transform should be modifying R and G channels, but is instead modifying B and G channels, setting to zero self.assertTrue(np.array_equal(bgr_switched_result.get_data(), np.zeros((5, 5, 3)))) self.assertTrue(np.array_equal(rgb_switched_result.get_data(), np.zeros((5, 5, 3))))
def test_ToTensor3(self): img = GenericImageEntity(np.zeros((5, 5, 3))) xformer = ToTensorXForm(2) img_out = xformer.do(img, RandomState()) shape_expected = (5, 5, 3) shape_actual = img_out.get_data().shape self.assertTrue(shape_actual == shape_expected)
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Compresses 3-channel image input image as a specified filetype and stores in memory, passes to into wand and applies filter, stores filtered image as specified filetype again in memory, which is then decompressed back into 3-channel image :param input_obj: entity to be transformed :param random_state_obj: object to hold random state and enable reproducibility :return:new entity with transform applied """ data = input_obj.get_data() original_n_chan = data.shape[2] rgb_data, alpha_ch = normalization_to_rgb(data, self.pre_normalize, self.__repr__()) logger.debug("%s is treating input as %s!" % (self.__repr__(), self.channel_order)) if self.channel_order == 'RGB': rgb_data = cv2.cvtColor(rgb_data, cv2.COLOR_RGB2BGR) form = '.bmp' success, buffer = cv2.imencode(form, rgb_data) # faster than numpy tobytes method input_stream = BytesIO(buffer) with wand.image.Image(blob=input_stream.getvalue()) as wand_image: filtered_wand_image = self.filter(wand_image) output_stream = BytesIO() filtered_wand_image.save(output_stream) rgb_filtered_data = cv2.imdecode(np.frombuffer(output_stream.getbuffer(), np.uint8), 1) if self.channel_order == 'RGB': rgb_filtered_data = cv2.cvtColor(rgb_filtered_data, cv2.COLOR_BGR2RGB) filtered_data = normalization_from_rgb(rgb_filtered_data, alpha_ch, self.post_normalize, original_n_chan, self.__repr__()) return GenericImageEntity(filtered_data, input_obj.get_mask())
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual defined transformation :param input_obj: the input Entity to be transformed :param random_state_obj: ignored :return: the transformed Entity """ img = input_obj.get_data() original_n_chan = img.shape[2] rgb_img, alpha_ch = normalization_to_rgb(img, self.pre_normalize, "AddSnowXForm") logger.debug( "Applying albumentations.RandomSnow with coeff=%0.02f, pre_normalize=%s, post_normalize=%s" % ( self.snow_coeff, self.pre_normalize, self.post_normalize, )) rgb_img_xformed = self.snow_object(random_state=random_state_obj, image=rgb_img)['image'] img_xformed = normalization_from_rgb(rgb_img_xformed, alpha_ch, self.post_normalize, original_n_chan, "AddSnowXForm") return GenericImageEntity(img_xformed, input_obj.get_mask())
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual defined transformation :param input_obj: the input Entity to be transformed :param random_state_obj: ignored :return: the transformed Entity """ img = input_obj.get_data() original_n_chan = img.shape[2] rgb_img, alpha_ch = normalization_to_rgb(img, self.pre_normalize, "AddRainXForm") logger.debug( "Applying albumentations.RandomRain with slant=%0.02f, drop_length=%0.02f, drop_width=%0.02f," "drop_color=%s, rain_type=%s, pre_normalization=%s, post_normalization=%s" % (self.slant, self.drop_length, self.drop_width, str(self.drop_color), self.rain_type, self.pre_normalize, self.post_normalize), ) rgb_img_xformed = self.rain_object(random_state=random_state_obj, image=rgb_img)['image'] img_xformed = normalization_from_rgb(rgb_img_xformed, alpha_ch, self.post_normalize, original_n_chan, "AddRainXForm") return GenericImageEntity(img_xformed, input_obj.get_mask())
def test_modify_clean_dataset_insertMode2(self): # test configuration num_images = 10 num_datapoints_per_image = 10 trigger_val = 7 add_val = 3 mul_val = 2 # create "clean" dataset dd_list = [] for ii in range(num_images): data = np.arange(ii, ii + num_datapoints_per_image) data_fname = 'file_' + str(ii) + '.png' cv2.imwrite(os.path.join(self.clean_dataset_rootdir, data_fname), data) dd_list.append({'file': data_fname}) clean_df = pd.DataFrame(dd_list) clean_csv_fname = 'data.csv' clean_df.to_csv(os.path.join(self.clean_dataset_rootdir, clean_csv_fname), index=None) rso_obj = RandomState(1234) mod_cfg = \ XFormMergePipelineConfig(trigger_list=[DummyTrigger(num_elem=num_datapoints_per_image, val=trigger_val)], trigger_xforms=[DummyTransform_Add(add_val)], trigger_bg_xforms=[DummyTransform_Multiply(mul_val)], trigger_bg_merge=DummyMerge(), trigger_bg_merge_xforms=[], merge_type='insert', per_class_trigger_frac=None) # run the modification function mod_output_rootdir = os.path.join(self.clean_dataset_rootdir, 'modified') mod_output_subdir = os.path.join(mod_output_rootdir, 'subdir') XFormMergePipeline.modify_clean_image_dataset( self.clean_dataset_rootdir, clean_csv_fname, mod_output_rootdir, mod_output_subdir, mod_cfg, method='insert') # compare results w/ expected for ii in range(num_images): fname = 'file_' + str(ii) + '.png' triggered_data_fp = os.path.join(mod_output_rootdir, mod_output_subdir, fname) triggered_data = np.reshape( GenericImageEntity(cv2.imread(triggered_data_fp, -1)).get_data(), (num_datapoints_per_image, )) expected_data = np.arange(ii, ii + num_datapoints_per_image ) * mul_val + trigger_val + add_val self.assertTrue(np.allclose(triggered_data, expected_data))
def do(self, img_obj: ImageEntity, pattern_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual blending operations :param img_obj: image to be blended upon :param pattern_obj: the layer to be blended with the image & pasted :param random_state_obj: ignored :return: the merged object """ img = img_obj.get_data() img_mask = img_obj.get_mask() pattern = pattern_obj.get_data() pattern_mask = pattern_obj.get_mask() logger.debug( "Grain Merging img w/ shape={} and pattern w/ shape={} with opacity={:0.02f}" .format(str(img.shape), str(pattern.shape), self.opacity)) img_r, img_c, _ = img.shape pat_r, pat_c, _ = pattern.shape if pat_r > img_r or pat_c > img_c: msg = "Pattern to be merged into image is larger than the image!" logger.error(msg) raise ValueError(msg) if pat_r < img_r or pat_c < img_c: # TODO: make this an option so that we have multiple resize options logger.debug( "Resizing pattern to match image size with image background!") pattern_resized = img.copy() row_insert_idx = (img_r - pat_r) // 2 col_insert_idx = (img_c - pat_c) // 2 pattern_resized[row_insert_idx:row_insert_idx + pat_r, col_insert_idx:col_insert_idx + pat_c, :] = pattern pattern = pattern_resized.copy() pattern_mask_resized = np.zeros((img_r, img_c), dtype=bool) pattern_mask_resized[row_insert_idx:row_insert_idx + pat_r, col_insert_idx:col_insert_idx + pat_c] = pattern_mask pattern_mask = pattern_mask_resized.copy() blended_img = blend_modes.grain_merge(img.astype(float), pattern.astype(float), self.opacity) blended_img_raw = Image.fromarray(blended_img.astype(np.uint8)) pattern_raw = Image.fromarray(pattern.astype(np.uint8)) logger.debug("Pasting pattern into grain merged image") blended_img_raw.paste(pattern_raw, (0, 0), pattern_raw) final_img = np.array(blended_img_raw) # TODO: revisit whether this is the correct/intended behavior for the mask final_mask = img_mask & pattern_mask return GenericImageEntity(final_img, final_mask)
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual blurring operation :param input_obj: the input Entity to which noise is to be added :param random_state_obj: ignored :return: the transformed (noise added) Entity """ img = input_obj.get_data() blurred = cv2.GaussianBlur(img, (self.ksize, self.ksize), self.sigmaX, self.sigmaY) logger.debug("Added Gaussian Blur w/ Kernel Size=%d to Image" % (self.ksize,)) return GenericImageEntity(blurred, input_obj.get_mask())
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual noise insertion :param input_obj: the input Entity to which noise is to be added :param random_state_obj: a RandomState object used to sample the noise :return: the transformed (noise added) Entity """ img = input_obj.get_data() vals = len(np.unique(img)) vals = self.exponent_base ** np.ceil(np.log2(vals)) noisy = random_state_obj.poisson(img * vals) / float(vals) logger.debug("Added Poisson Noise to Image") return GenericImageEntity(noisy, input_obj.get_mask())
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual defined transformation :param input_obj: the input Entity to be transformed :param random_state_obj: ignored :return: the transformed Entity """ img = input_obj.get_data() logger.debug("Applying albumentations.RandomBrightnessContrast") img_xformed = self.darken_or_brighten_object( random_state=random_state_obj, image=img)['image'] return GenericImageEntity(img_xformed, input_obj.get_mask())
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual defined transformation :param input_obj: the input Entity to be transformed :param random_state_obj: ignored :return: the transformed Entity """ img = input_obj.get_data() original_n_chan = img.shape[2] rgb_img, alpha_ch = normalization_to_rgb(img, self.pre_normalize, "AddSunFlareXForm") # RandomSunFlare requires center and angle of flare to be normalized on [0.0, 1.0], if self.sunflare_object is None: roi = () if self.flare_center == (-1, -1): roi = (0.0, 0.0, 1.0, 0.5) else: roi_x = self.flare_center[0] / rgb_img.shape[1] roi_y = self.flare_center[1] / rgb_img.shape[0] roi = (roi_x, roi_y, roi_x, roi_y) angle_lower = self.angle / (2 * math.pi) angle_upper = self.angle / (2 * math.pi) if self.angle == -1: angle_lower, angle_upper = 0.0, 1.0 self.sunflare_object = albu.RandomSunFlare( roi, angle_lower, angle_upper, self.no_of_flare_circles - 1, self.no_of_flare_circles + 1, self.src_radius, self.src_color, always_apply=True) logger.debug( "Applying albumentations.RandomSunFlare with center=%s, angle=%0.02f, # flare-circles=%d," "flare-radius=%d, color=%s, pre_normalize=%s, post_normalize=%s" % (str(self.flare_center), self.angle, self.no_of_flare_circles, self.src_radius, str( self.src_color), self.pre_normalize, self.post_normalize)) rgb_img_xformed = self.sunflare_object(random_state=random_state_obj, image=rgb_img)['image'] img_xformed = normalization_from_rgb(rgb_img_xformed, alpha_ch, self.post_normalize, original_n_chan, "AddSunFlareXForm") return GenericImageEntity(img_xformed, input_obj.get_mask())
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual noise insertion :param input_obj: the input Entity to which noise is to be added :param random_state_obj: a RandomState object used to sample the noise :return: the transformed (noise added) Entity """ img = input_obj.get_data() row, col, ch = img.shape sigma = self.var ** 0.5 gaussian_noise = random_state_obj.normal(self.mean, sigma, (row, col, ch)) gaussian_noise = gaussian_noise.reshape(row, col, ch) noisy = img + gaussian_noise logger.debug("Added Gaussian Noise to Image") return GenericImageEntity(noisy, input_obj.get_mask())
def do(self, img_obj: ImageEntity, pattern_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual Merge operation on the input and pattern :param img_obj: image to be added :param pattern_obj: pattern to be added :param random_state_obj: ignored :return: the merged object """ logger.debug( "Add Merging img w/ shape=%s and pattern w/ shape=%s", (str(img_obj.get_data().shape), str(pattern_obj.get_data().shape))) img_out = cv2.add(img_obj.get_data(), pattern_obj.get_data()) # TODO: revisit whether this is the correct behavior for the mask mask_out = cv2.add(img_obj.get_mask(), pattern_obj.get_mask()) return GenericImageEntity(img_out, mask_out)
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual defined transformation :param input_obj: the input Entity to be transformed :param random_state_obj: ignored :return: the transformed Entity """ img = input_obj.get_data() original_n_chan = img.shape[2] rgb_img, alpha_ch = normalization_to_rgb(img, self.pre_normalize, "AddShadowXForm") if self.shadow_object is None: no_of_shadows_lower, no_of_shadows_upper = self.no_of_shadows, self.no_of_shadows # RandomShadow requires roi to be normalized on [0.0, 1.0] roi = () if self.rectangular_roi == (-1, -1, -1, -1): roi = (0.0, 0.5, 1.0, 1.0) else: roi_x1 = self.rectangular_roi[0] / rgb_img.shape[1] roi_y1 = self.rectangular_roi[1] / rgb_img.shape[0] roi_x2 = self.rectangular_roi[2] / rgb_img.shape[1] roi_y2 = self.rectangular_roi[3] / rgb_img.shape[0] roi = (roi_x1, roi_y1, roi_x2, roi_y2) self.shadow_object = albu.RandomShadow(roi, no_of_shadows_lower, no_of_shadows_upper, self.shadow_dimension, always_apply=True) logger.debug( "Applying albumentations.RandomShadow with shadows=%d, ROI=%s, dimension=%d, pre_normalization=%s," "post_normalization=%s" % ( self.no_of_shadows, str(self.rectangular_roi), self.shadow_dimension, self.pre_normalize, self.post_normalize, )) rgb_img_xformed = self.shadow_object(random_state=random_state_obj, image=rgb_img)['image'] img_xformed = normalization_from_rgb(rgb_img_xformed, alpha_ch, self.post_normalize, original_n_chan, "AddShadowXForm") return GenericImageEntity(img_xformed, input_obj.get_mask())
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Performs the scaling on an input Entity using skimage.transform.rescale :param input_obj: the input object to be scaled :param random_state_obj: ignored :return: the transformed Entity """ img = input_obj.get_data() mask = input_obj.get_mask() logger.info("Applying %0.02f brightning of image" % (self.brightness, )) enhancer = ImageEnhance.Sharpness(Image.fromarray(img)) img_brightned = np.array(enhancer.enhance(self.brightness)) return GenericImageEntity(img_brightned, mask)
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual conversion :param input_obj: the input Entity to be transformed :param random_state_obj: a np.random.RandomState object used to sample the colors and maintain reproducibility :return: the transformed Entity """ img = input_obj.get_data() if len(img.shape) != 3: raise ValueError("Image is not RGB channel - convert first!") img[img[:, :, 2].squeeze() > self.thresh, 2] = random_state_obj.choice(255) img[img[:, :, 1].squeeze() > self.thresh, 1] = random_state_obj.choice(255) img[img[:, :, 0].squeeze() > self.thresh, 0] = random_state_obj.choice(255) logger.info("Converted 3-channel Grayscale image to a random color") return GenericImageEntity(img, input_obj.get_mask())
def test_simple_random_insert(self): pattern = GenericImageEntity(np.ones((5, 5, 3)) * 3) target_img = np.ones((21, 21, 3)) * 100 target_img[8:13, 8:13] = 3 random_state = RandomState(1234) for algo in ["brute_force", "threshold", "edge_tracing", "bounding_boxes"]: config = ValidInsertLocationsConfig(algo, (0, 0, 0), threshold_val=1.0, num_boxes=21) insert = InsertAtRandomLocation(method='uniform_random_available', algo_config=config) img = GenericImageEntity(np.ones((21, 21, 3)) * 100) img.get_data()[8:13, 8:13] = 0 insert.do(img, pattern, random_state) self.assertTrue(np.array_equal(target_img, img.get_data()))
def do(self, img_obj: ImageEntity, pattern_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual blend operation on an input and pattern :param img_obj: image to be blended upon :param pattern_obj: the layer to be blended with the image :param random_state_obj: ignored :return: the merged object """ img = img_obj.get_data() img_mask = img_obj.get_mask() pattern = pattern_obj.get_data() pattern_mask = pattern_obj.get_mask() logger.debug( "Grain Merging img w/ shape=%s and pattern w/ shape=%s with opacity=%0.02f", (str(img.shape), str(pattern.shape), self.opacity)) img_out = blend_modes.grain_merge(img.astype(float), pattern.astype(float), self.opacity) mask_out = img_mask & pattern_mask return GenericImageEntity(img_out, mask_out)
def do(self, input_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual specified transformation on the input Entity :param input_obj: the input object to be transformed :param random_state_obj: a np.random.RandomState object which performs the sampling of which channel to modify :return: the transformed Entity """ img = input_obj.get_data() if len(img.shape) != 3: raise ValueError("Image is not RGB channel - convert first!") channel = random_state_obj.choice(3) # choose which channel to modify # zero out the channels that we don't want color for to produce a # grayscale "like" color image for ii in range(3): if ii != channel: img[:, :, ii] = 0 logger.info("Converted 3-channel Grayscale image with full color applied to channel=%d" % (channel,)) return GenericImageEntity(img, input_obj.get_mask())
def do(self, img_obj: ImageEntity, pattern_obj: ImageEntity, random_state_obj: RandomState) -> ImageEntity: """ Perform the actual blending operations :param img_obj: image to be blended upon :param pattern_obj: the layer to be blended with the brightness adjusted & image & pasted :param random_state_obj: ignored :return: the merged object """ img = img_obj.get_data() pattern = pattern_obj.get_data() pattern_mask = pattern_obj.get_mask() # adjust brightness of pattern to match image logger.debug("Adjusting brightness according to:" + str(self.lighting_adjuster)) pattern_adjusted = self.lighting_adjuster(pattern, img) pattern_adjusted_obj = GenericImageEntity(pattern_adjusted, pattern_mask) logger.debug("Performing GrainMergePaste with opacity = %0.02f", (self.opacity)) merger = GrainMergePaste(self.opacity) return merger.do(img_obj, pattern_adjusted_obj, random_state_obj)
def test_modify_clean_dataset_regenerateMode(self): # test configuration num_images = 10 num_datapoints_per_image = 10 merge_add_val = 20 # create "clean" dataset dd_list = [] data_merger = DummyMerge() for ii in range(num_images): bg_data = GenericImageEntity( np.linspace(ii, ii + 1, num_datapoints_per_image)) bg_data_fname = os.path.join(self.clean_dataset_rootdir, 'bg_file_' + str(ii) + '.png') cv2.imwrite(bg_data_fname, bg_data.get_data()) fg_data = GenericImageEntity( np.linspace(ii + 2, ii + 3, num_datapoints_per_image)) fg_data_fname = os.path.join(self.clean_dataset_rootdir, 'fg_file_' + str(ii) + '.png') cv2.imwrite(fg_data_fname, fg_data.get_data()) # create the combined "file" data = data_merger.do(bg_data, fg_data, RandomState()) data_fname = 'file_' + str(ii) + '.png' cv2.imwrite(os.path.join(self.clean_dataset_rootdir, data_fname), data.get_data()) dd_list.append({ 'bg_file': os.path.abspath(bg_data_fname), 'fg_file': os.path.abspath(fg_data_fname), 'file': data_fname }) clean_df = pd.DataFrame(dd_list) clean_csv_fname = 'data.csv' clean_df.to_csv(os.path.join(self.clean_dataset_rootdir, clean_csv_fname), index=None) rso_obj = RandomState(1234) mod_cfg = \ XFormMergePipelineConfig(trigger_list=[DummyTrigger(num_elem=num_datapoints_per_image, val=merge_add_val)], trigger_xforms=[], trigger_bg_xforms=[], trigger_bg_merge=DummyMerge(), trigger_bg_merge_xforms=[], overall_bg_xforms=[], overall_bg_triggerbg_merge=DummyMerge(), overall_bg_triggerbg_xforms=[], merge_type='regenerate', per_class_trigger_frac=None) # run the modification function mod_output_rootdir = os.path.join(self.clean_dataset_rootdir, 'modified') mod_output_subdir = os.path.join(mod_output_rootdir, 'subdir') XFormMergePipeline.modify_clean_image_dataset( self.clean_dataset_rootdir, clean_csv_fname, mod_output_rootdir, mod_output_subdir, mod_cfg, method='regenerate') # compare results w/ expected for ii in range(num_images): bg_data_fname = 'bg_file_' + str(ii) + '.png' bg_data_fp = os.path.join(self.clean_dataset_rootdir, bg_data_fname) bg_data = cv2.imread(bg_data_fp, -1) fg_data_fname = 'fg_file_' + str(ii) + '.png' fg_data_fp = os.path.join(self.clean_dataset_rootdir, fg_data_fname) fg_data = cv2.imread(fg_data_fp, -1) triggered_data_fp = os.path.join(mod_output_rootdir, mod_output_subdir, 'file_' + str(ii) + '.png') triggered_data = cv2.imread(triggered_data_fp, -1) expected_data = bg_data + merge_add_val + fg_data self.assertTrue(np.allclose(triggered_data, expected_data))
def do(self, input_obj: ImageEntity, random_state_obj): img = input_obj.get_data() img *= self.multiply_const return GenericImageEntity(img, input_obj.get_mask())
class TestTriggerPatterns(unittest.TestCase): def setUp(self): self.random_state = RandomState(1234) self.rgb_entity = GenericImageEntity(self.random_state.rand(1000, 1000, 3).astype(np.uint8)) self.rgba_entity = GenericImageEntity(self.random_state.rand(500, 500, 4).astype(np.uint8)) self.noop = NoOpFilterXForm() self.noop_down = NoOpFilterXForm("BGR", True, False) self.gotham = GothamFilterXForm() self.nashville = NashvilleFilterXForm() self.kelvin = KelvinFilterXForm() self.lomo = LomoFilterXForm() self.toaster = ToasterXForm() def test_data_integrity(self): start_array = self.rgb_entity.get_data() end_array = self.noop.do(self.rgb_entity, self.random_state).get_data() self.assertTrue(np.array_equal(start_array, end_array)) start_array = self.rgba_entity.get_data() end_array = self.noop.do(self.rgba_entity, self.random_state).get_data() self.assertTrue(np.array_equal(start_array, end_array)) start_array = self.rgba_entity.get_data() end_array = self.noop_down.do(self.rgba_entity, self.random_state).get_data() self.assertTrue(np.array_equal(start_array[:, :, :3], end_array)) def test_gotham(self): out_rgb = self.gotham.do(self.rgb_entity, self.random_state) self.assertEqual(3, out_rgb.get_data().shape[2]) out_rgba = self.gotham.do(self.rgba_entity, self.random_state) self.assertEqual(4, out_rgba.get_data().shape[2]) def test_nashville(self): out_rgb = self.nashville.do(self.rgb_entity, self.random_state) self.assertEqual(3, out_rgb.get_data().shape[2]) out_rgba = self.nashville.do(self.rgba_entity, self.random_state) self.assertEqual(4, out_rgba.get_data().shape[2]) def test_kelvin(self): out_rgb = self.kelvin.do(self.rgb_entity, self.random_state) self.assertEqual(3, out_rgb.get_data().shape[2]) out_rgba = self.kelvin.do(self.rgba_entity, self.random_state) self.assertEqual(4, out_rgba.get_data().shape[2]) def test_lomo(self): out_rgb = self.lomo.do(self.rgb_entity, self.random_state) self.assertEqual(3, out_rgb.get_data().shape[2]) out_rgba = self.lomo.do(self.rgba_entity, self.random_state) self.assertEqual(4, out_rgba.get_data().shape[2]) def test_toaster(self): out_rgb = self.toaster.do(self.rgb_entity, self.random_state) self.assertEqual(3, out_rgb.get_data().shape[2]) out_rgba = self.toaster.do(self.rgba_entity, self.random_state) self.assertEqual(4, out_rgba.get_data().shape[2]) def test_channel_order(self): bgr_lomo = LomoFilterXForm('BGR') rgb_lomo = LomoFilterXForm('RGB') bgr_img = np.concatenate((np.ones((5, 5, 1)), np.zeros((5, 5, 2))), axis=2).astype(np.uint8) rgb_img = np.concatenate((np.zeros((5, 5, 2)), np.ones((5, 5, 1))), axis=2).astype(np.uint8) bgr_result = bgr_lomo.do(GenericImageEntity(bgr_img), random_state_obj=self.random_state) rgb_result = rgb_lomo.do(GenericImageEntity(rgb_img), random_state_obj=self.random_state) self.assertTrue(np.array_equal(bgr_result.get_data()[:, :, 0], rgb_result.get_data()[:, :, 2])) bgr_switched_result = rgb_lomo.do(GenericImageEntity(bgr_img), random_state_obj=self.random_state) rgb_switched_result = bgr_lomo.do(GenericImageEntity(rgb_img), random_state_obj=self.random_state) # transform should be modifying R and G channels, but is instead modifying B and G channels, setting to zero self.assertTrue(np.array_equal(bgr_switched_result.get_data(), np.zeros((5, 5, 3)))) self.assertTrue(np.array_equal(rgb_switched_result.get_data(), np.zeros((5, 5, 3))))
def do(self, input1, input2, random_state_obj): img1 = input1.get_data() img2 = input2.get_data() return GenericImageEntity(img1 + img2, input1.get_mask())
def do(self, input_obj, random_state_obj): img = input_obj.get_data() img += self.add_const return GenericImageEntity(img, input_obj.get_mask())