Merge pull request #8 from LutaoChu/seg-pipeline
Support multi-channel transform and model trainingown
commit
c6d911e71d
13 changed files with 154 additions and 255 deletions
@ -1 +1,5 @@ |
||||
PaddleSeg commit fec42fd869b6f796c74cd510671595e3512bc8e9 |
||||
PaddleSeg commit fec42fd869b6f796c74cd510671595e3512bc8e9 |
||||
|
||||
# 开发规范 |
||||
请注意,paddlers/models/ppxxx系列除了修改import路径和支持多通道模型外,不要增删改任何代码。 |
||||
新增的模型需放在paddlers/models/下的seg、det、cls、cd目录下。 |
@ -0,0 +1,40 @@ |
||||
# 遥感数据集 |
||||
|
||||
遥感影像的格式多种多样,不同传感器产生的数据格式也可能不同。PaddleRS至少兼容以下6种格式图片读取: |
||||
|
||||
- `tif` |
||||
- `png`, `jpeg`, `bmp` |
||||
- `img` |
||||
- `npy` |
||||
|
||||
标注图要求必须为单通道的png格式图像,像素值即为对应的类别,像素标注类别需要从0开始递增。例如0,1,2,3表示有4种类别,255用于指定不参与训练和评估的像素,标注类别最多为256类。 |
||||
|
||||
## L8 SPARCS数据集 |
||||
[L8 SPARCS公开数据集](https://www.usgs.gov/land-resources/nli/landsat/spatial-procedures-automated-removal-cloud-and-shadow-sparcs-validation)进行云雪分割,该数据集包含80张卫星影像,涵盖10个波段。原始标注图片包含7个类别,分别是`cloud`, `cloud shadow`, `shadow over water`, `snow/ice`, `water`, `land`和`flooded`。由于`flooded`和`shadow over water`2个类别占比仅为`1.8%`和`0.24%`,我们将其进行合并,`flooded`归为`land`,`shadow over water`归为`shadow`,合并后标注包含5个类别。 |
||||
|
||||
数值、类别、颜色对应表: |
||||
|
||||
|Pixel value|Class|Color| |
||||
|---|---|---| |
||||
|0|cloud|white| |
||||
|1|shadow|black| |
||||
|2|snow/ice|cyan| |
||||
|3|water|blue| |
||||
|4|land|grey| |
||||
|
||||
<p align="center"> |
||||
<img src="./images/dataset.png" align="middle" |
||||
</p> |
||||
|
||||
<p align='center'> |
||||
L8 SPARCS数据集示例 |
||||
</p> |
||||
|
||||
执行以下命令下载并解压经过类别合并后的数据集: |
||||
```shell script |
||||
mkdir dataset && cd dataset |
||||
wget https://paddleseg.bj.bcebos.com/dataset/remote_sensing_seg.zip |
||||
unzip remote_sensing_seg.zip |
||||
cd .. |
||||
``` |
||||
其中`data`目录存放遥感影像,`data_vis`目录存放彩色合成预览图,`mask`目录存放标注图。 |
@ -1,157 +0,0 @@ |
||||
# copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
import numpy as np |
||||
import os.path as osp |
||||
import cv2 |
||||
import copy |
||||
import random |
||||
import imghdr |
||||
from PIL import Image |
||||
|
||||
try: |
||||
from collections.abc import Sequence |
||||
except Exception: |
||||
from collections import Sequence |
||||
|
||||
# from paddlers.transforms.operators import Transform |
||||
|
||||
|
||||
class Transform(object): |
||||
""" |
||||
Parent class of all data augmentation operations |
||||
""" |
||||
|
||||
def __init__(self): |
||||
pass |
||||
|
||||
def apply_im(self, image): |
||||
pass |
||||
|
||||
def apply_mask(self, mask): |
||||
pass |
||||
|
||||
def apply_bbox(self, bbox): |
||||
pass |
||||
|
||||
def apply_segm(self, segms): |
||||
pass |
||||
|
||||
def apply(self, sample): |
||||
sample['image'] = self.apply_im(sample['image']) |
||||
if 'mask' in sample: |
||||
sample['mask'] = self.apply_mask(sample['mask']) |
||||
if 'gt_bbox' in sample: |
||||
sample['gt_bbox'] = self.apply_bbox(sample['gt_bbox']) |
||||
|
||||
return sample |
||||
|
||||
def __call__(self, sample): |
||||
if isinstance(sample, Sequence): |
||||
sample = [self.apply(s) for s in sample] |
||||
else: |
||||
sample = self.apply(sample) |
||||
|
||||
return sample |
||||
|
||||
|
||||
class ImgDecode(Transform): |
||||
""" |
||||
Decode image(s) in input. |
||||
Args: |
||||
to_rgb (bool, optional): If True, convert input images from BGR format to RGB format. Defaults to True. |
||||
""" |
||||
|
||||
def __init__(self, to_rgb=True): |
||||
super(ImgDecode, self).__init__() |
||||
self.to_rgb = to_rgb |
||||
|
||||
def read_img(self, img_path, input_channel=3): |
||||
img_format = imghdr.what(img_path) |
||||
name, ext = osp.splitext(img_path) |
||||
if img_format == 'tiff' or ext == '.img': |
||||
try: |
||||
import gdal |
||||
except: |
||||
try: |
||||
from osgeo import gdal |
||||
except: |
||||
raise Exception( |
||||
"Failed to import gdal! You can try use conda to install gdal" |
||||
) |
||||
six.reraise(*sys.exc_info()) |
||||
|
||||
dataset = gdal.Open(img_path) |
||||
if dataset == None: |
||||
raise Exception('Can not open', img_path) |
||||
im_data = dataset.ReadAsArray() |
||||
return im_data.transpose((1, 2, 0)) |
||||
elif img_format in ['jpeg', 'bmp', 'png', 'jpg']: |
||||
if input_channel == 3: |
||||
return cv2.imread(img_path, cv2.IMREAD_ANYDEPTH | |
||||
cv2.IMREAD_ANYCOLOR | cv2.IMREAD_COLOR) |
||||
else: |
||||
return cv2.imread(img_path, cv2.IMREAD_ANYDEPTH | |
||||
cv2.IMREAD_ANYCOLOR) |
||||
elif ext == '.npy': |
||||
return np.load(img_path) |
||||
else: |
||||
raise Exception('Image format {} is not supported!'.format(ext)) |
||||
|
||||
def apply_im(self, im_path): |
||||
if isinstance(im_path, str): |
||||
try: |
||||
image = self.read_img(im_path) |
||||
except: |
||||
raise ValueError('Cannot read the image file {}!'.format( |
||||
im_path)) |
||||
else: |
||||
image = im_path |
||||
|
||||
if self.to_rgb: |
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) |
||||
|
||||
return image |
||||
|
||||
def apply_mask(self, mask): |
||||
try: |
||||
mask = np.asarray(Image.open(mask)) |
||||
except: |
||||
raise ValueError("Cannot read the mask file {}!".format(mask)) |
||||
if len(mask.shape) != 2: |
||||
raise Exception( |
||||
"Mask should be a 1-channel image, but recevied is a {}-channel image.". |
||||
format(mask.shape[2])) |
||||
return mask |
||||
|
||||
def apply(self, sample): |
||||
""" |
||||
Args: |
||||
sample (dict): Input sample, containing 'image' at least. |
||||
Returns: |
||||
dict: Decoded sample. |
||||
""" |
||||
sample['image'] = self.apply_im(sample['image']) |
||||
if 'mask' in sample: |
||||
sample['mask'] = self.apply_mask(sample['mask']) |
||||
im_height, im_width, _ = sample['image'].shape |
||||
se_height, se_width = sample['mask'].shape |
||||
if im_height != se_height or im_width != se_width: |
||||
raise Exception( |
||||
"The height or width of the im is not same as the mask") |
||||
|
||||
sample['im_shape'] = np.array( |
||||
sample['image'].shape[:2], dtype=np.float32) |
||||
sample['scale_factor'] = np.array([1., 1.], dtype=np.float32) |
||||
return sample |
Loading…
Reference in new issue