/* * SPDX-FileCopyrightText: Copyright (c) 1993-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "decodeBbox3D.h" #include "common/bboxUtils.h" #include "common/checkMacrosPlugin.h" #include "common/kernels/kernel.h" #include "common/templates.h" #include #include namespace nvinfer1::plugin { using nvinfer1::plugin::DecodeBbox3DPlugin; using nvinfer1::plugin::DecodeBbox3DPluginCreator; namespace { static char const* const kPLUGIN_VERSION{"1"}; static char const* const kPLUGIN_NAME{"DecodeBbox3DPlugin"}; } // namespace DecodeBbox3DPlugin::DecodeBbox3DPlugin(float xMin, float xMax, float yMin, float yMax, float zMin, float zMax, int32_t numDirBins, float dirOffset, float dirLimitOffset, std::vector const& anchorBottomHeight, std::vector const& anchors, float scoreThreshold) : mMinXRange(xMin) , mMaxXRange(xMax) , mMinYRange(yMin) , mMaxYRange(yMax) , mMinZRange(zMin) , mMaxZRange(zMax) , mNumDirBins(numDirBins) , mDirOffset(dirOffset) , mDirLimitOffset(dirLimitOffset) , mScoreThreashold(scoreThreshold) { mAnchorBottomHeight = anchorBottomHeight; mAnchors = anchors; mNumClasses = static_cast(mAnchorBottomHeight.size()); PLUGIN_VALIDATE(static_cast(mNumClasses) * 2 * 4 == mAnchors.size()); } DecodeBbox3DPlugin::DecodeBbox3DPlugin(float xMin, float xMax, float yMin, float yMax, float zMin, float zMax, int32_t numDirBins, float dirOffset, float dirLimitOffset, std::vector const& anchorBottomHeight, std::vector const& anchors, float scoreThreshold, int32_t feature_h, int32_t feature_w) : mMinXRange(xMin) , mMaxXRange(xMax) , mMinYRange(yMin) , mMaxYRange(yMax) , mMinZRange(zMin) , mMaxZRange(zMax) , mNumDirBins(numDirBins) , mDirOffset(dirOffset) , mDirLimitOffset(dirLimitOffset) , mScoreThreashold(scoreThreshold) , mFeatureH(feature_h) , mFeatureW(feature_w) { mAnchorBottomHeight = anchorBottomHeight; mAnchors = anchors; mNumClasses = static_cast(mAnchorBottomHeight.size()); PLUGIN_VALIDATE(static_cast(mNumClasses) * 2 * 4 == mAnchors.size()); } DecodeBbox3DPlugin::DecodeBbox3DPlugin(void const* data, size_t length) { PLUGIN_VALIDATE(data != nullptr); auto const* d = reinterpret_cast(data); mMinXRange = readFromBuffer(d); mMaxXRange = readFromBuffer(d); mMinYRange = readFromBuffer(d); mMaxYRange = readFromBuffer(d); mMinZRange = readFromBuffer(d); mMaxZRange = readFromBuffer(d); mNumDirBins = readFromBuffer(d); mDirOffset = readFromBuffer(d); mDirLimitOffset = readFromBuffer(d); mScoreThreashold = readFromBuffer(d); mNumClasses = readFromBuffer(d); mFeatureH = readFromBuffer(d); mFeatureW = readFromBuffer(d); mAnchorBottomHeight.resize(mNumClasses); for (int32_t i = 0; i < mNumClasses; i++) { mAnchorBottomHeight[i] = readFromBuffer(d); } mAnchors.resize(mNumClasses * 2 * 4); for (int32_t i = 0; i < mNumClasses * 2 * 4; i++) { mAnchors[i] = readFromBuffer(d); } PLUGIN_VALIDATE(d == reinterpret_cast(data) + length); } nvinfer1::IPluginV2DynamicExt* DecodeBbox3DPlugin::clone() const noexcept { try { auto plugin = std::make_unique(mMinXRange, mMaxXRange, mMinYRange, mMaxYRange, mMinZRange, mMaxZRange, mNumDirBins, mDirOffset, mDirLimitOffset, mAnchorBottomHeight, mAnchors, mScoreThreashold, mFeatureH, mFeatureW); plugin->setPluginNamespace(mNamespace.c_str()); return plugin.release(); } catch (std::exception const& e) { caughtError(e); } return nullptr; } nvinfer1::DimsExprs DecodeBbox3DPlugin::getOutputDimensions(int32_t outputIndex, nvinfer1::DimsExprs const* inputs, int32_t nbInputs, nvinfer1::IExprBuilder& exprBuilder) noexcept { try { PLUGIN_VALIDATE(getNbOutputs() == 2); PLUGIN_VALIDATE(outputIndex >= 0 && outputIndex < getNbOutputs()); PLUGIN_VALIDATE(inputs != nullptr); auto const& featureH = inputs[0].d[1]; auto const& featureW = inputs[0].d[2]; auto const& batchSize = inputs[0].d[0]; if (outputIndex == 0) { nvinfer1::DimsExprs dim0{}; dim0.nbDims = 3; dim0.d[0] = batchSize; dim0.d[1] = exprBuilder.operation(nvinfer1::DimensionOperation::kPROD, featureH[0], exprBuilder.operation( nvinfer1::DimensionOperation::kPROD, featureW[0], exprBuilder.constant(mNumClasses * 2)[0])[0]); dim0.d[2] = exprBuilder.constant(9); return dim0; } nvinfer1::DimsExprs dim1{}; dim1.nbDims = 1; dim1.d[0] = batchSize; return dim1; } catch (std::exception const& e) { caughtError(e); } return nvinfer1::DimsExprs{}; } bool DecodeBbox3DPlugin::supportsFormatCombination( int32_t pos, nvinfer1::PluginTensorDesc const* inOut, int32_t nbInputs, int32_t nbOutputs) noexcept { try { PLUGIN_VALIDATE(nbInputs == 3); PLUGIN_VALIDATE(nbOutputs == 2); PLUGIN_VALIDATE(inOut != nullptr); PLUGIN_VALIDATE((pos >= 0) && (pos < nbInputs + nbOutputs)); } catch (std::exception const& e) { caughtError(e); return false; } PluginTensorDesc const& in = inOut[pos]; if (pos == 0) // cls_preds { return (in.type == nvinfer1::DataType::kFLOAT) && (in.format == TensorFormat::kLINEAR); } if (pos == 1) // box_preds { return (in.type == nvinfer1::DataType::kFLOAT) && (in.format == TensorFormat::kLINEAR); } if (pos == 2) // dir_cls_preds { return (in.type == nvinfer1::DataType::kFLOAT) && (in.format == TensorFormat::kLINEAR); } if (pos == 3) // boxes { return (in.type == nvinfer1::DataType::kFLOAT) && (in.format == TensorFormat::kLINEAR); } if (pos == 4) // box_num { return (in.type == nvinfer1::DataType::kINT32) && (in.format == TensorFormat::kLINEAR); } return false; } void DecodeBbox3DPlugin::configurePlugin(nvinfer1::DynamicPluginTensorDesc const* in, int32_t nbInputs, nvinfer1::DynamicPluginTensorDesc const* out, int32_t nbOutputs) noexcept { try { PLUGIN_VALIDATE(in != nullptr); mFeatureH = in[0].desc.dims.d[1]; mFeatureW = in[0].desc.dims.d[2]; } catch (std::exception const& e) { caughtError(e); } } size_t DecodeBbox3DPlugin::getWorkspaceSize(nvinfer1::PluginTensorDesc const* inputs, int32_t nbInputs, nvinfer1::PluginTensorDesc const* outputs, int32_t nbOutputs) const noexcept { size_t mAnchorsSize = mNumClasses * 2 * 4 * sizeof(float); size_t mAnchorBottomHeightSize = mNumClasses * sizeof(float); size_t workspaces[2]; workspaces[0] = mAnchorsSize; workspaces[1] = mAnchorBottomHeightSize; return calculateTotalWorkspaceSize(workspaces, 2); } int32_t DecodeBbox3DPlugin::enqueue(nvinfer1::PluginTensorDesc const* inputDesc, nvinfer1::PluginTensorDesc const* /* outputDesc */, void const* const* inputs, void* const* outputs, void* workspace, cudaStream_t stream) noexcept { try { PLUGIN_VALIDATE(inputDesc != nullptr && inputs != nullptr && outputs != nullptr && workspace != nullptr); int32_t batchSize = inputDesc[0].dims.d[0]; // Inputs auto const* clsInput = static_cast(inputs[0]); auto const* boxInput = static_cast(inputs[1]); auto const* dirClsInput = static_cast(inputs[2]); // Outputs auto* bndboxOutput = static_cast(outputs[0]); auto* boxNum = static_cast(outputs[1]); // Initialize workspaces auto* anchors = static_cast(workspace); size_t anchorsSize = mNumClasses * 2 * 4 * sizeof(float); auto* anchorBottomHeight = reinterpret_cast(nextWorkspacePtr(reinterpret_cast(anchors), anchorsSize)); size_t anchorBottomHeightSize = mNumClasses * sizeof(float); PLUGIN_CUASSERT(cudaMemcpyAsync(anchors, mAnchors.data(), anchorsSize, cudaMemcpyHostToDevice, stream)); PLUGIN_CUASSERT(cudaMemcpyAsync( anchorBottomHeight, mAnchorBottomHeight.data(), anchorBottomHeightSize, cudaMemcpyHostToDevice, stream)); // Initialize boxNum to 0 PLUGIN_CUASSERT(cudaMemsetAsync(boxNum, 0, batchSize * sizeof(int32_t), stream)); decodeBbox3DLaunch(batchSize, clsInput, boxInput, dirClsInput, anchors, anchorBottomHeight, bndboxOutput, boxNum, mMinXRange, mMaxXRange, mMinYRange, mMaxYRange, mFeatureW, mFeatureH, mNumClasses * 2, mNumClasses, 7, mScoreThreashold, mDirOffset, mDirLimitOffset, mNumDirBins, stream); return cudaPeekAtLastError(); } catch (std::exception const& e) { caughtError(e); } return STATUS_FAILURE; } nvinfer1::DataType DecodeBbox3DPlugin::getOutputDataType( int32_t index, nvinfer1::DataType const* inputTypes, int32_t nbInputs) const noexcept { try { PLUGIN_VALIDATE(inputTypes != nullptr); if (index == 0) { return inputTypes[0]; } return nvinfer1::DataType::kINT32; } catch (std::exception const& e) { caughtError(e); } return nvinfer1::DataType{}; } char const* DecodeBbox3DPlugin::getPluginType() const noexcept { return kPLUGIN_NAME; } char const* DecodeBbox3DPlugin::getPluginVersion() const noexcept { return kPLUGIN_VERSION; } int32_t DecodeBbox3DPlugin::getNbOutputs() const noexcept { return 2; } int32_t DecodeBbox3DPlugin::initialize() noexcept { return 0; } void DecodeBbox3DPlugin::terminate() noexcept {} size_t DecodeBbox3DPlugin::getSerializationSize() const noexcept { size_t scalarSize = 9 * sizeof(float) + 4 * sizeof(int32_t); size_t vectorSize = mNumClasses * 9 * sizeof(float); return scalarSize + vectorSize; } void DecodeBbox3DPlugin::serialize(void* buffer) const noexcept { PLUGIN_ASSERT(buffer != nullptr); auto* d = reinterpret_cast(buffer); auto* const start = d; writeToBuffer(d, mMinXRange); writeToBuffer(d, mMaxXRange); writeToBuffer(d, mMinYRange); writeToBuffer(d, mMaxYRange); writeToBuffer(d, mMinZRange); writeToBuffer(d, mMaxZRange); writeToBuffer(d, mNumDirBins); writeToBuffer(d, mDirOffset); writeToBuffer(d, mDirLimitOffset); writeToBuffer(d, mScoreThreashold); writeToBuffer(d, mNumClasses); writeToBuffer(d, mFeatureH); writeToBuffer(d, mFeatureW); for (int32_t i = 0; i < mNumClasses; i++) { writeToBuffer(d, mAnchorBottomHeight[i]); } for (int32_t i = 0; i < mNumClasses * 2 * 4; i++) { writeToBuffer(d, mAnchors[i]); } PLUGIN_ASSERT(d == start + getSerializationSize()); } void DecodeBbox3DPlugin::destroy() noexcept { delete this; } void DecodeBbox3DPlugin::setPluginNamespace(char const* libNamespace) noexcept { try { PLUGIN_VALIDATE(libNamespace != nullptr); mNamespace = libNamespace; } catch (std::exception const& e) { caughtError(e); } } char const* DecodeBbox3DPlugin::getPluginNamespace() const noexcept { return mNamespace.c_str(); } DecodeBbox3DPluginCreator::DecodeBbox3DPluginCreator() { mPluginAttributes.clear(); mPluginAttributes.emplace_back(PluginField("point_cloud_range", nullptr, PluginFieldType::kFLOAT32, 1)); mPluginAttributes.emplace_back(PluginField("anchors", nullptr, PluginFieldType::kFLOAT32, 1)); mPluginAttributes.emplace_back(PluginField("anchor_bottom_height", nullptr, PluginFieldType::kFLOAT32, 1)); mPluginAttributes.emplace_back(PluginField("dir_offset", nullptr, PluginFieldType::kFLOAT32, 1)); mPluginAttributes.emplace_back(PluginField("dir_limit_offset", nullptr, PluginFieldType::kFLOAT32, 1)); mPluginAttributes.emplace_back(PluginField("num_dir_bins", nullptr, PluginFieldType::kINT32, 1)); mPluginAttributes.emplace_back(PluginField("score_thresh", nullptr, PluginFieldType::kFLOAT32, 1)); mFC.nbFields = mPluginAttributes.size(); mFC.fields = mPluginAttributes.data(); } char const* DecodeBbox3DPluginCreator::getPluginName() const noexcept { return kPLUGIN_NAME; } char const* DecodeBbox3DPluginCreator::getPluginVersion() const noexcept { return kPLUGIN_VERSION; } PluginFieldCollection const* DecodeBbox3DPluginCreator::getFieldNames() noexcept { return &mFC; } IPluginV2* DecodeBbox3DPluginCreator::createPlugin(char const* /*name*/, PluginFieldCollection const* fc) noexcept { using namespace std::string_view_literals; try { PLUGIN_VALIDATE(fc != nullptr); PluginField const* fields = fc->fields; // Initialize default values for attributes. float pointCloudRange[6] = {0.F}; std::vector anchors{}; std::vector anchorBottomHeight{}; float dirOffset = 0.78539F; float dirLimitOffset = 0.F; int32_t numDirBins = 2; float scoreThreshold = 0.F; for (int32_t i = 0; i < fc->nbFields; ++i) { std::string_view const attr_name = fields[i].name; if (attr_name == "point_cloud_range"sv) { auto const* d = static_cast(fields[i].data); for (int32_t pointCloudIdx = 0; pointCloudIdx < 6; pointCloudIdx++) { pointCloudRange[pointCloudIdx] = d[pointCloudIdx]; } } else if (attr_name == "anchors"sv) { auto const* d = static_cast(fields[i].data); for (int32_t j = 0; j < fields[i].length; ++j) { anchors.push_back(d[j]); } } else if (attr_name == "anchor_bottom_height"sv) { auto const* d = static_cast(fields[i].data); for (int32_t j = 0; j < fields[i].length; ++j) { anchorBottomHeight.push_back(d[j]); } } else if (attr_name == "dir_offset"sv) { auto const* d = static_cast(fields[i].data); dirOffset = d[0]; } else if (attr_name == "dir_limit_offset"sv) { auto const* d = static_cast(fields[i].data); dirLimitOffset = d[0]; } else if (attr_name == "num_dir_bins"sv) { auto const* d = static_cast(fields[i].data); numDirBins = d[0]; } else if (attr_name == "score_thresh"sv) { auto const* d = static_cast(fields[i].data); scoreThreshold = d[0]; } } auto plugin = std::make_unique(pointCloudRange[0], pointCloudRange[3], pointCloudRange[1], pointCloudRange[4], pointCloudRange[2], pointCloudRange[5], numDirBins, dirOffset, dirLimitOffset, anchorBottomHeight, anchors, scoreThreshold); return plugin.release(); } catch (std::exception const& e) { caughtError(e); } return nullptr; } IPluginV2* DecodeBbox3DPluginCreator::deserializePlugin( char const* /*name*/, void const* serialData, size_t serialLength) noexcept { try { return new DecodeBbox3DPlugin(serialData, serialLength); } catch (std::exception const& e) { caughtError(e); } return nullptr; } void DecodeBbox3DPluginCreator::setPluginNamespace(char const* libNamespace) noexcept { try { PLUGIN_VALIDATE(libNamespace != nullptr); mNamespace = libNamespace; } catch (std::exception const& e) { caughtError(e); } } char const* DecodeBbox3DPluginCreator::getPluginNamespace() const noexcept { return mNamespace.c_str(); } } // namespace nvinfer1::plugin