我一直在尝试使用 CUDA 和 libpng 库来处理影像(即应用黑白滤镜)。但是,我不确定如何将影像资料传递给设备。
据我了解,libpng 库读取 png 并使用此函式将信息逐行存盘在名为 row_pointers 的 png_bytep 结构中。
void read_png_file(char* file_name){
char header[8]; // 8 is the maximum size that can be checked
FILE *fp = fopen(file_name, "rb");
if (!fp)
abort_("[read_png_file] File %s could not be opened for reading" file_name);
fread(header, 1, 8, fp);
// if (png_sig_cmp(header, 0, 8))
// abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);
//Inicializa variables necesarias para libpng
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
abort_("[read_png_file] png_create_read_struct failed");
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
abort_("[read_png_file] png_create_info_struct failed");
if (setjmp(png_jmpbuf(png_ptr)))
abort_("[read_png_file] Error during init_io");
//Inicializa el input/output para el archivo PNG
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
//Lee la información anterior a los datos de los píxeles como tal
png_read_info(png_ptr, info_ptr);
//Almacena información del archivo PNG
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
// Lectura del archivo PNG
if (setjmp(png_jmpbuf(png_ptr)))
abort_("[read_png_file] Error during read_image");
// Reserva el espacio necesario para almacenar los datos del archivo PNG por filas
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y )
row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
// Y para la copia para el device
d_row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y )
d_row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
png_read_image(png_ptr, row_pointers);
fclose(fp);
}
我一直在尝试传递存盘在 row_pointers 中的信息,创建一个名为 d_row_pointers 的副本,并使用 cudaMalloc 和 cudaMemcpy 函式,如下所示:
png_bytep * row_pointers;
png_bytep * d_row_pointers;
int main(int argc, char **argv)
{
// Verifica los parámetros para ejecutar el programa
if (argc != 3)
abort_("Uso: ./Nombre_del_Programa <file_in> <file_out>");
read_png_file(argv[1]);
// CUDA
int size = sizeof(png_bytep);
int int_size = sizeof(int);
cudaMalloc((void **)&d_row_pointers, size);
for (y=0; y<height; y )
cudaMalloc((void **)&d_row_pointers[y],png_get_rowbytes(png_ptr,info_ptr));
cudaMalloc((void **)&d_width, int_size);
cudaMalloc((void **)&d_height, int_size);
cudaMemcpy(d_row_pointers, &row_pointers, size, cudaMemcpyHostToDevice);
for (y=0; y<height; y )
cudaMemcpy(d_row_pointers[y], &row_pointers[y], png_get_rowbytes(png_ptr,info_ptr), cudaMemcpyHostToDevice);
cudaMemcpy(d_width, &width, int_size, cudaMemcpyHostToDevice);
cudaMemcpy(d_height, &height, int_size, cudaMemcpyHostToDevice);
// Lanzar el kernel
process_file<<<1,1>>>(d_row_pointers, d_width, d_height);
// Copiar los resultados de vuelta al host
cudaMemcpy(&row_pointers, d_row_pointers, size, cudaMemcpyDeviceToHost);
// Limpieza
for (y=0; y<height; y )
cudaFree(d_row_pointers[y]);
cudaFree(d_row_pointers);
cudaFree(d_width);
cudaFree(d_height);
// Escritura de la imagen con los resultados
write_png_file(argv[2]);
return 0;
}
这是应该应用过滤器的 process_file 函式
__global__ void process_file(png_bytep * d_row_pointers, int * d_width, int * d_height)
{
// Se realizan los cambios deseados en la imagen
//Verificar los datos recibidos
printf("Width = %d , Height = %d ", *d_width, *d_height);
int rgb_total = 0;
float rgb_average = 0.0;
int x = 0;
int y = 0;
png_byte *row;
png_byte *ptr;
for (y=0; y<*d_height-1; y ) {
for (x=0; x<*d_width; x ) {
rgb_total = 0;
rgb_average = 0;
row = d_row_pointers[y];
ptr = &(row[x*3]);
printf("Pixel %d - %d, Rgb values: %d - %d - %d \n", x, y, ptr[0], ptr[1], ptr[2]);
rgb_total = ptr[0] ptr[1] ptr[2];
// Calculando el promedios RGB
rgb_average = rgb_total / 3;
// printf("Average: %d \n", (int)rgb_average);
ptr[0] = (int)rgb_average;
ptr[1] = (int)rgb_average;
ptr[2] = (int)rgb_average;
// printf("Changed to %d - %d - %d \n",ptr[0], ptr[1], ptr[2]);
// printf("Pixel %d - %d done\n",x,y);
}
}
// printf("Para la imagen de resolución: %d x %d - ", *width, *height);
}
但我无法让它作业,即使内核似乎正在接收结构,当我访问资料时它全为零,当它被认为是 RGB 值时。我非常感谢有关将这些资料传递给内核的正确方法的任何帮助。谢谢!
PD:完整的代码可以在这里找到
uj5u.com热心网友回复:
我很确定这条线会导致问题:
cudaMemcpy(d_row_pointers[y], &row_pointers[y],
png_get_rowbytes(png_ptr,info_ptr), cudaMemcpyHostToDevice);
您无法d_row_pointers[y]
从 cpu 代码访问资料。cudaMalloc 需要一个指向 cpu 上的指标的指标,并将这样处理自变量。
您需要小心 CUDA 中的多维阵列。大多数人选择使用平面阵列,即使是影像。
这就是我的建议:将资料复制到平面(一维)缓冲区,然后将其复制到设备。这样会更难犯错误。
啊,还有一件事:您不需要明确地 cudaMalloc 和 cudaMemcpy 内核的宽度和高度自变量。您可以按值传递它们,就好像它是一个普通函式一样。您只需要那些用于阵列的函式。
0 评论