def execute(self):
        padded_bcube = self.bcube.uncrop(self.pad, self.mip)
        for k, specs in enumerate(self.src_specs[::-1]):
            z = specs['src_z']
            mask_id = specs['mask_id']
            bcube = padded_bcube.reset_coords(zs=z, ze=z+1, in_place=False)
            imgs = {}
            for name in ['src_img', 'src_mask', 'src_field']:
                layer = self.src_layers[str(specs[name])]
                if name == 'src_mask':
                    layer.binarizer = helpers.Binarizer(['eq', mask_id])
                imgs[name] = layer.read(bcube=bcube, mip=self.mip)
            mask = residuals.res_warp_img(imgs['src_mask'].float(), 
                                          imgs['src_field'])
            mask = (mask > 0.4).bool()
            cropped_mask = helpers.crop(mask, self.pad)
            img = residuals.res_warp_img(imgs['src_img'].float(), 
                                         imgs['src_field'])
            cropped_img = helpers.crop(img, self.pad)
            if k == 0:
                dst_img = cropped_img
                dst_img[~cropped_mask] = 0
            else:
                dst_img[cropped_mask] = cropped_img[cropped_mask]

        self.dst_layer.write(dst_img, bcube=self.bcube, mip=self.mip)
示例#2
0
    def execute(self):
        src_bcube = self.bcube.uncrop(self.pad, self.mip)
        tgt_bcube = src_bcube.translate(z_offset=self.tgt_z_offset)

        processor = procspec.parse_proc(spec_str=self.processor_spec)

        tgt_translation, tgt_data_dict = self.tgt_stack.read_data_dict(
            tgt_bcube, mip=self.mip, stack_name='tgt')

        # Compensate if target was moved to one side a lot
        tgt_drift = helpers.percentile_trans_adjuster(
            tgt_data_dict['tgt_agg_field'],
            unaligned_img=tgt_data_dict['tgt_img'])

        src_translation, src_data_dict = self.src_stack.read_data_dict(
            src_bcube, mip=self.mip, stack_name='src', translation=tgt_drift)
        #translation_adjuster=helpers.percentile_trans_adjuster)

        processor_input = {**src_data_dict, **tgt_data_dict}

        predicted_field = processor(processor_input, output_key='src_cf_field')

        predicted_field.x += tgt_drift.x
        predicted_field.y += tgt_drift.y

        cropped_field = helpers.crop(predicted_field, self.crop)
        self.dst_layer.write(cropped_field, bcube=self.bcube, mip=self.mip)
示例#3
0
    def execute(self):
        corgie_logger.debug(f"ComputeFieldTask")
        src_bcube = self.bcube.uncrop(self.pad, self.mip)
        tgt_bcube = src_bcube.translate(z_offset=self.tgt_z_offset)

        processor = procspec.parse_proc(spec_str=self.processor_spec)

        corgie_logger.debug(f"Read target")
        tgt_translation, tgt_data_dict = self.tgt_stack.read_data_dict(
            tgt_bcube, mip=self.mip, stack_name="tgt")

        # Compensate if target was moved to one side a lot
        # tgt_drift = helpers.percentile_trans_adjuster(
        #     tgt_data_dict["tgt_agg_field"], unaligned_img=tgt_data_dict["tgt_img"]
        # )
        tgt_drift = helpers.Translation(0, 0)
        corgie_logger.debug(f"Read source")
        src_translation, src_data_dict = self.src_stack.read_data_dict(
            src_bcube, mip=self.mip, stack_name="src", translation=tgt_drift)
        # translation_adjuster=helpers.percentile_trans_adjuster)
        # )
        processor_input = {**src_data_dict, **tgt_data_dict}

        corgie_logger.debug(f"Compute field")
        predicted_field = processor(processor_input, output_key="src_cf_field")

        predicted_field.x += tgt_drift.x
        predicted_field.y += tgt_drift.y

        cropped_field = helpers.crop(predicted_field, self.crop)
        corgie_logger.debug(f"Write field")
        self.dst_layer.write(cropped_field, bcube=self.bcube, mip=self.mip)
示例#4
0
    def execute(self):
        src_bcube = self.bcube.uncrop(self.pad, self.mip)

        src_data = self.src_layer.read(src_bcube, mip=self.mip)

        result = (~src_data.field().from_pixels()).pixels()

        cropped_result = helpers.crop(result, self.crop)

        self.dst_layer.write(cropped_result, bcube=self.bcube, mip=self.mip)
