prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Semantic Segmentation Scenes w/ 0 Chips Fail
  Semantic segmentation scenes with zero chips cause raster-vision to halt.  This can be an issue when using finely-cropped scenes and filtering by nodata.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py`
  Content:
  ```
  1 import logging
  2 from typing import List, Sequence
  3 
  4 import numpy as np
  5 
  6 from rastervision.core.box import Box
  7 from rastervision.core.data import ClassConfig, Scene
  8 from rastervision.core.rv_pipeline.rv_pipeline import RVPipeline
  9 from rastervision.core.rv_pipeline.utils import (fill_no_data,
  10                                                  nodata_below_threshold)
  11 from rastervision.core.rv_pipeline.semantic_segmentation_config import (
  12     SemanticSegmentationWindowMethod, SemanticSegmentationChipOptions)
  13 
  14 log = logging.getLogger(__name__)
  15 
  16 
  17 def get_train_windows(scene: Scene,
  18                       class_config: ClassConfig,
  19                       chip_size: int,
  20                       chip_options: SemanticSegmentationChipOptions,
  21                       chip_nodata_threshold: float = 1.) -> List[Box]:
  22     """Get training windows covering a scene.
  23 
  24     Args:
  25         scene: The scene over-which windows are to be generated.
  26 
  27     Returns:
  28         A list of windows, list(Box)
  29     """
  30     co = chip_options
  31     raster_source = scene.raster_source
  32     extent = raster_source.get_extent()
  33     label_source = scene.ground_truth_label_source
  34 
  35     def filter_windows(windows: Sequence[Box]) -> List[Box]:
  36         """Filter out chips that
  37         (1) are outside the AOI
  38         (2) only consist of null labels
  39         (3) have NODATA proportion >= chip_nodata_threshold
  40         """
  41         total_windows = len(windows)
  42         if scene.aoi_polygons:
  43             windows = Box.filter_by_aoi(windows, scene.aoi_polygons)
  44             log.info(f'AOI filtering: {len(windows)}/{total_windows} '
  45                      'chips accepted')
  46 
  47         filt_windows = []
  48         for w in windows:
  49             chip = raster_source.get_chip(w)
  50             nodata_below_thresh = nodata_below_threshold(
  51                 chip, chip_nodata_threshold, nodata_val=0)
  52 
  53             label_arr = label_source.get_labels(w).get_label_arr(w)
  54             null_labels = label_arr == class_config.get_null_class_id()
  55 
  56             if not np.all(null_labels) and nodata_below_thresh:
  57                 filt_windows.append(w)
  58         log.info('Label and NODATA filtering: '
  59                  f'{len(filt_windows)}/{len(windows)} chips accepted')
  60 
  61         windows = filt_windows
  62         return windows
  63 
  64     def should_use_window(window: Box) -> bool:
  65         if co.negative_survival_prob >= 1.0:
  66             return True
  67         else:
  68             target_class_ids = co.target_class_ids or list(
  69                 range(len(class_config)))
  70             is_pos = label_source.enough_target_pixels(
  71                 window, co.target_count_threshold, target_class_ids)
  72             should_use = is_pos or (np.random.rand() <
  73                                     co.negative_survival_prob)
  74             return should_use
  75 
  76     if co.window_method == SemanticSegmentationWindowMethod.sliding:
  77         stride = co.stride or int(round(chip_size / 2))
  78         windows = list(filter_windows((extent.get_windows(chip_size, stride))))
  79         a_window = windows[0]
  80         windows = list(filter(should_use_window, windows))
  81         if len(windows) == 0:
  82             windows = [a_window]
  83     elif co.window_method == SemanticSegmentationWindowMethod.random_sample:
  84         windows = []
  85         attempts = 0
  86 
  87         while attempts < co.chips_per_scene:
  88             window = extent.make_random_square(chip_size)
  89             if not filter_windows([window]):
  90                 continue
  91 
  92             attempts += 1
  93             if co.negative_survival_prob >= 1.0:
  94                 windows.append(window)
  95             elif attempts == co.chips_per_scene and len(windows) == 0:
  96                 # Ensure there is at least one window per scene.
  97                 windows.append(window)
  98             elif should_use_window(window):
  99                 windows.append(window)
  100 
  101     return windows
  102 
  103 
  104 class SemanticSegmentation(RVPipeline):
  105     def __init__(self, config: 'RVPipelineConfig', tmp_dir: str):
  106         super().__init__(config, tmp_dir)
  107         if self.config.dataset.img_channels is None:
  108             self.config.dataset.img_channels = self.get_img_channels()
  109 
  110             self.config.dataset.update()
  111             self.config.dataset.validate_config()
  112 
  113             self.config.update()
  114             self.config.validate_config()
  115 
  116     def get_img_channels(self):
  117         ''' Determine img_channels from the first training scene. '''
  118         class_config = self.config.dataset.class_config
  119         scene_cfg = self.config.dataset.train_scenes[0]
  120         scene = scene_cfg.build(
  121             class_config, self.tmp_dir, use_transformers=False)
  122         with scene.activate():
  123             img_channels = scene.raster_source.num_channels
  124         return img_channels
  125 
  126     def chip(self, *args, **kwargs):
  127         log.info(f'Chip options: {self.config.chip_options}')
  128         return super().chip(*args, **kwargs)
  129 
  130     def get_train_windows(self, scene):
  131         return get_train_windows(
  132             scene,
  133             self.config.dataset.class_config,
  134             self.config.train_chip_sz,
  135             self.config.chip_options,
  136             chip_nodata_threshold=self.config.chip_nodata_threshold)
  137 
  138     def get_train_labels(self, window, scene):
  139         return scene.ground_truth_label_source.get_labels(window=window)
  140 
  141     def post_process_sample(self, sample):
  142         # Use null label for each pixel with NODATA.
  143         img = sample.chip
  144         label_arr = sample.labels.get_label_arr(sample.window)
  145         null_class_id = self.config.dataset.class_config.get_null_class_id()
  146         sample.chip = fill_no_data(img, label_arr, null_class_id)
  147         return sample
  148 
  149     def post_process_batch(self, windows, chips, labels):
  150         # Fill in null class for any NODATA pixels.
  151         null_class_id = self.config.dataset.class_config.get_null_class_id()
  152         for window, chip in zip(windows, chips):
  153             label_arr = labels.get_label_arr(window)
  154             label_arr[np.sum(chip, axis=2) == 0] = null_class_id
  155             labels.set_label_arr(window, label_arr)
  156 
  157         return labels
  158
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py
  --- a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py
  +++ b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py
  @@ -75,11 +75,15 @@
   
       if co.window_method == SemanticSegmentationWindowMethod.sliding:
           stride = co.stride or int(round(chip_size / 2))
  -        windows = list(filter_windows((extent.get_windows(chip_size, stride))))
  -        a_window = windows[0]
  -        windows = list(filter(should_use_window, windows))
  -        if len(windows) == 0:
  -            windows = [a_window]
  +        unfiltered_windows = extent.get_windows(chip_size, stride)
  +        windows = list(filter_windows(unfiltered_windows))
  +        if len(windows) > 0:
  +            a_window = windows[0]
  +            windows = list(filter(should_use_window, windows))
  +            if len(windows) == 0:
  +                windows = [a_window]
  +        elif len(windows) == 0:
  +            return [unfiltered_windows[0]]
       elif co.window_method == SemanticSegmentationWindowMethod.random_sample:
           windows = []
           attempts = 0
  
