diff --git a/winml/lib/Api/ImageFeatureValue.cpp b/winml/lib/Api/ImageFeatureValue.cpp index 2ecfa297f3..1b8be103c0 100644 --- a/winml/lib/Api/ImageFeatureValue.cpp +++ b/winml/lib/Api/ImageFeatureValue.cpp @@ -123,6 +123,25 @@ static std::optional GetBoundsFromMetadata(const wfc::IProper return {}; } +static std::optional GetBitmapPixelRangeFromMetadata(const wfc::IPropertySet& properties) { + if (properties != nullptr && properties.HasKey(L"PixelRange")) { + if (auto pixelRangeInspectable = properties.Lookup(L"PixelRange")) { + auto pixelRangeValue = pixelRangeInspectable.as(); + auto pixelRange = static_cast(pixelRangeValue.GetInt32()); + WINML_THROW_HR_IF_FALSE_MSG( + WINML_ERR_INVALID_BINDING, + pixelRange == winml::LearningModelPixelRange::ZeroTo255 || + pixelRange == winml::LearningModelPixelRange::ZeroToOne || + pixelRange == winml::LearningModelPixelRange::MinusOneToOne, + "LearningModelPixelRange must be either ZeroTo255, ZeroToOne, or MinusOneToOne"); + + return pixelRange; + } + } + + return {}; +} + wgi::BitmapBounds ImageFeatureValue::CenterAndCropBounds( uint32_t idx, uint32_t desiredWidth, @@ -366,7 +385,6 @@ std::optional ImageFeatureValue::GetIn // TODO: Validate Bounds // Set up BitmapPixelFormat - auto pixelFormat = std::optional{}; pixelFormat = GetBitmapPixelFormatFromMetadata(context.properties); if (!pixelFormat.has_value() && spImageDescriptor) { @@ -387,13 +405,21 @@ std::optional ImageFeatureValue::GetIn } // Set up LearningModelPixelRange - winml::LearningModelPixelRange pixelRange = winml::LearningModelPixelRange::ZeroTo255; //default; - if (spImageDescriptor) { + auto pixelRange = std::optional{}; + pixelRange = GetBitmapPixelRangeFromMetadata(context.properties); + if (pixelRange.has_value()) { + // The pixel range was set by the bind properties, skip all checks and honor + // the user provided normalization property. Do nothing. + } else if (!pixelRange.has_value() && spImageDescriptor) { pixelRange = spImageDescriptor->PixelRange(); + } else if (!pixelRange.has_value() && spTensorDescriptor) { + pixelRange = winml::LearningModelPixelRange::ZeroTo255; //default; + } else { + THROW_HR(WINML_ERR_INVALID_BINDING); } //NCHW layout - auto imageTensorDescriptor = CreateImageTensorDescriptor(tensorKind, pixelFormat.value(), pixelRange, m_batchSize, descriptorWidth, descriptorHeight); + auto imageTensorDescriptor = CreateImageTensorDescriptor(tensorKind, pixelFormat.value(), pixelRange.value(), m_batchSize, descriptorWidth, descriptorHeight); return ImageResourceMetadata{bounds, imageTensorDescriptor}; } diff --git a/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp b/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp index 96fae01ff1..090dcf72ee 100644 --- a/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp +++ b/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp @@ -260,6 +260,14 @@ static void Scenario6BindWithProperties() { // insert it in the property set propertySet.Insert(L"BitmapPixelFormat", bitmapPixelFormatProperty); + // make a LearningModelPixelRange + LearningModelPixelRange pixelRange = LearningModelPixelRange::ZeroTo255; + // translate it to an int so it can be used as a PropertyValue; + int intFromLearningModelPixelRange = static_cast(pixelRange); + auto pixelRangeProperty = wf::PropertyValue::CreateInt32(intFromLearningModelPixelRange); + // insert it in the property set + propertySet.Insert(L"PixelRange", pixelRangeProperty); + // bind with properties WINML_EXPECT_NO_THROW(binding.Bind(input.Name(), imageValue, propertySet)); }