示例#5
0
 def execute(self):
     corgie_logger.debug(f"ComposeWithDistanceTask, {self.bcube}")
     corgie_logger.debug(f"input_fields: {self.input_fields}")
     corgie_logger.debug(f"z_list: {self.z_list}")
     pbcube = self.bcube.uncrop(self.pad, self.mip)
     fields = PyramidDistanceFieldSet(
         decay_dist=self.decay_dist,
         blur_rate=self.blur_rate,
         layers=self.input_fields,
     )
     field = fields.read(bcube=pbcube, z_list=self.z_list, mip=self.mip)
     cropped_field = helpers.crop(field, self.pad)
     self.output_field.write(cropped_field, bcube=self.bcube, mip=self.mip)
    def execute(self):
        src_bcube = self.bcube.uncrop(self.pad, self.mip)

        processor = procspec.parse_proc(spec_str=self.processor_spec)

        src_translation, src_data_dict = self.src_stack.read_data_dict(
            src_bcube, mip=self.mip, stack_name='src')

        processor_input = {**src_data_dict}

        result = processor(processor_input, output_key='output')

        cropped_result = helpers.crop(result, self.crop)
        self.dst_layer.write(cropped_result, bcube=self.bcube, mip=self.mip)
示例#7
0
    def execute(self):
        device = "cuda" if torch.cuda.is_available() else "cpu"
        padded_bcube = self.bcube.uncrop(self.pad, self.mip)
        for k, specs in enumerate(self.src_specs[::-1]):
            src_z = specs["src_z"]
            dst_z = self.bcube.z_range()[0]

            corgie_logger.info(f"Load fields for {padded_bcube}")
            # backwards compatible
            if not isinstance(specs["src_field"], list):
                specs["src_field"] = [specs["src_field"]]
            mask_layer = self.src_layers[str(specs["src_mask"])]

            field_ids = list(map(str, specs["src_field"]))
            corgie_logger.info(f"field ids={field_ids}")
            z_list = specs.get("src_field_z", [src_z] * len(field_ids))
            fields = FieldSet([self.src_layers[n] for n in field_ids])
            field = fields.read(
                bcube=padded_bcube, z_list=z_list, mip=self.mip, device=device
            )
            bcube = padded_bcube.reset_coords(zs=src_z, ze=src_z + 1, in_place=False)

            mask_trans = helpers.percentile_trans_adjuster(field)
            mask_trans = mask_trans.round_to_mip(self.mip, mask_layer.data_mip)
            corgie_logger.debug(f"mask_trans: {mask_trans}")

            mask_bcube = bcube.translate(
                x_offset=mask_trans.y, y_offset=mask_trans.x, mip=self.mip
            )

            corgie_logger.info(f"Load masks for {mask_bcube}")
            mask_id = specs["mask_id"]
            mask_layer.binarizer = helpers.Binarizer(["eq", mask_id])
            mask = mask_layer.read(bcube=mask_bcube, mip=self.mip, device=device)
            mask = residuals.res_warp_img(
                mask.float(), field - mask_trans.to_tensor(device=field.device)
            ).tensor()
            mask = (mask > 0.4).bool()
            cropped_mask = helpers.crop(mask, self.pad)

            relabel_id = torch.as_tensor(specs.get("relabel_id", k + 1), dtype=torch.uint8)
            if k == 0:
                dst_img = cropped_mask * relabel_id
                dst_img[~cropped_mask] = 0
            else:
                dst_img[cropped_mask] = cropped_mask[cropped_mask] * relabel_id

        self.dst_layer.write(dst_img.cpu(), bcube=self.bcube, mip=self.mip)
    def execute(self):
        src_bcube = self.bcube.uncrop(self.pad, self.mip)
        tgt_bcube = src_bcube.translate(z=self.tgt_z_offset)

        processor = procspec.parse_proc(spec_str=self.processor_spec, default_output='src_cf_field')

        src_translation, src_data_dict = self.src_stack.read_data_dict(src_bcube,
                mip=self.mip, stack_name='src')
        tgt_translation, tgt_data_dict = self.tgt_stack.read_data_dict(tgt_bcube,
                mip=self.mip, stack_name='tgt')

        processor_input = {**src_data_dict, **tgt_data_dict}

        predicted_field = processor(processor_input)
        cropped_field = helpers.crop(predicted_field, self.crop)
        self.dst_layer.write(cropped_field, bcube=self.bcube, mip=self.mip)
