def _add_foreground_boxes(
        regions: list[dict[str, torch.Tensor]],
        first_frame: torch.Tensor,
        last_frame: torch.Tensor,
        kernel_size: int,
        binary_threshold: int,
    ) -> list[dict[str, torch.Tensor]]:
        """Add any foreground regions that were not detected by the region extractor.

        This method adds regions that likely belong to the foreground of the video
        scene, but were not detected by the region extractor module. The foreground
        pixels are determined by taking the pixel difference between two consecutive
        video frames and applying a binary threshold. The final detections consist of
        all connected components in the foreground that do not fall in one of the
        bounding boxes predicted by the region extractor.

        Args:
            regions (list[dict[str, torch.Tensor]]): Region detections for a batch of
                images, generated by the region extraction module.
            first_frame (torch.Tensor): Video frame at time t-1
            last_frame (torch.Tensor): Video frame at time t
            kernel_size (int): Kernel size for Gaussian smoothing applied to input
                frames
            binary_threshold (int): Binary threshold used in foreground detection,
                should be in range ``[0, 255]``

        Returns:
            list[dict[str, torch.Tensor]]: Region detections with foreground regions
                appended. Each dict contains:
                - boxes (torch.Tensor): Updated bounding boxes
                - labels (torch.Tensor): Updated class labels
                - scores (torch.Tensor): Updated confidence scores
                - masks (torch.Tensor): Updated instance masks
        """
        # apply gaussian blur to first and last frame
        first_frame = gaussian_blur(first_frame, [kernel_size, kernel_size])
        last_frame = gaussian_blur(last_frame, [kernel_size, kernel_size])

        # take the abs diff between the blurred images and convert to grayscale
        pixel_diff = torch.abs(first_frame - last_frame)
        pixel_diff = rgb_to_grayscale(pixel_diff).squeeze(1)

        # apply binary threshold to the diff
        foreground_map = (pixel_diff > binary_threshold / 255).int()

        # remove regions already detected by region extractor
        boxes_list = [im_regions["boxes"] for im_regions in regions]
        boxes_list = [
            clip_boxes_to_image(boxes + torch.Tensor([-2, -2, 2, 2]).to(boxes.device), foreground_map.shape[-2:])
            for boxes in boxes_list
        ]  # extend boxes by 2 in all directions to ensure full object is included
        boxes_mask = boxes_to_masks(boxes_list, foreground_map.shape[-2:]).int()
        foreground_map *= -boxes_mask + 1  # invert mask

        # find boxes from foreground map
        batch_boxes, _ = masks_to_boxes(foreground_map)

        # append foreground detections to region extractor detections
        for im_regions, boxes, pixel_mask in zip(regions, batch_boxes, foreground_map, strict=True):
            if boxes.shape[0] == 0:
                continue

            # append boxes, labels and scores
            im_regions["boxes"] = torch.cat([im_regions["boxes"], boxes])
            im_regions["labels"] = torch.cat(
                [im_regions["labels"], torch.zeros(boxes.shape[0], device=boxes.device)],
            )  # set label as background, in accordance with region extractor predictions
            im_regions["scores"] = torch.cat(
                [im_regions["scores"], torch.ones(boxes.shape[0], device=boxes.device) * 0.5],
            )  # set confidence to 0.5

            # append masks
            im_boxes_as_list = [box.unsqueeze(0) for box in boxes]  # list with one box per element
            boxes_mask = boxes_to_masks(im_boxes_as_list, pixel_mask.shape[-2:]).int()
            new_masks = pixel_mask.repeat((len(im_boxes_as_list), 1, 1)) * boxes_mask
            im_regions["masks"] = torch.cat([im_regions["masks"], new_masks.unsqueeze(1)])

        return regions
Add any foreground regions that were not detected by the region extractor.

        This method adds regions that likely belong to the foreground of the video
        scene, but were not detected by the region extractor module. The foreground
        pixels are determined by taking the pixel difference between two consecutive
        video frames and applying a binary threshold. The final detections consist of
        all connected components in the foreground that do not fall in one of the
        bounding boxes predicted by the region extractor.

        Args:
            regions (list[dict[str, torch.Tensor]]): Region detections for a batch of
                images, generated by the region extraction module.
            first_frame (torch.Tensor): Video frame at time t-1
            last_frame (torch.Tensor): Video frame at time t
            kernel_size (int): Kernel size for Gaussian smoothing applied to input
                frames
            binary_threshold (int): Binary threshold used in foreground detection,
                should be in range ``[0, 255]``

        Returns:
            list[dict[str, torch.Tensor]]: Region detections with foreground regions
                appended. Each dict contains:
                - boxes (torch.Tensor): Updated bounding boxes
                - labels (torch.Tensor): Updated class labels
                - scores (torch.Tensor): Updated confidence scores
                - masks (torch.Tensor): Updated instance masks
        
src/anomalib/models/video/ai_vad/regions.py