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