示例#9
0
    def execute(self):
        src_bcube = self.bcube.uncrop(self.pad, self.mip)
        tgt_bcube = src_bcube.translate(z_offset=self.tgt_z_offset)

        processor = procspec.parse_proc(spec_str=self.processor_spec)

        _, tgt_data_dict = self.tgt_stack.read_data_dict(tgt_bcube,
                                                         mip=self.mip,
                                                         stack_name='tgt')

        _, src_data_dict = self.src_stack.read_data_dict(src_bcube,
                                                         mip=self.mip,
                                                         stack_name='src')

        processor_input = {**src_data_dict, **tgt_data_dict}

        result = processor(processor_input, output_key='result')

        cropped_result = helpers.crop(result, self.crop)
        self.dst_layer.write(cropped_result, bcube=self.bcube, mip=self.mip)
示例#10
0
    def execute(self):
        corgie_logger.debug(f"CombineMaskTask, {self.bcube}")
        pbcube = self.bcube.uncrop(self.pad, self.mip)
        bf = BoolFn(self.exp)
        for z in range(*self.bcube.z_range()):

            def eval(exp):
                w, k, o = exp["weight"], exp["key"], exp["offset"]
                bcube = pbcube.reset_coords(zs=z + o, ze=z + o + 1, in_place=False)
                layer = self.src_stack.layers[k]
                return w * layer.read(bcube=bcube, mip=self.mip)

            m = bf(eval).to(torch.uint8)
            m = helpers.crop(m, self.pad)
            bcube = self.bcube.reset_coords(zs=z, ze=z + 1, in_place=False)
            self.dst_layer.write(m, bcube=bcube, mip=self.mip)

        # This task can be used with caching
        for layer in self.src_stack.layers.values():
            layer.flush(self.mip)
示例#11
0
 def execute(self):
     corgie_logger.debug(f"BroadcastTask, {self.bcube}")
     input_fields = self.stitching_fields[::-1]
     if len(self.z_list) != len(input_fields):
         fmul = len(self.z_list) // len(input_fields)
         frem = len(self.z_list) % len(input_fields)
         input_fields = input_fields[::-1]
         input_fields = fmul * input_fields + input_fields[:frem]
         input_fields = input_fields[::-1]
     input_fields += [self.block_field]
     z_list = self.z_list + [self.bcube.z_range()[0]]
     corgie_logger.debug(f"input_fields: {input_fields}")
     corgie_logger.debug(f"z_list: {z_list}")
     pbcube = self.bcube.uncrop(self.pad, self.mip)
     corgie_logger.debug(f"pbcube: {pbcube}")
     fields = PyramidDistanceFieldSet(decay_dist=self.decay_dist,
                                      blur_rate=self.blur_rate,
                                      layers=input_fields)
     field = fields.read(bcube=pbcube, z_list=z_list, mip=self.mip)
     cropped_field = helpers.crop(field, self.pad)
     self.output_field.write(cropped_field, bcube=self.bcube, mip=self.mip)
示例#12
0
    def execute(self):
        src_bcube = self.bcube.uncrop(self.pad, self.mip)
        tgt_bcube = src_bcube.translate(z_offset=self.tgt_z_offset)

        processor = procspec.parse_proc(spec_str=self.processor_spec)

        _, tgt_data_dict = self.tgt_stack.read_data_dict(tgt_bcube,
                                                         mip=self.mip,
                                                         stack_name="tgt")

        _, src_data_dict = self.src_stack.read_data_dict(src_bcube,
                                                         mip=self.mip,
                                                         stack_name="src")

        processor_input = {**src_data_dict, **tgt_data_dict}

        result = processor(processor_input, output_key="result")

        tgt_pixel_data = self.pixel_offset_layer.read(
            bcube=self.bcube.translate(z_offset=self.tgt_z_offset),
            mip=self.mip)
        written_pixel_data = self.pixel_offset_layer.read(bcube=self.bcube,
                                                          mip=self.mip)
        written_mask_data = self.dst_layer.read(bcube=self.bcube, mip=self.mip)
        result = result.to(device=written_mask_data.device)
        cropped_result = helpers.crop(result, self.crop)
        if self.seethrough_limit > 0:
            seethrough_mask = (cropped_result > 0) & (tgt_pixel_data <
                                                      self.seethrough_limit)
        else:
            seethrough_mask = cropped_result > 0
        written_mask_data[seethrough_mask] = True
        written_pixel_data[seethrough_mask] = (torch.minimum(
            tgt_pixel_data[seethrough_mask],
            torch.ones_like(tgt_pixel_data[seethrough_mask]) * 254,
        ) + 1)
        self.dst_layer.write(written_mask_data, bcube=self.bcube, mip=self.mip)
        self.pixel_offset_layer.write(written_pixel_data,
                                      bcube=self.bcube,
                                      mip=self.mip)
