Autoscale input images to match model input, with command line arguments and message to indicate autoscaling if image input dimensions mismatch the model inputs. (#86)

This commit is contained in:
pmbrown1055 2018-11-15 13:53:56 -08:00 коммит произвёл Ryan Lai
Родитель b581106c1a
Коммит e910fd2fe6
8 изменённых файлов: 91 добавлений и 9 удалений

Двоичные данные
SharedContent/media/fish_112.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 38 KiB

Просмотреть файл

@ -470,9 +470,18 @@ namespace WinMLRunnerTest
auto const curPath = FileHelper::GetModulePath();
std::wstring command = curPath +
L"./WinMLRunner " + L"-model " + curPath + L"SqueezeNet.onnx "
+ L" -input " + curPath + L"horizontal-crop.png";
+ L" -input " + curPath + L"fish_112.png";
Assert::AreNotEqual(0, RunProc((wchar_t *)command.c_str()));
}
TEST_METHOD(AutoScaleImage)
{
auto const curPath = FileHelper::GetModulePath();
std::wstring command = curPath +
L"./WinMLRunner " + L"-model " + curPath + L"SqueezeNet.onnx "
+ L" -input " + curPath + L"fish_112.png -autoScale Cubic";
Assert::AreEqual(0, RunProc((wchar_t*)command.c_str()));
}
};
TEST_CLASS(CsvInputTest)

Просмотреть файл

@ -232,6 +232,17 @@
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\SharedContent\media\fish_112.png">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</DeploymentContent>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</DeploymentContent>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</DeploymentContent>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\SharedContent\media\horizontal-crop.png">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</DeploymentContent>

Просмотреть файл

@ -53,10 +53,16 @@ namespace BindingUtilities
return SoftwareBitmap::CreateCopyFromBuffer(buffer, TypeHelper::GetBitmapPixelFormat(inputDataType), static_cast<int32_t>(width), static_cast<int32_t>(height));
}
SoftwareBitmap LoadImageFile(const hstring& filePath, InputDataType inputDataType)
SoftwareBitmap LoadImageFile(const TensorFeatureDescriptor& imageDescriptor, InputDataType inputDataType, const hstring& filePath, const CommandLineArgs& args)
{
assert(inputDataType != InputDataType::Tensor);
// We assume NCHW and NCDHW
uint64_t width = imageDescriptor.Shape().GetAt(imageDescriptor.Shape().Size() - 1);
uint64_t height = imageDescriptor.Shape().GetAt(imageDescriptor.Shape().Size() - 2);
uint64_t channelCount = imageDescriptor.Shape().GetAt(1);
uint64_t batchCount = imageDescriptor.Shape().GetAt(0);
try
{
// open the file
@ -65,10 +71,33 @@ namespace BindingUtilities
auto stream = file.OpenAsync(FileAccessMode::Read).get();
// Create the decoder from the stream
BitmapDecoder decoder = BitmapDecoder::CreateAsync(stream).get();
// get the bitmap
SoftwareBitmap softwareBitmap = decoder.GetSoftwareBitmapAsync(TypeHelper::GetBitmapPixelFormat(inputDataType), BitmapAlphaMode::Ignore).get();
return softwareBitmap;
// If input dimensions are different from tensor input, then scale / crop while reading
if (args.AutoScale() &&
( decoder.PixelHeight() != height ||
decoder.PixelWidth() != width))
{
if (!args.Silent())
std::cout << std::endl << "Binding Utilities: AutoScaling input image to match model input dimensions...";
// Create a transform object with default parameters (no transform)
auto transform = BitmapTransform();
transform.ScaledHeight(height);
transform.ScaledWidth(width);
transform.InterpolationMode(args.AutoScaleInterpMode());
// get the bitmap
return decoder.GetSoftwareBitmapAsync(TypeHelper::GetBitmapPixelFormat(inputDataType),
BitmapAlphaMode::Ignore,
transform,
ExifOrientationMode::RespectExifOrientation,
ColorManagementMode::DoNotColorManage).get();
}
else
{
// get the bitmap
return decoder.GetSoftwareBitmapAsync(TypeHelper::GetBitmapPixelFormat(inputDataType), BitmapAlphaMode::Ignore).get();
}
}
catch (...)
{
@ -265,7 +294,8 @@ namespace BindingUtilities
const std::wstring& imagePath,
InputBindingType inputBindingType,
InputDataType inputDataType,
const IDirect3DDevice winrtDevice
const IDirect3DDevice winrtDevice,
const CommandLineArgs& args
)
{
auto imageDescriptor = featureDescriptor.try_as<TensorFeatureDescriptor>();
@ -278,7 +308,7 @@ namespace BindingUtilities
auto softwareBitmap = imagePath.empty()
? GenerateGarbageImage(imageDescriptor, inputDataType)
: LoadImageFile(imagePath.c_str(), inputDataType);
: LoadImageFile(imageDescriptor, inputDataType, imagePath.c_str(), args);
auto videoFrame = CreateVideoFrame(softwareBitmap, inputBindingType, inputDataType, winrtDevice);

Просмотреть файл

@ -29,6 +29,7 @@ void CommandLineArgs::PrintUsage() {
std::cout << " -IgnoreFirstRun : ignore the first run in the perf results when calculating the average" << std::endl;
std::cout << " -silent: only errors are printed to the console" << std::endl;
std::cout << " -debug: print trace logs" << std::endl;
std::cout << " -autoScale <interpolationMode>: Enable image autoscaling and set the interpolation mode [Nearest, Linear, Cubic, Fant]" << std::endl;
}
CommandLineArgs::CommandLineArgs()
@ -118,6 +119,32 @@ CommandLineArgs::CommandLineArgs()
{
m_silent = true;
}
else if ((_wcsicmp(args[i], L"-autoScale") == 0) && (i + 1 < numArgs))
{
m_autoScale = true;
if (_wcsicmp(args[++i], L"Nearest") == 0)
{
m_autoScaleInterpMode = BitmapInterpolationMode::NearestNeighbor;
}
else if (_wcsicmp(args[i], L"Linear") == 0)
{
m_autoScaleInterpMode = BitmapInterpolationMode::Linear;
}
else if (_wcsicmp(args[i], L"Cubic") == 0)
{
m_autoScaleInterpMode = BitmapInterpolationMode::Cubic;
}
else if (_wcsicmp(args[i], L"Fant") == 0)
{
m_autoScaleInterpMode = BitmapInterpolationMode::Fant;
}
else
{
std::cout << "Unknown AutoScale Interpolation Mode!" << std::endl;
PrintUsage();
return;
}
}
else if ((_wcsicmp(args[i], L"/?") == 0))
{
PrintUsage();

Просмотреть файл

@ -16,6 +16,8 @@ public:
bool EnableDebugOutput() const { return m_debug; }
bool Silent() const { return m_silent; }
bool CreateDeviceOnClient() const { return m_createDeviceOnClient; }
bool AutoScale() const { return m_autoScale; }
BitmapInterpolationMode AutoScaleInterpMode() const { return m_autoScaleInterpMode; }
const std::wstring& ImagePath() const { return m_imagePath; }
const std::wstring& CsvPath() const { return m_csvData; }
@ -78,6 +80,8 @@ private:
bool m_ignoreFirstRun = false;
bool m_debug = false;
bool m_silent = false;
bool m_autoScale = false;
BitmapInterpolationMode m_autoScaleInterpMode = BitmapInterpolationMode::Cubic;
std::wstring m_modelFolderPath;
std::wstring m_modelPath;

Просмотреть файл

@ -88,7 +88,7 @@ std::vector<ILearningModelFeatureValue> GenerateInputFeatures(
}
else
{
auto imageFeature = BindingUtilities::CreateBindableImage(description, args.ImagePath(), inputBindingType, inputDataType, winrtDevice);
auto imageFeature = BindingUtilities::CreateBindableImage(description, args.ImagePath(), inputBindingType, inputDataType, winrtDevice, args);
inputFeatures.push_back(imageFeature);
}
}

Просмотреть файл

@ -40,6 +40,7 @@ Required command-Line arguments:
-IgnoreFirstRun : Will ignore the first run in the perf results when calculating the average
-silent : Silent mode (only errors will be printed to the console)
-debug : Will start a trace logging session.
-autoScale <mode> : Will automatically scale an input image to match the required input dimensions of the model. Pass in the interpolation mode, one of ["Nearest", "Linear", "Cubic", "Fant"].
```