From f9f8d0329769c4efd6fff2ccf81212ca99bce17a Mon Sep 17 00:00:00 2001 From: wqz960 <362379625@qq.com> Date: Sat, 4 Jul 2020 05:08:48 +0000 Subject: [PATCH 1/4] add feature maps visualization --- tools/feature_maps_visualization/fm.jpg | Bin 0 -> 10752 bytes tools/feature_maps_visualization/fm_vis.py | 99 ++++++++++++++++++ .../feature_maps_visualization/get_started.md | 65 ++++++++++++ tools/feature_maps_visualization/test.jpg | Bin 0 -> 31228 bytes tools/feature_maps_visualization/utils.py | 84 +++++++++++++++ 5 files changed, 248 insertions(+) create mode 100644 tools/feature_maps_visualization/fm.jpg create mode 100644 tools/feature_maps_visualization/fm_vis.py create mode 100644 tools/feature_maps_visualization/get_started.md create mode 100644 tools/feature_maps_visualization/test.jpg create mode 100644 tools/feature_maps_visualization/utils.py diff --git a/tools/feature_maps_visualization/fm.jpg b/tools/feature_maps_visualization/fm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18b99f96ff1f3e099d38bcd99db4ab1d3a77d95a GIT binary patch literal 10752 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 0 and args.channel_num <= fm.shape[1], "the channel is out of the range" + fm = (np.squeeze(fm[0][args.channel_num].numpy())*255).astype(np.uint8) + print(fm) + if fm is not None: + if args.save: + print(args.save_path) + cv2.imwrite(args.save_path, fm) + if args.show: + cv2.show(fm) + cv2.waitKey(0) + +if __name__ == "__main__": + main() diff --git a/tools/feature_maps_visualization/get_started.md b/tools/feature_maps_visualization/get_started.md new file mode 100644 index 000000000..72d1949aa --- /dev/null +++ b/tools/feature_maps_visualization/get_started.md @@ -0,0 +1,65 @@ +# 特征图可视化指南 + +## 一、概述 + +特征图是输入图片在卷积网络中的特征表达,对特征图的研究可以有利于我们对于模型的理解与设计,所以基于动态图我们使用本工具来可视化特征图。 + +## 二、准备工作 + +首先我们需要选定研究的模型,本文设定ResNet50作为研究模型,将resnet.py从[模型库](../../ppcls/modeling/architecture/)拷贝到当前目录下,并下载预训练模型[预训练模型](../../docs/zh_CN/models/models_intro), 复制resnet50的模型链接,使用下列命令下载并解压预训练模型。 + +```bash +wget The Link for Pretrained Model +tar -xf Downloaded Pretrained Model +``` + +以resnet50为例: +```bash +wget https://paddle-imagenet-models-name.bj.bcebos.com/ResNet50_pretrained.tar +tar -xf ResNet50_pretrained.tar +``` + +## 三、修改模型 + +找到我们所需要的特征图位置,设置self.fm将其fetch出来,本文以resnet50中的stem层之后的特征图为例。 + +在ResNet50的__init__函数中定义self.fm +```python +self.fm = None +``` +在ResNet50的forward函数中指定特征图 +```python +def forward(self, inputs): + y = self.conv(inputs) + self.fm = y + y = self.pool2d_max(y) + for bottleneck_block in self.bottleneck_block_list: + y = bottleneck_block(y) + y = self.pool2d_avg(y) + y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_output]) + y = self.out(y) + return y, self.fm +``` +执行函数 +```bash +python tools/feature_maps_visualization/fm_vis.py -i the image you want to test \ + -c channel_num -p pretrained model \ + --show whether to show \ + --save whether to save \ + --save_path where to save \ + --use_gpu whether to use gpu +``` +参数说明: ++ `-i`:待预测的图片文件路径,如 `./test.jpeg` ++ `-c`:特征图维度,如 `./resnet50-vd/model` ++ `-p`:权重文件路径,如 `./ResNet50_pretrained/` ++ `--show`:是否展示图片,默认值 False ++ `--save`:是否保存图片,默认值:True ++ `--save_path`:保存路径,如:`./tools/` ++ `--use_gpu`:是否使用 GPU 预测,默认值:True + +## 四、结果 +输入图片: +![](../../tools/feature_maps_visualization/test.jpg) +输出特征图: +![](../../tools/feature_maps_visualization/fm.jpg) \ No newline at end of file diff --git a/tools/feature_maps_visualization/test.jpg b/tools/feature_maps_visualization/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da9d1a756b17ebe07ea2ad5cec0657ea23d0ea1d GIT binary patch literal 31228 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 literal 0 HcmV?d00001 diff --git a/tools/feature_maps_visualization/utils.py b/tools/feature_maps_visualization/utils.py new file mode 100644 index 000000000..6c4a75e1a --- /dev/null +++ b/tools/feature_maps_visualization/utils.py @@ -0,0 +1,84 @@ +# Copyright (c) 2020 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 cv2 +import numpy as np + + +class DecodeImage(object): + def __init__(self, to_rgb=True): + self.to_rgb = to_rgb + + def __call__(self, img): + data = np.frombuffer(img, dtype='uint8') + img = cv2.imdecode(data, 1) + if self.to_rgb: + assert img.shape[2] == 3, 'invalid shape of image[%s]' % ( + img.shape) + img = img[:, :, ::-1] + + return img + + +class ResizeImage(object): + def __init__(self, resize_short=None): + self.resize_short = resize_short + + def __call__(self, img): + img_h, img_w = img.shape[:2] + percent = float(self.resize_short) / min(img_w, img_h) + w = int(round(img_w * percent)) + h = int(round(img_h * percent)) + return cv2.resize(img, (w, h)) + + +class CropImage(object): + def __init__(self, size): + if type(size) is int: + self.size = (size, size) + else: + self.size = size + + def __call__(self, img): + w, h = self.size + img_h, img_w = img.shape[:2] + w_start = (img_w - w) // 2 + h_start = (img_h - h) // 2 + + w_end = w_start + w + h_end = h_start + h + return img[h_start:h_end, w_start:w_end, :] + + +class NormalizeImage(object): + def __init__(self, scale=None, mean=None, std=None): + self.scale = np.float32(scale if scale is not None else 1.0 / 255.0) + mean = mean if mean is not None else [0.485, 0.456, 0.406] + std = std if std is not None else [0.229, 0.224, 0.225] + + shape = (1, 1, 3) + self.mean = np.array(mean).reshape(shape).astype('float32') + self.std = np.array(std).reshape(shape).astype('float32') + + def __call__(self, img): + return (img.astype('float32') * self.scale - self.mean) / self.std + + +class ToTensor(object): + def __init__(self): + pass + + def __call__(self, img): + img = img.transpose((2, 0, 1)) + return img From 0644c970a6fd581bfc6818868467b6a5dac25af9 Mon Sep 17 00:00:00 2001 From: wqz960 <362379625@qq.com> Date: Sat, 4 Jul 2020 05:19:09 +0000 Subject: [PATCH 2/4] add feature maps visualization --- tools/feature_maps_visualization/fm_vis.py | 1 - tools/feature_maps_visualization/get_started.md | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/feature_maps_visualization/fm_vis.py b/tools/feature_maps_visualization/fm_vis.py index d3bea2be3..efb983cad 100644 --- a/tools/feature_maps_visualization/fm_vis.py +++ b/tools/feature_maps_visualization/fm_vis.py @@ -19,7 +19,6 @@ import numpy as np import cv2 import utils import argparse -import matplotlib.pyplot as plt def parse_args(): def str2bool(v): diff --git a/tools/feature_maps_visualization/get_started.md b/tools/feature_maps_visualization/get_started.md index 72d1949aa..e11fe968a 100644 --- a/tools/feature_maps_visualization/get_started.md +++ b/tools/feature_maps_visualization/get_started.md @@ -23,6 +23,8 @@ tar -xf ResNet50_pretrained.tar 找到我们所需要的特征图位置,设置self.fm将其fetch出来,本文以resnet50中的stem层之后的特征图为例。 +在fm_vis.py中修改模型的名字。 + 在ResNet50的__init__函数中定义self.fm ```python self.fm = None @@ -60,6 +62,9 @@ python tools/feature_maps_visualization/fm_vis.py -i the image you want to test ## 四、结果 输入图片: + ![](../../tools/feature_maps_visualization/test.jpg) + 输出特征图: -![](../../tools/feature_maps_visualization/fm.jpg) \ No newline at end of file + +![](../../tools/feature_maps_visualization/fm.jpg) From 5c20b55eadeebb9cde002a4117723cbf22b4f927 Mon Sep 17 00:00:00 2001 From: wqz960 <362379625@qq.com> Date: Mon, 20 Jul 2020 03:28:10 +0000 Subject: [PATCH 3/4] modify position --- .../feature_visualization_input.jpg | Bin .../feature_visualization_output.jpg | Bin .../feature_visiualization}/get_started.md | 9 +- .../download_resnet50_pretrained.sh | 2 + tools/feature_maps_visualization/fm_vis.py | 9 +- tools/feature_maps_visualization/resnet.py | 215 ++++++++++++++++++ 6 files changed, 223 insertions(+), 12 deletions(-) rename tools/feature_maps_visualization/test.jpg => docs/images/feature_maps/feature_visualization_input.jpg (100%) rename tools/feature_maps_visualization/fm.jpg => docs/images/feature_maps/feature_visualization_output.jpg (100%) rename {tools/feature_maps_visualization => docs/zh_CN/feature_visiualization}/get_started.md (78%) create mode 100644 tools/feature_maps_visualization/download_resnet50_pretrained.sh create mode 100644 tools/feature_maps_visualization/resnet.py diff --git a/tools/feature_maps_visualization/test.jpg b/docs/images/feature_maps/feature_visualization_input.jpg similarity index 100% rename from tools/feature_maps_visualization/test.jpg rename to docs/images/feature_maps/feature_visualization_input.jpg diff --git a/tools/feature_maps_visualization/fm.jpg b/docs/images/feature_maps/feature_visualization_output.jpg similarity index 100% rename from tools/feature_maps_visualization/fm.jpg rename to docs/images/feature_maps/feature_visualization_output.jpg diff --git a/tools/feature_maps_visualization/get_started.md b/docs/zh_CN/feature_visiualization/get_started.md similarity index 78% rename from tools/feature_maps_visualization/get_started.md rename to docs/zh_CN/feature_visiualization/get_started.md index e11fe968a..a287aad88 100644 --- a/tools/feature_maps_visualization/get_started.md +++ b/docs/zh_CN/feature_visiualization/get_started.md @@ -6,7 +6,7 @@ ## 二、准备工作 -首先我们需要选定研究的模型,本文设定ResNet50作为研究模型,将resnet.py从[模型库](../../ppcls/modeling/architecture/)拷贝到当前目录下,并下载预训练模型[预训练模型](../../docs/zh_CN/models/models_intro), 复制resnet50的模型链接,使用下列命令下载并解压预训练模型。 +首先需要选定研究的模型,本文设定ResNet50作为研究模型,将resnet.py从[模型库](../../../ppcls/modeling/architecture/)拷贝到当前目录下,并下载预训练模型[预训练模型](../../zh_CN/models/models_intro), 复制resnet50的模型链接,使用下列命令下载并解压预训练模型。 ```bash wget The Link for Pretrained Model @@ -53,18 +53,17 @@ python tools/feature_maps_visualization/fm_vis.py -i the image you want to test ``` 参数说明: + `-i`:待预测的图片文件路径,如 `./test.jpeg` -+ `-c`:特征图维度,如 `./resnet50-vd/model` ++ `-c`:特征图维度,如 `./resnet50_vd/model` + `-p`:权重文件路径,如 `./ResNet50_pretrained/` + `--show`:是否展示图片,默认值 False -+ `--save`:是否保存图片,默认值:True + `--save_path`:保存路径,如:`./tools/` + `--use_gpu`:是否使用 GPU 预测,默认值:True ## 四、结果 输入图片: -![](../../tools/feature_maps_visualization/test.jpg) +![](../../../tools/feature_maps_visualization/test.jpg) 输出特征图: -![](../../tools/feature_maps_visualization/fm.jpg) +![](../../../tools/feature_maps_visualization/fm.jpg) diff --git a/tools/feature_maps_visualization/download_resnet50_pretrained.sh b/tools/feature_maps_visualization/download_resnet50_pretrained.sh new file mode 100644 index 000000000..286c2400a --- /dev/null +++ b/tools/feature_maps_visualization/download_resnet50_pretrained.sh @@ -0,0 +1,2 @@ +wget https://paddle-imagenet-models-name.bj.bcebos.com/ResNet50_pretrained.tar +tar -xf ResNet50_pretrained.tar \ No newline at end of file diff --git a/tools/feature_maps_visualization/fm_vis.py b/tools/feature_maps_visualization/fm_vis.py index efb983cad..1731313ba 100644 --- a/tools/feature_maps_visualization/fm_vis.py +++ b/tools/feature_maps_visualization/fm_vis.py @@ -28,7 +28,6 @@ def parse_args(): parser.add_argument("-c", "--channel_num", type=int) parser.add_argument("-p", "--pretrained_model", type=str) parser.add_argument("--show", type=str2bool, default=False) - parser.add_argument("--save", type=str2bool, default=True) parser.add_argument("--save_path", type=str) parser.add_argument("--use_gpu", type=str2bool, default=True) @@ -66,9 +65,7 @@ def main(): place = fluid.CUDAPlace(gpu_id) else: place = fluid.CPUPlace() - fm = None - - print(args.pretrained_model) + pre_weights_dict = fluid.load_program_state(args.pretrained_model) with fluid.dygraph.guard(place): net = ResNet50() @@ -83,12 +80,10 @@ def main(): net.set_dict(pre_weights_dict_new) net.eval() _, fm = net(data) - assert args.channel_num >= 0 and args.channel_num <= fm.shape[1], "the channel is out of the range" + assert args.channel_num >= 0 and args.channel_num <= fm.shape[1], "the channel is out of the range, should be in {} but got {}".format([0, fm.shape[1]], args.channel_num) fm = (np.squeeze(fm[0][args.channel_num].numpy())*255).astype(np.uint8) - print(fm) if fm is not None: if args.save: - print(args.save_path) cv2.imwrite(args.save_path, fm) if args.show: cv2.show(fm) diff --git a/tools/feature_maps_visualization/resnet.py b/tools/feature_maps_visualization/resnet.py new file mode 100644 index 000000000..d3f230da6 --- /dev/null +++ b/tools/feature_maps_visualization/resnet.py @@ -0,0 +1,215 @@ +import numpy as np +import argparse +import ast +import paddle +import paddle.fluid as fluid +from paddle.fluid.param_attr import ParamAttr +from paddle.fluid.layer_helper import LayerHelper +from paddle.fluid.dygraph.nn import Conv2D, Pool2D, BatchNorm, Linear +from paddle.fluid.dygraph.base import to_variable + +from paddle.fluid import framework + +import math +import sys +import time + +class ConvBNLayer(fluid.dygraph.Layer): + def __init__(self, + num_channels, + num_filters, + filter_size, + stride=1, + groups=1, + act=None, + name=None): + super(ConvBNLayer, self).__init__() + + self._conv = Conv2D( + num_channels=num_channels, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) // 2, + groups=groups, + act=None, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=False) + if name == "conv1": + bn_name = "bn_" + name + else: + bn_name = "bn" + name[3:] + self._batch_norm = BatchNorm(num_filters, + act=act, + param_attr=ParamAttr(name=bn_name + '_scale'), + bias_attr=ParamAttr(bn_name + '_offset'), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance') + + def forward(self, inputs): + y = self._conv(inputs) + y = self._batch_norm(y) + return y + + +class BottleneckBlock(fluid.dygraph.Layer): + def __init__(self, + num_channels, + num_filters, + stride, + shortcut=True, + name=None): + super(BottleneckBlock, self).__init__() + + self.conv0 = ConvBNLayer( + num_channels=num_channels, + num_filters=num_filters, + filter_size=1, + act='relu', + name=name+"_branch2a") + self.conv1 = ConvBNLayer( + num_channels=num_filters, + num_filters=num_filters, + filter_size=3, + stride=stride, + act='relu', + name=name+"_branch2b") + self.conv2 = ConvBNLayer( + num_channels=num_filters, + num_filters=num_filters * 4, + filter_size=1, + act=None, + name=name+"_branch2c") + + if not shortcut: + self.short = ConvBNLayer( + num_channels=num_channels, + num_filters=num_filters * 4, + filter_size=1, + stride=stride, + name=name + "_branch1") + + self.shortcut = shortcut + + self._num_channels_out = num_filters * 4 + + def forward(self, inputs): + y = self.conv0(inputs) + conv1 = self.conv1(y) + conv2 = self.conv2(conv1) + + if self.shortcut: + short = inputs + else: + short = self.short(inputs) + + y = fluid.layers.elementwise_add(x=short, y=conv2) + + layer_helper = LayerHelper(self.full_name(), act='relu') + return layer_helper.append_activation(y) + + +class ResNet(fluid.dygraph.Layer): + def __init__(self, layers=50, class_dim=1000): + super(ResNet, self).__init__() + + self.layers = layers + supported_layers = [50, 101, 152] + assert layers in supported_layers, \ + "supported layers are {} but input layer is {}".format(supported_layers, layers) + self.fm = None + + if layers == 50: + depth = [3, 4, 6, 3] + elif layers == 101: + depth = [3, 4, 23, 3] + elif layers == 152: + depth = [3, 8, 36, 3] + num_channels = [64, 256, 512, 1024] + num_filters = [64, 128, 256, 512] + + self.conv = ConvBNLayer( + num_channels=3, + num_filters=64, + filter_size=7, + stride=2, + act='relu', + name="conv1") + self.pool2d_max = Pool2D( + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max') + + self.bottleneck_block_list = [] + for block in range(len(depth)): + shortcut = False + for i in range(depth[block]): + if layers in [101, 152] and block == 2: + if i == 0: + conv_name="res"+str(block+2)+"a" + else: + conv_name="res"+str(block+2)+"b"+str(i) + else: + conv_name="res"+str(block+2)+chr(97+i) + bottleneck_block = self.add_sublayer( + 'bb_%d_%d' % (block, i), + BottleneckBlock( + num_channels=num_channels[block] + if i == 0 else num_filters[block] * 4, + num_filters=num_filters[block], + stride=2 if i == 0 and block != 0 else 1, + shortcut=shortcut, + name=conv_name)) + self.bottleneck_block_list.append(bottleneck_block) + shortcut = True + + self.pool2d_avg = Pool2D( + pool_size=7, pool_type='avg', global_pooling=True) + + self.pool2d_avg_output = num_filters[len(num_filters) - 1] * 4 * 1 * 1 + + stdv = 1.0 / math.sqrt(2048 * 1.0) + + self.out = Linear(self.pool2d_avg_output, + class_dim, + param_attr=ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), name="fc_0.w_0"), + bias_attr=ParamAttr(name="fc_0.b_0")) + + def forward(self, inputs): + y = self.conv(inputs) + y = self.pool2d_max(y) + self.fm = y + for bottleneck_block in self.bottleneck_block_list: + y = bottleneck_block(y) + y = self.pool2d_avg(y) + y = fluid.layers.reshape(y, shape=[-1, self.pool2d_avg_output]) + y = self.out(y) + return y, self.fm + + +def ResNet50(**args): + model = ResNet(layers=50, **args) + return model + + +def ResNet101(**args): + model = ResNet(layers=101, **args) + return model + + +def ResNet152(**args): + model = ResNet(layers=152, **args) + return model + + +if __name__ == "__main__": + import numpy as np + place = fluid.CPUPlace() + with fluid.dygraph.guard(place): + model = ResNet50() + img = np.random.uniform(0, 255, [1, 3, 224, 224]).astype('float32') + img = fluid.dygraph.to_variable(img) + res = model(img) + print(res.shape) From a68d90c53bbad1614696bd8d5441fb26c2768095 Mon Sep 17 00:00:00 2001 From: wqz960 <362379625@qq.com> Date: Mon, 20 Jul 2020 04:16:02 +0000 Subject: [PATCH 4/4] fix interpolation --- docs/zh_CN/feature_visiualization/get_started.md | 3 ++- tools/feature_maps_visualization/fm_vis.py | 9 +++++---- tools/feature_maps_visualization/utils.py | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/zh_CN/feature_visiualization/get_started.md b/docs/zh_CN/feature_visiualization/get_started.md index a287aad88..f80a2f848 100644 --- a/docs/zh_CN/feature_visiualization/get_started.md +++ b/docs/zh_CN/feature_visiualization/get_started.md @@ -47,7 +47,7 @@ def forward(self, inputs): python tools/feature_maps_visualization/fm_vis.py -i the image you want to test \ -c channel_num -p pretrained model \ --show whether to show \ - --save whether to save \ + --interpolation interpolation method\ --save_path where to save \ --use_gpu whether to use gpu ``` @@ -56,6 +56,7 @@ python tools/feature_maps_visualization/fm_vis.py -i the image you want to test + `-c`:特征图维度,如 `./resnet50_vd/model` + `-p`:权重文件路径,如 `./ResNet50_pretrained/` + `--show`:是否展示图片,默认值 False ++ `--interpolation`: 图像插值方式, 默认值 1 + `--save_path`:保存路径,如:`./tools/` + `--use_gpu`:是否使用 GPU 预测,默认值:True diff --git a/tools/feature_maps_visualization/fm_vis.py b/tools/feature_maps_visualization/fm_vis.py index 1731313ba..b389d833c 100644 --- a/tools/feature_maps_visualization/fm_vis.py +++ b/tools/feature_maps_visualization/fm_vis.py @@ -28,19 +28,20 @@ def parse_args(): parser.add_argument("-c", "--channel_num", type=int) parser.add_argument("-p", "--pretrained_model", type=str) parser.add_argument("--show", type=str2bool, default=False) + parser.add_argument("--interpolation", type=int, default=1) parser.add_argument("--save_path", type=str) parser.add_argument("--use_gpu", type=str2bool, default=True) return parser.parse_args() -def create_operators(): +def create_operators(interpolation=1): size = 224 img_mean = [0.485, 0.456, 0.406] img_std = [0.229, 0.224, 0.225] img_scale = 1.0 / 255.0 decode_op = utils.DecodeImage() - resize_op = utils.ResizeImage(resize_short=256) + resize_op = utils.ResizeImage(resize_short=256, interpolation=interpolation) crop_op = utils.CropImage(size=(size, size)) normalize_op = utils.NormalizeImage( scale=img_scale, mean=img_mean, std=img_std) @@ -58,7 +59,7 @@ def preprocess(fname, ops): def main(): args = parse_args() - operators = create_operators() + operators = create_operators(args.interpolation) # assign the place if args.use_gpu: gpu_id = fluid.dygraph.parallel.Env().dev_id @@ -66,7 +67,7 @@ def main(): else: place = fluid.CPUPlace() - pre_weights_dict = fluid.load_program_state(args.pretrained_model) + #pre_weights_dict = fluid.load_program_state(args.pretrained_model) with fluid.dygraph.guard(place): net = ResNet50() data = preprocess(args.image_file, operators) diff --git a/tools/feature_maps_visualization/utils.py b/tools/feature_maps_visualization/utils.py index 6c4a75e1a..7c7014932 100644 --- a/tools/feature_maps_visualization/utils.py +++ b/tools/feature_maps_visualization/utils.py @@ -32,15 +32,16 @@ class DecodeImage(object): class ResizeImage(object): - def __init__(self, resize_short=None): + def __init__(self, resize_short=None, interpolation=1): self.resize_short = resize_short + self.interpolation = interpolation def __call__(self, img): img_h, img_w = img.shape[:2] percent = float(self.resize_short) / min(img_w, img_h) w = int(round(img_w * percent)) h = int(round(img_h * percent)) - return cv2.resize(img, (w, h)) + return cv2.resize(img, (w, h), interpolation=self.interpolation) class CropImage(object):