verification_info: {"golden_diff": "diff --git a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py\n--- a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py\n+++ b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py\n@@ -75,11 +75,15 @@\n \n     if co.window_method == SemanticSegmentationWindowMethod.sliding:\n         stride = co.stride or int(round(chip_size / 2))\n-        windows = list(filter_windows((extent.get_windows(chip_size, stride))))\n-        a_window = windows[0]\n-        windows = list(filter(should_use_window, windows))\n-        if len(windows) == 0:\n-            windows = [a_window]\n+        unfiltered_windows = extent.get_windows(chip_size, stride)\n+        windows = list(filter_windows(unfiltered_windows))\n+        if len(windows) > 0:\n+            a_window = windows[0]\n+            windows = list(filter(should_use_window, windows))\n+            if len(windows) == 0:\n+                windows = [a_window]\n+        elif len(windows) == 0:\n+            return [unfiltered_windows[0]]\n     elif co.window_method == SemanticSegmentationWindowMethod.random_sample:\n         windows = []\n         attempts = 0\n", "issue": "Semantic Segmentation Scenes w/ 0 Chips Fail\nSemantic segmentation scenes with zero chips cause raster-vision to halt.  This can be an issue when using finely-cropped scenes and filtering by nodata.\n", "before_files": [{"content": "import logging\nfrom typing import List, Sequence\n\nimport numpy as np\n\nfrom rastervision.core.box import Box\nfrom rastervision.core.data import ClassConfig, Scene\nfrom rastervision.core.rv_pipeline.rv_pipeline import RVPipeline\nfrom rastervision.core.rv_pipeline.utils import (fill_no_data,\n                                                 nodata_below_threshold)\nfrom rastervision.core.rv_pipeline.semantic_segmentation_config import (\n    SemanticSegmentationWindowMethod, SemanticSegmentationChipOptions)\n\nlog = logging.getLogger(__name__)\n\n\ndef get_train_windows(scene: Scene,\n                      class_config: ClassConfig,\n                      chip_size: int,\n                      chip_options: SemanticSegmentationChipOptions,\n                      chip_nodata_threshold: float = 1.) -> List[Box]:\n    \"\"\"Get training windows covering a scene.\n\n    Args:\n        scene: The scene over-which windows are to be generated.\n\n    Returns:\n        A list of windows, list(Box)\n    \"\"\"\n    co = chip_options\n    raster_source = scene.raster_source\n    extent = raster_source.get_extent()\n    label_source = scene.ground_truth_label_source\n\n    def filter_windows(windows: Sequence[Box]) -> List[Box]:\n        \"\"\"Filter out chips that\n        (1) are outside the AOI\n        (2) only consist of null labels\n        (3) have NODATA proportion >= chip_nodata_threshold\n        \"\"\"\n        total_windows = len(windows)\n        if scene.aoi_polygons:\n            windows = Box.filter_by_aoi(windows, scene.aoi_polygons)\n            log.info(f'AOI filtering: {len(windows)}/{total_windows} '\n                     'chips accepted')\n\n        filt_windows = []\n        for w in windows:\n            chip = raster_source.get_chip(w)\n            nodata_below_thresh = nodata_below_threshold(\n                chip, chip_nodata_threshold, nodata_val=0)\n\n            label_arr = label_source.get_labels(w).get_label_arr(w)\n            null_labels = label_arr == class_config.get_null_class_id()\n\n            if not np.all(null_labels) and nodata_below_thresh:\n                filt_windows.append(w)\n        log.info('Label and NODATA filtering: '\n                 f'{len(filt_windows)}/{len(windows)} chips accepted')\n\n        windows = filt_windows\n        return windows\n\n    def should_use_window(window: Box) -> bool:\n        if co.negative_survival_prob >= 1.0:\n            return True\n        else:\n            target_class_ids = co.target_class_ids or list(\n                range(len(class_config)))\n            is_pos = label_source.enough_target_pixels(\n                window, co.target_count_threshold, target_class_ids)\n            should_use = is_pos or (np.random.rand() <\n                                    co.negative_survival_prob)\n            return should_use\n\n    if co.window_method == SemanticSegmentationWindowMethod.sliding:\n        stride = co.stride or int(round(chip_size / 2))\n        windows = list(filter_windows((extent.get_windows(chip_size, stride))))\n        a_window = windows[0]\n        windows = list(filter(should_use_window, windows))\n        if len(windows) == 0:\n            windows = [a_window]\n    elif co.window_method == SemanticSegmentationWindowMethod.random_sample:\n        windows = []\n        attempts = 0\n\n        while attempts < co.chips_per_scene:\n            window = extent.make_random_square(chip_size)\n            if not filter_windows([window]):\n                continue\n\n            attempts += 1\n            if co.negative_survival_prob >= 1.0:\n                windows.append(window)\n            elif attempts == co.chips_per_scene and len(windows) == 0:\n                # Ensure there is at least one window per scene.\n                windows.append(window)\n            elif should_use_window(window):\n                windows.append(window)\n\n    return windows\n\n\nclass SemanticSegmentation(RVPipeline):\n    def __init__(self, config: 'RVPipelineConfig', tmp_dir: str):\n        super().__init__(config, tmp_dir)\n        if self.config.dataset.img_channels is None:\n            self.config.dataset.img_channels = self.get_img_channels()\n\n            self.config.dataset.update()\n            self.config.dataset.validate_config()\n\n            self.config.update()\n            self.config.validate_config()\n\n    def get_img_channels(self):\n        ''' Determine img_channels from the first training scene. '''\n        class_config = self.config.dataset.class_config\n        scene_cfg = self.config.dataset.train_scenes[0]\n        scene = scene_cfg.build(\n            class_config, self.tmp_dir, use_transformers=False)\n        with scene.activate():\n            img_channels = scene.raster_source.num_channels\n        return img_channels\n\n    def chip(self, *args, **kwargs):\n        log.info(f'Chip options: {self.config.chip_options}')\n        return super().chip(*args, **kwargs)\n\n    def get_train_windows(self, scene):\n        return get_train_windows(\n            scene,\n            self.config.dataset.class_config,\n            self.config.train_chip_sz,\n            self.config.chip_options,\n            chip_nodata_threshold=self.config.chip_nodata_threshold)\n\n    def get_train_labels(self, window, scene):\n        return scene.ground_truth_label_source.get_labels(window=window)\n\n    def post_process_sample(self, sample):\n        # Use null label for each pixel with NODATA.\n        img = sample.chip\n        label_arr = sample.labels.get_label_arr(sample.window)\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        sample.chip = fill_no_data(img, label_arr, null_class_id)\n        return sample\n\n    def post_process_batch(self, windows, chips, labels):\n        # Fill in null class for any NODATA pixels.\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        for window, chip in zip(windows, chips):\n            label_arr = labels.get_label_arr(window)\n            label_arr[np.sum(chip, axis=2) == 0] = null_class_id\n            labels.set_label_arr(window, label_arr)\n\n        return labels\n", "path": "rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py"}], "after_files": [{"content": "import logging\nfrom typing import List, Sequence\n\nimport numpy as np\n\nfrom rastervision.core.box import Box\nfrom rastervision.core.data import ClassConfig, Scene\nfrom rastervision.core.rv_pipeline.rv_pipeline import RVPipeline\nfrom rastervision.core.rv_pipeline.utils import (fill_no_data,\n                                                 nodata_below_threshold)\nfrom rastervision.core.rv_pipeline.semantic_segmentation_config import (\n    SemanticSegmentationWindowMethod, SemanticSegmentationChipOptions)\n\nlog = logging.getLogger(__name__)\n\n\ndef get_train_windows(scene: Scene,\n                      class_config: ClassConfig,\n                      chip_size: int,\n                      chip_options: SemanticSegmentationChipOptions,\n                      chip_nodata_threshold: float = 1.) -> List[Box]:\n    \"\"\"Get training windows covering a scene.\n\n    Args:\n        scene: The scene over-which windows are to be generated.\n\n    Returns:\n        A list of windows, list(Box)\n    \"\"\"\n    co = chip_options\n    raster_source = scene.raster_source\n    extent = raster_source.get_extent()\n    label_source = scene.ground_truth_label_source\n\n    def filter_windows(windows: Sequence[Box]) -> List[Box]:\n        \"\"\"Filter out chips that\n        (1) are outside the AOI\n        (2) only consist of null labels\n        (3) have NODATA proportion >= chip_nodata_threshold\n        \"\"\"\n        total_windows = len(windows)\n        if scene.aoi_polygons:\n            windows = Box.filter_by_aoi(windows, scene.aoi_polygons)\n            log.info(f'AOI filtering: {len(windows)}/{total_windows} '\n                     'chips accepted')\n\n        filt_windows = []\n        for w in windows:\n            chip = raster_source.get_chip(w)\n            nodata_below_thresh = nodata_below_threshold(\n                chip, chip_nodata_threshold, nodata_val=0)\n\n            label_arr = label_source.get_labels(w).get_label_arr(w)\n            null_labels = label_arr == class_config.get_null_class_id()\n\n            if not np.all(null_labels) and nodata_below_thresh:\n                filt_windows.append(w)\n        log.info('Label and NODATA filtering: '\n                 f'{len(filt_windows)}/{len(windows)} chips accepted')\n\n        windows = filt_windows\n        return windows\n\n    def should_use_window(window: Box) -> bool:\n        if co.negative_survival_prob >= 1.0:\n            return True\n        else:\n            target_class_ids = co.target_class_ids or list(\n                range(len(class_config)))\n            is_pos = label_source.enough_target_pixels(\n                window, co.target_count_threshold, target_class_ids)\n            should_use = is_pos or (np.random.rand() <\n                                    co.negative_survival_prob)\n            return should_use\n\n    if co.window_method == SemanticSegmentationWindowMethod.sliding:\n        stride = co.stride or int(round(chip_size / 2))\n        unfiltered_windows = extent.get_windows(chip_size, stride)\n        windows = list(filter_windows(unfiltered_windows))\n        if len(windows) > 0:\n            a_window = windows[0]\n            windows = list(filter(should_use_window, windows))\n            if len(windows) == 0:\n                windows = [a_window]\n        elif len(windows) == 0:\n            return [unfiltered_windows[0]]\n    elif co.window_method == SemanticSegmentationWindowMethod.random_sample:\n        windows = []\n        attempts = 0\n\n        while attempts < co.chips_per_scene:\n            window = extent.make_random_square(chip_size)\n            if not filter_windows([window]):\n                continue\n\n            attempts += 1\n            if co.negative_survival_prob >= 1.0:\n                windows.append(window)\n            elif attempts == co.chips_per_scene and len(windows) == 0:\n                # Ensure there is at least one window per scene.\n                windows.append(window)\n            elif should_use_window(window):\n                windows.append(window)\n\n    return windows\n\n\nclass SemanticSegmentation(RVPipeline):\n    def __init__(self, config: 'RVPipelineConfig', tmp_dir: str):\n        super().__init__(config, tmp_dir)\n        if self.config.dataset.img_channels is None:\n            self.config.dataset.img_channels = self.get_img_channels()\n\n            self.config.dataset.update()\n            self.config.dataset.validate_config()\n\n            self.config.update()\n            self.config.validate_config()\n\n    def get_img_channels(self):\n        ''' Determine img_channels from the first training scene. '''\n        class_config = self.config.dataset.class_config\n        scene_cfg = self.config.dataset.train_scenes[0]\n        scene = scene_cfg.build(\n            class_config, self.tmp_dir, use_transformers=False)\n        with scene.activate():\n            img_channels = scene.raster_source.num_channels\n        return img_channels\n\n    def chip(self, *args, **kwargs):\n        log.info(f'Chip options: {self.config.chip_options}')\n        return super().chip(*args, **kwargs)\n\n    def get_train_windows(self, scene):\n        return get_train_windows(\n            scene,\n            self.config.dataset.class_config,\n            self.config.train_chip_sz,\n            self.config.chip_options,\n            chip_nodata_threshold=self.config.chip_nodata_threshold)\n\n    def get_train_labels(self, window, scene):\n        return scene.ground_truth_label_source.get_labels(window=window)\n\n    def post_process_sample(self, sample):\n        # Use null label for each pixel with NODATA.\n        img = sample.chip\n        label_arr = sample.labels.get_label_arr(sample.window)\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        sample.chip = fill_no_data(img, label_arr, null_class_id)\n        return sample\n\n    def post_process_batch(self, windows, chips, labels):\n        # Fill in null class for any NODATA pixels.\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        for window, chip in zip(windows, chips):\n            label_arr = labels.get_label_arr(window)\n            label_arr[np.sum(chip, axis=2) == 0] = null_class_id\n            labels.set_label_arr(window, label_arr)\n\n        return labels\n", "path": "rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py"}]}