2017-10-14 72 views
1

我要添加的图像变换(我称之为ResizeTransformer),其如何添加图像大小调整变换CNTK

  • 调整大小的图像的较小的尺寸给定的尺寸,同时保持原始的宽高比

要在不实施单独ResizeTransformer做到这一点我想修改this file 但是该类ScaleTransformer : public ImageTransformerBase类,这个类实现StreamInformation ScaleTransformer::Transform(const StreamInformation& inputStream)与变换流的目的,让所有的SAM大小相同。 我的查询如下:

  1. 为什么要实现这个功能是必需的?这是否会增加任何性能优势,或者这对于更基本的目的而言很重要?

  2. 我是否必须将ResizeTransformer()作为单独的类来实施?

  3. 在这种情况下,我必须执行StreamInformation ResizeTransformer::Transform(const StreamInformation& inputStream吗?

需要为这个改造 这个转换需要,因为一个人的数据集中的所有图像可以是不同大小的,有人可能想从每个图像中提取的多个补丁。在这种情况下,最佳解决方案是将图像的较小尺寸调整为大于剪裁尺寸的特定尺寸,然后从中提取尺寸为C的多个补丁。这种数据增强在我所了解的某些论文中得到了实践。

PS: 我做如下补充,努力增加ResizeTransformer

我感到困惑的是如何对其进行测试。 C++编译成功,意味着C++代码是正确的。但我想在python中使用它。

添置header file在我的系统: `

class ResizeTransformer : public ImageTransformerBase 
{ 
public: 
    explicit ResizeTransformer(const Microsoft::MSR::CNTK::ConfigParameters& config); 

private: 
    enum class ResizeMode 
    { 
    ResizeMin = 0, 
    ResizeMax = 0 
    }; 

    ResizeMode resize_mode; 
    size_t resized_length; 
    void Apply(uint8_t copyId, cv::Mat &mat) override; 
}; 

而到了source file

ResizeTransformer::ResizeTransformer(const ConfigParameters& config) : ImageTransformerBase(config) 
{ 
    resized_length = config(L"resized_length"); 
    if (resized_length <= 0) 
    RuntimeError("Cannot resize any dimension of an image to zero or negative number."); 

    string resize_type = config(L"resize_type", "ResizeMin"); 
    if (resize_type == "ResizeMin") 
    resize_mode = ResizeMode::ResizeMin; 
    else if (resize_type == "ResizeMax") 
    resize_mode = ResizeMode::ResizeMax; 
    else RuntimeError("Invalid resize_type. Must be one of ResizeMin and ResizeMax"); 
} 

void ResizeTransformer::Apply(uint8_t, cv::Mat &mat) 
{ 
    float height = mat.rows; 
    float width = mat.cols; 
    float aspectratio = height/width; 
    float newheight{}; 
    float newwidth{}; 
    if (resize_mode == ResizeMode::ResizeMin) 
    { 
     if(height <=width) 
    { 
     newheight = resized_length; 
     newwidth = newheight/aspectratio; 
    } 
     else 
    { 
     newheight = aspectratio * resized_length; 
     newwidth = resized_length; 
    } 
    } 
    else 
    { 
     if(height <=width) 
    { 
     newheight = aspectratio * resized_length; 
     newwidth = resized_length; 
    } 
     else 
    { 
     newheight = resized_length; 
     newwidth = newheight/aspectratio; 
    } 
    } 
    resize(mat, mat, cv::Size2f(newwidth, newheight)); 
} 

我添加以下行this file

transformations.push_back(Transformation{ std::make_shared<ResizeTransformer>(featureStream), featureName }); 

然后我说的跟在012之后

CNTK_API ImageTransform ReaderResize(int resized_length, 
             const wchar_t* resize_type = L"ResizeMin"); 

最后添加以下功能this file

def resize(resized_length, resize_type='ResizeMin'): 
    ''' 
    Resize transform that can be used to pass to `map_features` 
    Given an input image, it will resize a given dimension to 
    a fixed size (resized_length), while preserving the aspect ratio. 


    Args: 
     resized_length (int): A positive integer. It is the resized value of the 
      dimension which has to be resized. The other dimension is resized while 
      maintaining the aspect ratio. 
     resize_type (str, default 'ResizeMin'): 'ResizeMin' or 'ResizeMax'. 
      When 'ResizeMin', the smaller dimension of the image is resized to a fixed size 
      given by resized_length, with the larger dimension resized in a way to preserve 
      the priginal aspect ratio. When 'ResizeMax', the same operation is performed 
      but now the larger dimension of the image is resized to a fixed size. 
    Returns: 
     A dictionary like object describing the ResizeTransform. 
    ''' 
    return cntk_py.reader_resize(resized_length, resize_type) 

回答

1

1)这允许上层到如果可能提前定义的时间缓冲。所以如果你知道你将调整到(x,y) - 那么你可以在那里定义输出流的形状(类似于ScaleTransform)。 否则 - 您可以在Transform(SequenceDataPtr)/(如果使用ImageBaseTranform类时应用)方法设置图像布局。 2)你可以,或者你可以改变ScaleTransformer来做你所需要的(只需要在配置中使用另一个参数)。

3)如果你实现自己的ResizeTranformer - 你可以简单地把NDShape ::未知的变换,是这样的:

StreamInformation ResizeTranformer::Transform(
    const StreamInformation& inputStream) 
{ 
    TransformBase::Transform(inputStream); 
    m_outputStream.m_sampleLayout = NDShape::Unknown(); 
    return m_outputStream; 
} 

PS。代码看起来不错,不过你可能仍然需要在inputStream上添加一个Transform,如上所述。 另请注意,当图像到达核心网时,它们都应具有相同的尺寸。解串器不支持不同形状的图像。

如果你想揭露ResizeTransformer你需要做到以下几点:

1)实施ResizerTranformer(正如我们上面所讨论的,你做了

2)的ImageReader/Exports.cpp按名称添加分辨率为CreateTransformer功能,即

else if (type == L"Resize") 
     *transformer = new ResizeTransformer(config); 

(这个人是缺少在你身边似乎)

3)工厂方法添加到在CNTKLibrary.h/MinibatchSource.cpp的C++ API,作为一个例子见尺度变换(ReaderScale):(你没有) ImageTransform ReaderResize(...){... }

4)落实使用参数的检查等在绑定/蟒蛇/ cntk/IO/transforms.py一个Python包装(你是) DEF调整(...):

然后如果您重新编译并将PATH设置为您的本地版本(/ x64/Release)的CNTK和PYTHON_PATH为/ binding/python,则应该可以使用新的转换。 您可以将测试添加到io/tests,然后转到/ binding/python/cntk,然后运行“pytest”。

我可能已经忘记了一些事情,所以如果遇到任何问题,请咨询CNTK团队,他们应该能够提供帮助。

谢谢!

+0

我终于决定修改ScaleTransform并进行了更改。你的回答对未来的变化非常有用:)非常感谢。 – Ujjwal