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:
Родитель
b581106c1a
Коммит
e910fd2fe6
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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"].
|
||||
|
||||
```
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче