算法思路

  • 传统的泛红算法主要有两种方法,递归或者队列扫描,这两种方法在总体思路大致都是从种子点开始,逐步扫描周围的符合要求的点(比如和种子点颜色距离小于一个规定的值),当出现符合要求的点后将此点染色,同时继续在此点周围扫描下一个符合要求的点。
  • 此cuda泛洪算法也借鉴了传统的cpu算法,从种子点开始“生长”,但与cpu算法不同的是,使用cuda时的“扫描”下一个符合要求的点时,是并行处理的。这就意味着,当生长的区域的接近圆形块状区域时,使用cuda的扫描将比cpu快很多倍,可以理解为cpu扫描一次只能判断一个点,cuda一次可以判断当前已染色区域轮廓外的一圈点。

具体实现

  • 首先确定cuda所使用的block与thread:因为存在扫描的循环何时停止问题,各线程之间需要一个共同的变量来判断while循环是否进行下去,而各线程的处理进度肯定各不相同,所以此时需要一个线程间的同步:__syncthread() 。所以,我选择在一个block里装满线程,正好也可以使用block内的共享内存来完成while循环的判断。
  • 借鉴cpu使用队列来存储需扫描的点的思路,我直接创建了一个与原始图片同样大小的数组state[](通过x和y计算offset,同样是一维数组),数组初始化全0,表示所有点未被访问过。在扫描的过程中,当某个点被染色后,就讲此点所对应的state数组中的值改为1,表示已访问过,且此后的扫描将不再访问此点。
  • 定义一个共享内存need_continue,作为主while循环的判定条件,定义一个共享内存more,表示此次循环有扫描到新的符合条件的点。在每一次的主while循环的开始,先将more置0,同步一下。此后若有线程扫描到新的点,便将more置1。此轮主循环的最后,若more是1,则主while循环继续,否则,就退出循环,结束计算。

具体代码

CUDA主函数

void floodFillwithGPU( uchar * mat_data, int rows, int cols, int startX, int startY,int randR,int randG,int randB) {uchar* gpu_mat_data;uchar* gpu_mat_state;cudaError_t cudaStatus;//申请空间cudaStatus = cudaMalloc((void**)&gpu_mat_data, rows * cols * 3);if (cudaStatus != cudaSuccess) {fprintf(stderr, "cudaMalloc failed!");goto err;}cudaStatus = cudaMalloc((void**)&gpu_mat_state, rows * cols  );if (cudaStatus != cudaSuccess) {fprintf(stderr, "cudaMalloc failed!");goto err;}cudaStatus = cudaMemcpy(gpu_mat_data,mat_data, rows * cols * 3,cudaMemcpyHostToDevice);if (cudaStatus != cudaSuccess) {fprintf(stderr, "cudaMemcpy failed!");goto err;}kernel << < 1, threadsPerBlock >> > (gpu_mat_data, gpu_mat_state, startX, startY, rows, cols, randR, randG, randB);cudaStatus = cudaMemcpy(mat_data, gpu_mat_data,rows * cols * 3,cudaMemcpyDeviceToHost);if (cudaStatus != cudaSuccess) {fprintf(stderr, "cudaMemcpy failed!");goto err;}err:cudaFree(gpu_mat_data);cudaFree(gpu_mat_state);
}

核函数

