东方耀AI技术分享

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 1174|回复: 1
打印 上一主题 下一主题

[C/C++] cuda编程:GPU上做图像卷积操作与报错调试HandleError

[复制链接]

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14446
QQ
跳转到指定楼层
楼主
发表于 2021-6-8 14:52:19 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式


cuda编程:GPU上做图像卷积操作




  1. #include "stdio.h"

  2. static void HandleError(cudaError_t err,
  3.                         const char *file,
  4.                         int line)
  5.                         {
  6.                             if(err != cudaSuccess)
  7.                             {
  8.                                 printf("错误:%s在%s中%d行,看看吧\n",
  9.                                 cudaGetErrorString(err),
  10.                                 file, line);
  11.                                 exit(EXIT_FAILURE);
  12.                             }
  13.                         }
  14. #define HANDLE_ERROR(err) (HandleError(err, __FILE__, __LINE__))

  15. int getThreadNum()
  16. {
  17.     cudaDeviceProp prop;
  18.     int count;

  19.     HANDLE_ERROR(cudaGetDeviceCount(&count));
  20.     printf("gpu num %d\n", count);
  21.     HANDLE_ERROR(cudaGetDeviceProperties(&prop, 0));
  22.     printf("max thread num: %d\n", prop.maxThreadsPerBlock);
  23.     printf("max grid dimensions: %d, %d, %d)\n",
  24.      prop.maxGridSize[0], prop.maxGridSize[1], prop.maxGridSize[2]);
  25.     return prop.maxThreadsPerBlock;
  26. }

  27. __global__ void conv(float *img, float *kernel, float *result,
  28.     int width, int height, int kernelSize)
  29.     {
  30.         int ti = threadIdx.x; //线程id
  31.         int bi = blockIdx.x;  //block id
  32.         //blockDim.x 块的维度大小 实际就是 每个block的线程总数
  33.         int id = (bi * blockDim.x + ti);
  34.         // 这个id就是 相当于所有数据的下标一样的  是一维的
  35.         if(id >= width * height)
  36.         {
  37.             return;
  38.         }
  39.         // id转为二维的索引 row col
  40.         int row = id / width;  // 行号
  41.         int col = id % width;  // 列号
  42.         // 图像上的一个像素点对应了3*3次相乘后求和:卷积操作的定义 所以必须用循环了
  43.         for(int i = 0; i < kernelSize; ++i)
  44.         {
  45.             for(int j = 0; j < kernelSize; ++j)
  46.             {
  47.                 float imgValue = 0;  // 图像像素点的值
  48.                 int curRow = row - kernelSize / 2 + i;
  49.                 int curCol = col - kernelSize / 2 + j;
  50.                 if(curRow < 0 || curCol < 0 || curRow >= height || curCol >= width)
  51.                 {
  52.                     //超出图像的边界了 啥也不做
  53.                 }
  54.                 else
  55.                 {
  56.                     imgValue = img[curRow * width + curCol];
  57.                 }
  58.                 // 看出:传进来的 img kernel result 都是一维的数组 指针
  59.                 result[id] += kernel[i * kernelSize + j] * imgValue;
  60.             }

  61.         }
  62.     }

  63. //cuda编程:GPU上做图像卷积操作
  64. int main()
  65. {
  66.     int width = 1920;
  67.     int height = 1080;
  68.     // new操作符 堆空间分配空间
  69.     float *img = new float[width * height];
  70.     for(int row = 0; row < height; ++row)
  71.     {
  72.         for(int col = 0; col < width; ++col)
  73.         {
  74.             img[col + row * width] = (col + row) % 256;  // 赋值
  75.         }
  76.     }

  77.     int kernelSize = 3;
  78.     float *kernel = new float[kernelSize * kernelSize];
  79.     for(int i = 0; i < kernelSize * kernelSize; ++i)
  80.     {
  81.         kernel[i] = i % kernelSize - 1;   // 卷积核 赋值
  82.     }

  83.     float *imgGpu;
  84.     float *kernelGpu;
  85.     float *resultGpu;
  86.     // 分配gpu空间
  87.     HANDLE_ERROR(cudaMalloc(&imgGpu, width * height * sizeof(float)));
  88.     HANDLE_ERROR(cudaMalloc(&kernelGpu, kernelSize * kernelSize * sizeof(float)));
  89.     HANDLE_ERROR(cudaMalloc(&resultGpu, width * height * sizeof(float)));

  90.     HANDLE_ERROR(cudaMemcpy(imgGpu, img,
  91.      width * height * sizeof(float), cudaMemcpyHostToDevice));
  92.     HANDLE_ERROR(cudaMemcpy(kernelGpu, kernel,
  93.      kernelSize * kernelSize * sizeof(float), cudaMemcpyHostToDevice));
  94.    
  95.    
  96.     int threadNum = getThreadNum();   // 线程数 全部分配=1024
  97.     int blockNum = (width * height - 0.5) / threadNum + 1;  // 块的数目会根据实际数据长度来分

  98.     conv<<<blockNum, threadNum>>>
  99.         (imgGpu, kernelGpu, resultGpu, width, height, kernelSize);

  100.     float *result = new float[width * height];
  101.     HANDLE_ERROR(cudaMemcpy(result, resultGpu,
  102.     width * height * sizeof(float), cudaMemcpyDeviceToHost));

  103.     // visualization
  104.     printf("img\n");
  105.     for(int row = 0; row < 10; ++row)
  106.     {
  107.         for(int col = 0; col < 10; ++col)
  108.         {
  109.             printf("%2.0f ", img[col + row * width]);
  110.         }
  111.         printf("\n");
  112.     }
  113.     printf("kernel\n");
  114.     for(int row = 0; row < kernelSize; ++row)
  115.     {
  116.         for(int col = 0; col < kernelSize; ++col)
  117.         {
  118.             printf("%2.0f ", kernel[col + row * kernelSize]);
  119.         }
  120.         printf("\n");
  121.     }

  122.     printf("result\n");
  123.     for(int row = 0; row < 10; ++row)
  124.     {
  125.         for(int col = 0; col < 10; ++col)
  126.         {
  127.             printf("%2.0f ", result[col + row * width]);
  128.         }
  129.         printf("\n");
  130.     }


  131.     return 0;
  132. }
复制代码


conv0.png (49.54 KB, 下载次数: 78)

conv0.png
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

0

主题

98

帖子

200

积分

中级会员

Rank: 3Rank: 3

积分
200
沙发
发表于 2021-11-23 19:40:14 | 只看该作者
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|人工智能工程师的摇篮 ( 湘ICP备2020019608号-1 )

GMT+8, 2024-6-2 19:49 , Processed in 0.188316 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表