cv::MAT如何转换为NHCW格式?
How cv::MAT convert to NHCW format?
在用户Guide.html中,tensorRT的Input/output需要使用NCHW格式。
NCHW 格式是什么?
如何将 cv::MAT 转换为 NCHW 格式?
我 运行 像下面的代码一样使用 TensorRT 进行推理。
没有错误。但是,这不是正确的输出结果。
int batchSize = 1;
int size_of_single_input = 256 * 256 * 3 * sizeof(float);
int size_of_single_output = 100 * 1 * 1 * sizeof(float);
IBuilder* builder = createInferBuilder(gLogger);
INetworkDefinition* network = builder->createNetwork();
CaffeParser parser;
auto blob_name_to_tensor = parser.parse(“deploy.prototxt”,
"sample.caffemodel",
*network,
DataType::kFLOAT);
network->markOutput(*blob_name_to_tensor->find("prob"));
builder->setMaxBatchSize(1);
builder->setMaxWorkspaceSize(1 << 30);
ICudaEngine* engine = builder->buildCudaEngine(*network);
IExecutionContext *context = engine->createExecutionContext();
int inputIndex = engine->getBindingIndex(INPUT_LAYER_NAME),
int outputIndex = engine->getBindingIndex(OUTPUT_LAYER_NAME);
cv::Mat input;
input = imread("./sample.jpg");
cvtColor(input, input, CV_BGR2RGB);
cv::resize(input, input, cv::Size(256, 256));
float output[OUTPUTSIZE];
void* buffers = malloc(engine->getNbBindings() * sizeof(void*));
cudaMalloc(&buffers[inputIndex], batchSize * size_of_single_input);
cudaMalloc(&buffers[outputIndex], batchSize * size_of_single_output);
cudaStream_t stream;
cudaStreamCreate(&stream);
cudaMemcpyAsync(buffers[inputIndex], (float *)input,
batchSize * size_of_single_input,
cudaMemcpyHostToDevice, stream);
context.enqueue(batchSize, buffers, stream, nullptr);
cudaMemcpyAsync(output, buffers[outputIndex],
batchSize * size_of_single_output,
cudaMemcpyDeviceToHost, stream));
cudaStreamSynchronize(stream);
NCHW:对于 3 通道图像,比如 BGR,首先存储 B 通道的像素,然后是 G 通道,最后是 R 通道。
NHWC:对于每个像素,其 3 种颜色按 BGR 顺序存储在一起。
TensorRT 要求您的图像数据采用 NCHW 顺序。但是 OpenCV 以 NHWC 顺序读取它。您可以编写一个简单的函数来将数据从 NHWC 读取到一个缓冲区,您可以在缓冲区中按 NCHW 顺序存储它们。将此缓冲区复制到设备内存并传递给 TensorRT。
您可以在 TensorRT 安装的 samples/sampleFasterRCNN/sampleFasterRCNN.cpp
文件中找到此操作的示例。它读取 PPM 文件,该文件也是 NHWC 顺序,然后将其转换为 NCHW 顺序并减去平均值,这两个步骤都在一个步骤中完成。您可以修改它以满足您的目的。
此代码片段按照 Ashwin 的解释进行转换
bool SampleUffSSD::processInput(const samplesCommon::BufferManager& buffers)
const int batchSize = mParams.batchSize;
// Available images
std::vector<std::string> imageList = {"test.jpeg"};
mPPMs.resize(batchSize);
assert(mPPMs.size() <= imageList.size());
for (int i = 0; i < batchSize; ++i)
{
readImage(locateFile(imageList[i], mParams.dataDirs), image);
}
float* hostDataBuffer = static_cast<float*>(buffers.getHostBuffer(mParams.inputTensorNames[0]));
// Host memory for input buffer
for (int i = 0, volImg = inputH * inputW; i < mParams.batchSize; ++i)
{
for (unsigned j = 0, volChl = inputH * inputW; j < inputH; ++j)
{
for( unsigned k = 0; k < inputW; ++ k)
{
cv::Vec3b bgr = image.at<cv::Vec3b>(j,k);
hostDataBuffer[i * volImg + 0 * volChl + j * inputW + k] = (2.0 / 255.0) * float(bgr[2]) - 1.0;
hostDataBuffer[i * volImg + 1 * volChl + j * inputW + k] = (2.0 / 255.0) * float(bgr[1]) - 1.0;
hostDataBuffer[i * volImg + 2 * volChl + j * inputW + k] = (2.0 / 255.0) * float(bgr[0]) - 1.0;
}
}
}
// suppose all data types are int.
// size of mat is 256*256*3.
cv::Mat NCHW,NHWC;
std::vector<cv::Mat> channels;
split(NHWC, channels);
memcpy(NCHW.data,channels[0].data,256*256*sizeof(int));
memcpy(NCHW.data+256*256,channels[1].data,256*256*sizeof(int));
memcpy(NCHW.data+2*256*256,channels[2].data,256*256*sizeof(int));
这是另一个基于 OpenCV 的简单答案:
cv::resize(img, img, input_size);
img.convertTo(img, CV_32FC3, 1.f / 255.f);
vector<float> chw_buffer(img.elemSize() * img.total());
std::vector<Mat> chw;
for (size_t n = 0; n < channels; ++n)
chw.emplace_back(Mat(input_size, CV_32FC1, chw_buffer.data() + n * input_width * input_height));
cv::split(img, chw);
cudaMemcpyAsync(gpu_buffers[inputIndex], chw_buffer.size(), cudaMemcpyHostToDevice, stream);
这是 CPU 上 NHWC 到 NCHW 的简短直接解决方案:
static void hwc_to_chw(cv::InputArray src, cv::OutputArray dst) {
std::vector<cv::Mat> channels;
cv::split(src, channels);
// Stretch one-channel images to vector
for (auto &img : channels) {
img = img.reshape(1, 1);
}
// Concatenate three vectors to one
cv::hconcat( channels, dst );
}
在用户Guide.html中,tensorRT的Input/output需要使用NCHW格式。
NCHW 格式是什么?
如何将 cv::MAT 转换为 NCHW 格式?
我 运行 像下面的代码一样使用 TensorRT 进行推理。
没有错误。但是,这不是正确的输出结果。
int batchSize = 1;
int size_of_single_input = 256 * 256 * 3 * sizeof(float);
int size_of_single_output = 100 * 1 * 1 * sizeof(float);
IBuilder* builder = createInferBuilder(gLogger);
INetworkDefinition* network = builder->createNetwork();
CaffeParser parser;
auto blob_name_to_tensor = parser.parse(“deploy.prototxt”,
"sample.caffemodel",
*network,
DataType::kFLOAT);
network->markOutput(*blob_name_to_tensor->find("prob"));
builder->setMaxBatchSize(1);
builder->setMaxWorkspaceSize(1 << 30);
ICudaEngine* engine = builder->buildCudaEngine(*network);
IExecutionContext *context = engine->createExecutionContext();
int inputIndex = engine->getBindingIndex(INPUT_LAYER_NAME),
int outputIndex = engine->getBindingIndex(OUTPUT_LAYER_NAME);
cv::Mat input;
input = imread("./sample.jpg");
cvtColor(input, input, CV_BGR2RGB);
cv::resize(input, input, cv::Size(256, 256));
float output[OUTPUTSIZE];
void* buffers = malloc(engine->getNbBindings() * sizeof(void*));
cudaMalloc(&buffers[inputIndex], batchSize * size_of_single_input);
cudaMalloc(&buffers[outputIndex], batchSize * size_of_single_output);
cudaStream_t stream;
cudaStreamCreate(&stream);
cudaMemcpyAsync(buffers[inputIndex], (float *)input,
batchSize * size_of_single_input,
cudaMemcpyHostToDevice, stream);
context.enqueue(batchSize, buffers, stream, nullptr);
cudaMemcpyAsync(output, buffers[outputIndex],
batchSize * size_of_single_output,
cudaMemcpyDeviceToHost, stream));
cudaStreamSynchronize(stream);
NCHW:对于 3 通道图像,比如 BGR,首先存储 B 通道的像素,然后是 G 通道,最后是 R 通道。
NHWC:对于每个像素,其 3 种颜色按 BGR 顺序存储在一起。
TensorRT 要求您的图像数据采用 NCHW 顺序。但是 OpenCV 以 NHWC 顺序读取它。您可以编写一个简单的函数来将数据从 NHWC 读取到一个缓冲区,您可以在缓冲区中按 NCHW 顺序存储它们。将此缓冲区复制到设备内存并传递给 TensorRT。
您可以在 TensorRT 安装的 samples/sampleFasterRCNN/sampleFasterRCNN.cpp
文件中找到此操作的示例。它读取 PPM 文件,该文件也是 NHWC 顺序,然后将其转换为 NCHW 顺序并减去平均值,这两个步骤都在一个步骤中完成。您可以修改它以满足您的目的。
此代码片段按照 Ashwin 的解释进行转换
bool SampleUffSSD::processInput(const samplesCommon::BufferManager& buffers)
const int batchSize = mParams.batchSize;
// Available images
std::vector<std::string> imageList = {"test.jpeg"};
mPPMs.resize(batchSize);
assert(mPPMs.size() <= imageList.size());
for (int i = 0; i < batchSize; ++i)
{
readImage(locateFile(imageList[i], mParams.dataDirs), image);
}
float* hostDataBuffer = static_cast<float*>(buffers.getHostBuffer(mParams.inputTensorNames[0]));
// Host memory for input buffer
for (int i = 0, volImg = inputH * inputW; i < mParams.batchSize; ++i)
{
for (unsigned j = 0, volChl = inputH * inputW; j < inputH; ++j)
{
for( unsigned k = 0; k < inputW; ++ k)
{
cv::Vec3b bgr = image.at<cv::Vec3b>(j,k);
hostDataBuffer[i * volImg + 0 * volChl + j * inputW + k] = (2.0 / 255.0) * float(bgr[2]) - 1.0;
hostDataBuffer[i * volImg + 1 * volChl + j * inputW + k] = (2.0 / 255.0) * float(bgr[1]) - 1.0;
hostDataBuffer[i * volImg + 2 * volChl + j * inputW + k] = (2.0 / 255.0) * float(bgr[0]) - 1.0;
}
}
}
// suppose all data types are int.
// size of mat is 256*256*3.
cv::Mat NCHW,NHWC;
std::vector<cv::Mat> channels;
split(NHWC, channels);
memcpy(NCHW.data,channels[0].data,256*256*sizeof(int));
memcpy(NCHW.data+256*256,channels[1].data,256*256*sizeof(int));
memcpy(NCHW.data+2*256*256,channels[2].data,256*256*sizeof(int));
这是另一个基于 OpenCV 的简单答案:
cv::resize(img, img, input_size);
img.convertTo(img, CV_32FC3, 1.f / 255.f);
vector<float> chw_buffer(img.elemSize() * img.total());
std::vector<Mat> chw;
for (size_t n = 0; n < channels; ++n)
chw.emplace_back(Mat(input_size, CV_32FC1, chw_buffer.data() + n * input_width * input_height));
cv::split(img, chw);
cudaMemcpyAsync(gpu_buffers[inputIndex], chw_buffer.size(), cudaMemcpyHostToDevice, stream);
这是 CPU 上 NHWC 到 NCHW 的简短直接解决方案:
static void hwc_to_chw(cv::InputArray src, cv::OutputArray dst) {
std::vector<cv::Mat> channels;
cv::split(src, channels);
// Stretch one-channel images to vector
for (auto &img : channels) {
img = img.reshape(1, 1);
}
// Concatenate three vectors to one
cv::hconcat( channels, dst );
}