示例#13
0
    def execute(self):
        tgt_bcube = self.bcube.uncrop(self.pad, self.mip)
        _, tgt_data_dict = self.tgt_stack.read_data_dict(tgt_bcube,
                                                         mip=self.mip,
                                                         stack_name="tgt")

        dst_layers = self.dst_stack.get_layers_of_type("img")
        for dst_layer in dst_layers:
            z_offset = int(dst_layer.name)
            src_bcube = tgt_bcube.translate(z_offset=z_offset)
            processor = procspec.parse_proc(spec_str=self.processor_spec)

            _, src_data_dict = self.src_stack.read_data_dict(src_bcube,
                                                             mip=self.mip,
                                                             stack_name="src")

            processor_input = {**src_data_dict, **tgt_data_dict}

            result = processor(processor_input, output_key="result")
            crop = self.pad // 2**(self.dst_mip - self.mip)
            cropped_result = helpers.crop(result, crop)
            dst_layer.write(cropped_result, bcube=self.bcube, mip=self.dst_mip)
示例#14
0
    def execute(self):
        padded_bcube = self.bcube.uncrop(self.pad, self.mip)

        for f in self.additional_fields:
            self.src_stack.add_layer(f)

        src_translation, src_data_dict = self.src_stack.read_data_dict(
            padded_bcube, mip=self.mip, stack_name='src')
        agg_field = src_data_dict[f"src_agg_field"]

        if self.blackout_masks:
            mask_layers = self.dst_stack.get_layers_of_type(["img", "mask"])
            mask = helpers.read_mask_list(mask_layers, self.bcube, self.mip)
        else:
            mask = None

        if self.render_masks:
            write_layers = self.dst_stack.get_layers_of_type(["img", "mask"])
        else:
            write_layers = self.dst_stack.get_layers_of_type("img")

        for l in write_layers:
            src = src_data_dict[f"src_{l.name}"]

            if agg_field is not None:
                warped_src = residuals.res_warp_img(src.float(), agg_field)
            else:
                warped_src = src

            if mask is not None:
                warped_src[mask] = 0.0

            cropped_out = helpers.crop(warped_src, self.pad)
            l.write(cropped_out, bcube=self.bcube, mip=self.mip)

        for f in self.additional_fields:
            self.src_stack.remove_layer(f.name)
示例#15
0
    def execute(self):
        padded_bcube = self.bcube.uncrop(self.pad, self.mip)
        seethrough_bcube = self.bcube.translate(
            z_offset=self.seethrough_offset)

        for f in self.additional_fields:
            #just in case the "additional" field is actually already a part of src_stack
            if f not in self.src_stack.layers.values():
                self.src_stack.add_layer(f)

        src_translation, src_data_dict = self.src_stack.read_data_dict(
            padded_bcube, mip=self.mip, add_prefix=False)
        agg_field = src_data_dict[f"agg_field"]
        agg_mask = None

        if self.blackout_masks or self.seethrough:
            mask_layers = self.dst_stack.get_layers_of_type(["mask"])
            mask_layer_names = [l.name for l in mask_layers]
            for n, d in six.iteritems(src_data_dict):
                if n in mask_layer_names:
                    if agg_mask is None:
                        agg_mask = d
                    else:
                        agg_mask = ((agg_mask + d) > 0).byte()

            if agg_mask is not None:
                coarsen_factor = int(2**(6 - self.mip))
                agg_mask = helpers.coarsen_mask(agg_mask, coarsen_factor)
                if agg_field is not None:
                    warped_mask = residuals.res_warp_img(
                        agg_mask.float(), agg_field)
                else:
                    warped_mask = agg_mask

                warped_mask = (warped_mask > 0.4).byte()
            else:
                warped_mask = None

        if self.render_masks:
            write_layers = self.dst_stack.get_layers_of_type(["img", "mask"])
        else:
            write_layers = self.dst_stack.get_layers_of_type("img")

        for l in write_layers:
            src = src_data_dict[f"{l.name}"]
            if agg_field is not None:
                warped_src = residuals.res_warp_img(src.float(), agg_field)
            else:
                warped_src = src

            cropped_out = helpers.crop(warped_src, self.pad)

            if self.blackout_masks or self.seethrough:
                if warped_mask is not None:
                    warped_mask = helpers.crop(warped_mask, self.pad)

                if l.get_layer_type(
                ) == "img" and self.blackout_masks and warped_mask is not None:
                    cropped_out[warped_mask] = self.blackout_value

                if l.get_layer_type(
                ) == "img" and self.seethrough and warped_mask is not None:
                    seethrough_data = l.read(bcube=seethrough_bcube,
                                             mip=self.mip)

                    coarsen_factor = int(2**(6 - self.mip))
                    seethrough_mask = helpers.coarsen_mask(
                        warped_mask, coarsen_factor)
                    seethrough_mask[cropped_out == 0] = True

                    cropped_out[seethrough_mask] = \
                            seethrough_data[seethrough_mask]

                    seenthru = (cropped_out[seethrough_mask] != 0).sum()
                    corgie_logger.debug(f"Seenthrough {seenthru} pixels")

            l.write(cropped_out, bcube=self.bcube, mip=self.mip)
