gpt4 book ai didi

c++ - 具有 3 个 channel 的 nppi 调整大小功能得到奇怪的输出

转载 作者:行者123 更新时间:2023-12-01 22:58:00 25 4
gpt4 key购买 nike

在使用 nppi cuda 库中的 nppi 几何变换函数时,我遇到了一个奇怪的错误。代码在这里:

#include <nppi.h>
#include <nppi_geometry_transforms.h>

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <vector>

void write(const cv::Mat &mat1, const std::string &path) {
auto mat2 = cv::Mat(mat1.rows, mat1.cols, CV_8UC4);
for (int i = 0; i < mat1.rows; i++) {
for (int j = 0; j < mat1.cols; j++) {
auto &bgra = mat2.at<cv::Vec4b>(i, j);
auto &rgb = mat1.at<cv::Vec3b>(i, j);
bgra[0] = rgb[2];
bgra[1] = rgb[1];
bgra[2] = rgb[0];
bgra[3] = UCHAR_MAX;
}
}
std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
compression_params.push_back(9);
cv::imwrite(path, mat2, compression_params);
}

int main() {
std::cout << "Hello, World!" << std::endl;
auto mat = cv::Mat(256, 256, CV_8UC3);
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
auto &rgb = mat.at<cv::Vec3b>(i, j);
rgb[0] = (uint8_t)j;
rgb[1] = (uint8_t)i;
rgb[2] = (uint8_t)(UCHAR_MAX - j);
}
}
write(mat, "./test.png");
uint8_t *gpuBuffer1;
uint8_t *gpuBuffer2;
cudaMalloc(&gpuBuffer1, mat.total());
cudaMalloc(&gpuBuffer2, mat.total());
cudaMemcpy(gpuBuffer1, mat.data, mat.total(), cudaMemcpyHostToDevice);
auto status = nppiResize_8u_C3R(
gpuBuffer1, mat.cols * 3, {.width = mat.cols, .height = mat.rows},
{.x = 0, .y = 0, .width = mat.cols, .height = mat.rows}, gpuBuffer2,
mat.cols * 3, {.width = mat.cols, .height = mat.rows},
{.x = 0, .y = 0, .width = mat.cols, .height = mat.rows},
NPPI_INTER_NN);
if (status != NPP_SUCCESS) {
std::cerr << "Error executing Resize -- code: " << status << std::endl;
}
auto mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3);
cudaMemcpy(mat2.data, gpuBuffer2, mat.total(), cudaMemcpyDeviceToHost);
write(mat2, "./test1.png");
}

基本上我会显示彩虹图片。然后将其写入 GPU,然后将其调整为完全相同的大小,然后将其复制回主机,然后再次显示。我得到的是大约 2/3 的返回图片中的乱码数据。

original resized

第一张图片是输入图片。第二张输入图片为输出图片。

我希望两张图片是一样的。

如果我使用偏移量调整 ROI 并更改目标缓冲区的宽度和高度,则调整大小的图片顶部 1/3 中的像素实际上会正确移动和调整大小。但是图片的其余部分是乱码。不知道出了什么问题。有没有在 cuda nppi 库或图像处理方面有经验的人知道发生了什么事?

为了方便任何想要编译它的人,下面包含了 CMake 文件。您必须将 opencv 和 cuda 工具包安装为 C++ 库:

cmake_minimum_required(VERSION 3.18)
project(test_nppi)
enable_language(CUDA)
set(CMAKE_CXX_STANDARD 17)

find_package(CUDAToolkit REQUIRED)
find_package(OpenCV)

message(STATUS ${CUDAToolkit_INCLUDE_DIRS})
add_executable(test_nppi main.cu)
target_link_libraries(test_nppi ${OpenCV_LIBS} CUDA::nppig)
target_include_directories(test_nppi PUBLIC ${OpenCV_INCLUDE_DIRS} ${CUDAToolkit_INCLUDE_DIRS})

set_target_properties(test_nppi PROPERTIES
CUDA_SEPARABLE_COMPILATION ON)