__global__ void kernel(unsigned char* mat_p, unsigned char* state_p, int startX, int startY , int rows, int cols, int randR, int randG, int randB) {__shared__ int R,G,B;__shared__ int need_continue;__shared__ int more;int size = rows * cols;int cnt = 0;int i;int offset = threadIdx.x;int root_offset = startX + startY * cols;while (offset < size) {//初始化,获得root颜色if(offset == root_offset) {R = mat_p[root_offset * 3 + 0];G = mat_p[root_offset * 3 + 1];B = mat_p[root_offset * 3 + 2];deal(offset , mat_p, state_p, R, G, B,randR,randG,randB);//more = true;state_p[offset] = 1;}else {state_p[offset] = 0;}offset += blockDim.x;}if (threadIdx.x == 0) {need_continue = 1;more = 0;}__syncthreads();while (need_continue) {offset = threadIdx.x;while (offset < size) {// cols 为每行元素个数if (state_p[offset] == 1) {if (!more) {atomicAdd(&more, 1);}state_p[offset ] = 2;if (offset % cols == 0) {//left sideif (offset / cols == 0) { //top sidedeal(offset + 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + cols, mat_p, state_p, R, G, B, randR, randG, randB);}else if (offset / cols == rows -1 ) { //bottomdeal(offset + 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset - cols, mat_p, state_p, R, G, B, randR, randG, randB);}else {deal(offset + 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + cols, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset - cols, mat_p, state_p, R, G, B, randR, randG, randB);}}else if (offset % cols == cols - 1) { //right sideif (offset / cols == 0) { //top sidedeal(offset - 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + cols, mat_p, state_p, R, G, B, randR, randG, randB);}else if (offset / cols == rows - 1) { //bottomdeal(offset - 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset - cols, mat_p, state_p, R, G, B, randR, randG, randB);}else {deal(offset - 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + cols, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset - cols, mat_p, state_p, R, G, B, randR, randG, randB);}}else if (offset / cols == 0) { //just topdeal(offset - 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + cols, mat_p, state_p, R, G, B, randR, randG, randB);}else if (offset / cols == rows - 1) { //just topdeal(offset - 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset - cols, mat_p, state_p, R, G, B, randR, randG, randB);}else {deal(offset - cols, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + cols, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset - 1, mat_p, state_p, R, G, B, randR, randG, randB);deal(offset + 1, mat_p, state_p, R, G, B, randR, randG, randB);}}offset += blockDim.x;}__syncthreads();if (threadIdx.x == 0) {if (more) {need_continue = true;more = 0;}else {need_continue = false;}}__syncthreads();}
}

上色函数

__device__ void deal( int new_offset, unsigned char* mat_p, unsigned char* state_p,int R,int G,int B, int randR, int randG, int randB) {if (state_p[new_offset] == 0) {int r = mat_p[new_offset * 3 + 0];int g = mat_p[new_offset * 3 + 1];int b = mat_p[new_offset * 3 + 2];if( fabsf(r-R)<10 && fabsf(g-G)<10 && fabsf(b-B)<10 ){//if(r==R && g==G && b==B){state_p[ new_offset ] = 1;mat_p[new_offset * 3 + 0] = randB;mat_p[new_offset * 3 + 1] = randG;mat_p[new_offset * 3 + 2] = randR;}}
}

最终效果

因为并行处理的存在,所以在处理块状区域时使用cuda比传统cpu算法快上不少。但对于细长条形的区域,此cuda法将比传统cpu算法慢上不少。当处理的区域为块状区域时(如下图)

种子点取紫色区域中心时,此cuda算法需15ms左右,传统cpu算法需110ms左右

种子点取蓝色区域红色‘+’位置时,此cuda算法需50ms左右,传统cpu算法需100ms左右

而当填充这种细长条形区域时,此cuda算法需1s左右,而传统cpu算法仅需110ms左右

而当填充上图橙红色区域时(上图橙红色区域为迷宫的‘路’,是完全连通的),对于这种既细长又有一定的宽度的图形,种子点选取为图片左上角圆形迷宫外蓝色‘+’处。此时此cuda算法需1150ms左右,传统cpu算法需1200ms左右。

学习记录 --用CUDA完成泛洪算法相关推荐

  1. 全息图像学习记录(1)——SFFT算法

    全息图像学习记录(1)--SFFT算法 (第一次写作) 编程环境 具体代码 小结 (第一次写作) 最近开始搞全息图的模拟,现在以这种方式记录下来.在光学里,菲涅耳衍射(Fresnel diffract ...

  2. 2023.2.3,周五【图神经网络 学习记录17】二部图——BiNE算法:显式关系,隐式关系;新的随机游走方式 特点:随机游走次数 是跟节点中心性相关的,在随机游走的过程中 添加一个停止随机游走的概率

    声明:仅学习使用~ 前情提要: 2023.2.2,周四[图神经网络 学习记录16]异构图Graph Embedding算法--GATNE(异构图多属性 多边 类型算法),不建议普通PC跑-PyChar ...

  3. 【学习 记录】狄克斯特拉算法 - Java

    最近学习<算法图解>一书时,看到狄克斯特拉算法之前没有使用过,在学习后用常用语言Java将算法实现出来以加深印象. 作用 狄克斯特拉算法用于找出最快的路径,而常用的广度优先搜索算法可用于找 ...

  4. 学习记录1.0(基础算法)

    蒟蒻的总结 主要总结了排序.前缀和(偷懒).差分(偷懒).离散化和区间和并问题. 还没学哈希表.二叉树啥的 ,学了之后会更新的新的做法的! 大部分都来自Acwing啦! 1.快速排序 用指针左右往中间 ...

  5. [数据结构与算法] 学习记录合辑 (07) 图

    该合辑为笔者自b站自学的"C++数据结构与算法"课程学习记录,旨在将重要的学习要点.思考内容与部分代码进行记录,以便后续自行翻看,亦可给其他读者带来一些参考 内容基于笔者自身的理解 ...

  6. 学习记录:二层网络环路相关

    学习记录 上周实习过程中由于对此相关内容不熟悉,造成了事故.由此对相关内容加强学习,特此记录. 目录 学习记录 一.交换机相关 二.网络环路的产生 三.网络环路的影响 四.如何避免网络环路 五.二层环 ...

  7. 大创学习记录(四)之yolov3代码学习

    PyTorch-YOLOv3项目训练与代码学习 借助从零开始的PyTorch项目理解YOLOv3目标检测的实现 PyTorch 对于PyTorch就不用多说了,目前最灵活.最容易掌握的深度学习库,它有 ...

  8. SSD训练数据集流程(学习记录)

    关于理论部分我看的是b站"霹雳吧啦Wz"的SSD理论讲解,作为入门小白表示能听懂,需要的同学可以自行观看 目录 1.训练环境 2.训练步骤 1.训练环境 我的环境是win11+an ...

  9. PyTorch学习记录——PyTorch进阶训练技巧

    PyTorch学习记录--PyTorch进阶训练技巧 1.自定义损失函数 1.1 以函数的方式定义损失函数 1.2 以类的方式定义损失函数 1.3 比较与思考 2.动态调整学习率 2.1 官方提供的s ...

最新文章

  1. zigbee 串口不稳定_基于项目的ZigBee系统组网介绍
  2. 当红网络财富人生 用科技狂澜财富成为首富
  3. openGL光照要点总结
  4. Java操作itext,寻找给定关键字,并且进行页面抽取和页面盖章两个操作
  5. python2.7安装教程win7_win7 64位环境下,为python2.7 安装pip
  6. 基于Haproxy的高可用实战
  7. java数组及循环专题练习(使用数组和循环结构实现一个简易的功能完善的订餐系统)
  8. 不同主机之间通过XDMCP协议通信(X-server和X-client不在同一主机)
  9. 引用 孙悟空的师傅菩提祖师的真实真份和镇元大仙辈份排名+四大灵猴
  10. OSChina 周四乱弹 —— 八字欠备,五行缺胎
  11. 2021年场(厂)内专用机动车辆安全管理考试及场(厂)内专用机动车辆安全管理考试题
  12. Wire Load Model (线负载模型)
  13. 云虚拟主机+WordPress搭建个人博客详细内容
  14. 使用MATLAB计算一幅图像的熵
  15. 两个div并排 左边div宽固定 右边自适应
  16. 自动化 Google 以图搜图
  17. Android学习之手机传感器的获取
  18. 一条气象预警是如何产生的
  19. VB.NET版机房收费系统---组合查询
  20. 行编辑器c语言,简单的行编辑器(C语言).doc

热门文章

  1. 开关电源测试软件有哪些,请问开关电源的测试仪器都有哪些
  2. 脱离极域电子课堂控制
  3. tgp饥荒服务器修改人数,饥荒联机版房间人数上限修改图文教程
  4. excel 删除空白列的三种方法,以及如何批量删除空行空列
  5. 【论文精读】Hybrid Bird‘s-Eye Edge Based Semantic Visual SLAM for Automated Valet Parking
  6. 计算机在幼儿园教育中的应用,浅谈计算机信息技术在幼儿园中的应用
  7. [算法练习]雨水收集问题
  8. arctime必须要java_下载Arctime字幕软件 | Arctime字幕软件
  9. es4----es6数组方法
  10. 五连珠c语言,c语言连珠五子棋(未完成)