示例#16
0
    def execute(self):
        padded_bcube = self.bcube.uncrop(self.pad, self.mip)

        for f in self.additional_fields:
            # just in case the "additional" field is actually already a part of src_stack
            if f not in self.src_stack.layers.values():
                self.src_stack.add_layer(f)

        src_translation, src_data_dict = self.src_stack.read_data_dict(
            padded_bcube,
            mip=self.mip,
            add_prefix=False,
            translation_adjuster=helpers.percentile_trans_adjuster,
        )
        agg_field = src_data_dict[f"agg_field"]
        if agg_field is not None:
            agg_field[:, 0] -= src_translation.x
            agg_field[:, 1] -= src_translation.y

        # Produce and aggregate mask if there's a need to blackout all masks
        agg_mask = None
        if self.blackout_masks:
            mask_layers = self.dst_stack.get_layers_of_type(["mask"])
            mask_layer_names = [l.name for l in mask_layers]
            for n, d in six.iteritems(src_data_dict):
                if n in mask_layer_names:
                    if agg_mask is None:
                        agg_mask = d
                    else:
                        agg_mask = ((agg_mask + d) > 0).byte()

            # if the mask is not empty, warp it and coarsen it for seethrough
            if agg_mask is not None:
                coarsen_factor = int(2**(6 - self.mip))
                agg_mask = helpers.coarsen_mask(agg_mask, coarsen_factor)
                if agg_field is not None:
                    warped_mask = residuals.res_warp_img(
                        agg_mask.float(), agg_field)
                else:
                    warped_mask = agg_mask

                warped_mask = (warped_mask > 0.4).byte()
                # To save time, we won't be blacking out stuff that gets cropped anyway
                warped_mask = helpers.crop(warped_mask, self.pad)
            else:
                warped_mask = None

        if self.render_masks:
            write_layers = self.dst_stack.get_layers_of_type(["img", "mask"])
        else:
            write_layers = self.dst_stack.get_layers_of_type("img")

        for l in write_layers:
            src = src_data_dict[f"{l.name}"]
            '''
            if (src != 0).sum():
                import pdb; pdb.set_trace()
            else:
                return
            '''
            if agg_field is not None:
                warped_src = residuals.res_warp_img(src.float(), agg_field)
            else:
                warped_src = src

            cropped_out = helpers.crop(warped_src, self.pad)

            if l.get_layer_type() == "img":
                if self.blackout_masks and warped_mask is not None:
                    cropped_out[warped_mask] = self.blackout_value

                if self.preserve_zeros and agg_field is not None:
                    src_zero_mask = src == 0
                    warped_zero_mask = residuals.res_warp_img(
                        src_zero_mask.float(), agg_field)
                    warped_zero_mask = (warped_zero_mask > 0.4).byte()
                    warped_zero_mask = helpers.crop(warped_zero_mask, self.pad)
                    cropped_out[warped_zero_mask] = 0

                if self.seethrough_mask_layer is not None:
                    seethrough_mask = (self.seethrough_mask_layer.read(
                        bcube=self.bcube, mip=self.mip) != 0)
                    seethrough_bcube = self.bcube.translate(
                        z_offset=self.seethrough_offset)
                    seethrough_data = l.read(bcube=seethrough_bcube,
                                             mip=self.mip)

                    cropped_out[seethrough_mask] = seethrough_data[
                        seethrough_mask]

                    seenthru = (cropped_out[seethrough_mask] != 0).sum()
                    corgie_logger.debug(f"Seenthrough {seenthru} pixels")

            l.write(cropped_out, bcube=self.bcube, mip=self.mip)

        for f in self.additional_fields:
            # remove fields we added
            self.src_stack.remove_layer(f.name)