我之前对单 channel 图片使用过nppi调整大小功能,但没有出现这个问题。 3 channel nppi resize 函数的输出很奇怪,我想我没有完全理解输入参数。由于有3个颜色 channel ,Step乘以3,但所有其他尺寸只是以像素为单位测量尺寸;并且 src 和 destination 的大小相同......不确定我在这里不理解什么。

最佳答案

问题是 mat.total() 等于像素总数,而不是字节总数。

根据 OpenCV documentation :

total () const
Returns the total number of array elements.

在您的代码示例中,mat.total() 等于 256*256,而总字节数等于 256*256*3 (RGB 每个像素应用 3 个字节)。
(在 OpenCV 术语中,“数组元素”相当于图像像素)。

cudaMemcpy(gpuBuffer1, mat.data, mat.total()... 仅复制图像总字节数的 1/3,因此只有图像数据的上 1/3 有效.


根据 this post ,计算字节数的正确方法是:

size_t mat_size_in_bytes = mat.step[0] * mat.rows;

在大多数情况下,对于 CV_8UC3mat.step[0] = mat.cols*3,但要涵盖所有情况,我们最好使用 mat.step[0]


更正后的代码示例:

#include "nppi.h"
#include "nppi_geometry_transforms.h"

#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include <vector>

void write(const cv::Mat& mat1, const std::string& path) {
auto mat2 = cv::Mat(mat1.rows, mat1.cols, CV_8UC4);
for (int i = 0; i < mat1.rows; i++) {
for (int j = 0; j < mat1.cols; j++) {
auto& bgra = mat2.at<cv::Vec4b>(i, j);
auto& rgb = mat1.at<cv::Vec3b>(i, j);
bgra[0] = rgb[2];
bgra[1] = rgb[1];
bgra[2] = rgb[0];
bgra[3] = UCHAR_MAX;
}
}
std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
compression_params.push_back(9);
cv::imwrite(path, mat2, compression_params);
}

int main() {
std::cout << "Hello, World!" << std::endl;
auto mat = cv::Mat(256, 256, CV_8UC3);
auto mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3);
for (int i = 0; i < mat.rows; i++) {
for (int j = 0; j < mat.cols; j++) {
auto& rgb = mat.at<cv::Vec3b>(i, j);
rgb[0] = (uint8_t)j;
rgb[1] = (uint8_t)i;
rgb[2] = (uint8_t)(UCHAR_MAX - j);
}
}
write(mat, "./test.png");
uint8_t* gpuBuffer1;
uint8_t* gpuBuffer2;
size_t mat_size_in_bytes = mat.step[0] * mat.rows; // https://stackoverflow.com/questions/26441072/finding-the-size-in-bytes-of-cvmat
size_t mat2_size_in_bytes = mat2.step[0] * mat2.rows;
cudaMalloc(&gpuBuffer1, mat_size_in_bytes);
cudaMalloc(&gpuBuffer2, mat2_size_in_bytes);
cudaMemcpy(gpuBuffer1, mat.data, mat_size_in_bytes, cudaMemcpyHostToDevice);

NppiSize oSrcSize = { mat.cols, mat.rows };
NppiRect oSrcRectROI = { 0, 0, mat.cols, mat.rows };
NppiSize oDstSize = { mat2.cols, mat2.rows };
NppiRect oDstRectROI = { 0, 0, mat2.cols, mat2.rows };

auto status = nppiResize_8u_C3R(
gpuBuffer1, mat.step[0], oSrcSize,
oSrcRectROI, gpuBuffer2,
mat2.step[0], oDstSize,
oDstRectROI,
NPPI_INTER_NN);

if (status != NPP_SUCCESS) {
std::cerr << "Error executing Resize -- code: " << status << std::endl;
}

cudaMemcpy(mat2.data, gpuBuffer2, mat2_size_in_bytes, cudaMemcpyDeviceToHost);
write(mat2, "./test1.png");
}

输出:
enter image description here

关于c++ - 具有 3 个 channel 的 nppi 调整大小功能得到奇怪的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72588979/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com