示例#17
0
 def spoof_x_y_residual(self, x_d, y_d, mip, crop_amount=0):
     x_res = crop(self.x_res_displacement(x_d, mip=mip), crop_amount)
     y_res = crop(self.y_res_displacement(y_d, mip=mip), crop_amount)
     result = np.stack((x_res, y_res), axis=2)
     result = np.expand_dims(result, 0)
     return result
示例#18
0
    def execute(self):
        device = "cuda" if torch.cuda.is_available() else "cpu"

        # Field padding
        padded_bcube = self.bcube.uncrop(self.pad, self.mip)
        for k, specs in enumerate(self.src_specs[::-1]):
            src_z = specs["src_z"]
            dst_z = self.bcube.z_range()[0]

            corgie_logger.info(f"Load fields for {padded_bcube}")
            # backwards compatible
            if not isinstance(specs["src_field"], list):
                specs["src_field"] = [specs["src_field"]]
            mask_layer = self.src_layers[str(specs["src_mask"])]

            field_ids = list(map(str, specs["src_field"]))
            corgie_logger.info(f"field ids={field_ids}")
            z_list = specs.get("src_field_z", [src_z] * len(field_ids))
            fields = FieldSet([self.src_layers[n] for n in field_ids])
            field = fields.read(
                bcube=padded_bcube, z_list=z_list, mip=self.mip, device=device
            )
            bcube = padded_bcube.reset_coords(zs=src_z, ze=src_z + 1, in_place=False)

            # Extend image/mask cutout to account for field spread
            render_pad = int((field.max_vector() - field.min_vector()).max().ceil().tensor().item())
            snap_factor = 2 ** (max(self.mip, mask_layer.data_mip) - self.mip)
            render_pad = math.ceil(render_pad / snap_factor) * snap_factor
            render_pad = min(render_pad, 4096)  # Safety

            render_bcube = bcube.uncrop(render_pad, self.mip)
            corgie_logger.debug(f"render_pad: {render_pad}")

            # Move image/mask cutout to account for field drift
            img_trans = helpers.percentile_trans_adjuster(field)
            mask_trans = img_trans.round_to_mip(self.mip, mask_layer.data_mip)
            corgie_logger.debug(f"img_trans: {img_trans} | mask_trans: {mask_trans}")

            img_bcube = render_bcube.translate(
                x_offset=img_trans.y, y_offset=img_trans.x, mip=self.mip
            )
            mask_bcube = render_bcube.translate(
                x_offset=mask_trans.y, y_offset=mask_trans.x, mip=self.mip
            )

            if render_pad > 0:
                field = torch.nn.functional.pad(field, [render_pad, render_pad, render_pad, render_pad], mode='replicate')

            corgie_logger.info(f"Load masks for {mask_bcube}")
            mask_id = specs["mask_id"]
            mask_layer.binarizer = helpers.Binarizer(["eq", mask_id])
            mask = mask_layer.read(bcube=mask_bcube, mip=self.mip, device=device)
            mask = residuals.res_warp_img(
                mask.float(), field - mask_trans.to_tensor(device=field.device)
            ).tensor()
            mask = (mask > 0.4).bool()
            cropped_mask = helpers.crop(mask, self.pad + render_pad)

            corgie_logger.info(f"Load image for {img_bcube}")
            if cropped_mask.sum() == 0:
                cropped_img = torch.zeros_like(cropped_mask, dtype=torch.float)
            else:
                img_layer = self.src_layers[str(specs["src_img"])]
                img = img_layer.read(bcube=img_bcube, mip=self.mip, device=device)
                img = residuals.res_warp_img(
                    img.float(), field - img_trans.to_tensor(device=field.device)
                )
                cropped_img = helpers.crop(img, self.pad + render_pad)

            # write to composite image
            if k == 0:
                dst_img = cropped_img
                dst_img[~cropped_mask] = 0
            else:
                dst_img[cropped_mask] = cropped_img[cropped_mask]

        self.dst_layer.write(dst_img.cpu(), bcube=self.bcube, mip=self.mip)