1. 程式人生 > >我的CUDA學習之旅4——Sobel運算元影象邊緣檢測CUDA實現

我的CUDA學習之旅4——Sobel運算元影象邊緣檢測CUDA實現

引言

關於影象邊緣檢測,記得剛開始接觸影象處理時,第一個自己實現的程式是通過筆記本攝像頭採集影象,利用OpenCV自帶的演算法庫進行Canny運算元邊緣檢測,那時候當看到程式執行後,視訊視窗實時顯示經Canny運算元邊緣分割後的影象,覺得十分有科技感,後來慢慢開始自己寫邊緣檢測的原始碼,本部落格以Sobel運算元為例,將邊緣檢測通過CUDA實現。

任務要求

輸入一張圖片,將其轉為灰度圖後,通過CUDA在GPU中對圖片實現Sobel運算元邊緣檢測,最後將結果輸出至CPU並進行顯示,要求輸出圖與用CPU內實現後的結果一致。

實現思路

關於Sobel運算元的邊緣檢測原理,可看此部落格

Sobel邊緣檢測演算法
由於檢測的原理是通過對Gx和Gy兩個方向的卷積,故在CUDA實現時我們需要正確索引到以目標畫素點為中心的3*3的小方格中各個元素的位置,由於影象從CPU端傳給GPU是一段一維連續的記憶體,增大了我們索引的難度,故在block和grid的設計上,我把整張影象完整的對映到了grid中,每個thread即對應一個畫素,通過二維索引的方法將一維的記憶體準確對映。

實現環境

VS2013 + CUDA7.5 + Opencv2.4.13

實現程式碼

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda.h> #include <device_functions.h> #include <opencv2\opencv.hpp> #include <iostream> using namespace std; using namespace cv; //Sobel運算元邊緣檢測核函式 __global__ void sobelInCuda(unsigned char *dataIn, unsigned char *dataOut, int imgHeight, int imgWidth) { int xIndex = threadIdx.x + blockIdx.x * blockDim.x; int
yIndex = threadIdx.y + blockIdx.y * blockDim.y; int index = yIndex * imgWidth + xIndex; int Gx = 0; int Gy = 0; if (xIndex > 0 && xIndex < imgWidth - 1 && yIndex > 0 && yIndex < imgHeight - 1) { Gx = dataIn[(yIndex - 1) * imgWidth + xIndex + 1] + 2 * dataIn[yIndex * imgWidth + xIndex + 1] + dataIn[(yIndex + 1) * imgWidth + xIndex + 1] - (dataIn[(yIndex - 1) * imgWidth + xIndex - 1] + 2 * dataIn[yIndex * imgWidth + xIndex - 1] + dataIn[(yIndex + 1) * imgWidth + xIndex - 1]); Gy = dataIn[(yIndex - 1) * imgWidth + xIndex - 1] + 2 * dataIn[(yIndex - 1) * imgWidth + xIndex] + dataIn[(yIndex - 1) * imgWidth + xIndex + 1] - (dataIn[(yIndex + 1) * imgWidth + xIndex - 1] + 2 * dataIn[(yIndex + 1) * imgWidth + xIndex] + dataIn[(yIndex + 1) * imgWidth + xIndex + 1]); dataOut[index] = (abs(Gx) + abs(Gy)) / 2; } } //Sobel運算元邊緣檢測CPU函式 void sobel(Mat srcImg, Mat dstImg, int imgHeight, int imgWidth) { int Gx = 0; int Gy = 0; for (int i = 1; i < imgHeight - 1; i++) { uchar *dataUp = srcImg.ptr<uchar>(i - 1); uchar *data = srcImg.ptr<uchar>(i); uchar *dataDown = srcImg.ptr<uchar>(i + 1); uchar *out = dstImg.ptr<uchar>(i); for (int j = 1; j < imgWidth - 1; j++) { Gx = (dataUp[j + 1] + 2 * data[j + 1] + dataDown[j + 1]) - (dataUp[j - 1] + 2 * data[j - 1] + dataDown[j - 1]); Gy = (dataUp[j - 1] + 2 * dataUp[j] + dataUp[j + 1]) - (dataDown[j - 1] + 2 * dataDown[j] + dataDown[j + 1]); out[j] = (abs(Gx) + abs(Gy)) / 2; } } } int main() { Mat grayImg = imread("1.jpg", 0); int imgHeight = grayImg.rows; int imgWidth = grayImg.cols; Mat gaussImg; //高斯濾波 GaussianBlur(grayImg, gaussImg, Size(3, 3), 0, 0, BORDER_DEFAULT); //Sobel運算元CPU實現 Mat dst(imgHeight, imgWidth, CV_8UC1, Scalar(0)); sobel(gaussImg, dst, imgHeight, imgWidth); //CUDA實現後的傳回的影象 Mat dstImg(imgHeight, imgWidth, CV_8UC1, Scalar(0)); //建立GPU記憶體 unsigned char *d_in; unsigned char *d_out; cudaMalloc((void**)&d_in, imgHeight * imgWidth * sizeof(unsigned char)); cudaMalloc((void**)&d_out, imgHeight * imgWidth * sizeof(unsigned char)); //將高斯濾波後的影象從CPU傳入GPU cudaMemcpy(d_in, gaussImg.data, imgHeight * imgWidth * sizeof(unsigned char), cudaMemcpyHostToDevice); dim3 threadsPerBlock(32, 32); dim3 blocksPerGrid((imgWidth + threadsPerBlock.x - 1) / threadsPerBlock.x, (imgHeight + threadsPerBlock.y - 1) / threadsPerBlock.y); //呼叫核函式 sobelInCuda << <blocksPerGrid, threadsPerBlock >> >(d_in, d_out, imgHeight, imgWidth); //將影象傳回GPU cudaMemcpy(dstImg.data, d_out, imgHeight * imgWidth * sizeof(unsigned char), cudaMemcpyDeviceToHost); //釋放GPU記憶體 cudaFree(d_in); cudaFree(d_out); return 0; }

實現結果

原圖
原圖
CPU實現後圖像
CPU實現後圖像
CUDA實現後圖像
CUDA實現後圖像
通過比對發現CUDA輸出結果與CPU實現輸出結果一致~

相關推薦

CUDA學習4——Sobel運算元影象邊緣檢測CUDA實現

引言 關於影象邊緣檢測,記得剛開始接觸影象處理時,第一個自己實現的程式是通過筆記本攝像頭採集影象,利用OpenCV自帶的演算法庫進行Canny運算元邊緣檢測,那時候當看到程式執行後,視訊視窗實時顯示經Canny運算元邊緣分割後的影象,覺得十分有科技感,後來慢慢

CUDA學習1——大影象分塊處理程式(包括求均值,最大值等)

引言 在我的第一篇文章中我簡單介紹了CUDA以及我的一些個人學習見解,在本文中我將開始正式開始CUDA實踐之旅,眾做周知CUDA目前應用的領域十分廣泛,它能把一些普通的CPU程式碼提速幾十倍甚至幾百倍。在本人所從事的影象處理領域,在一些大影象的處理上(4K以上

java學習-4

個數 相同 參與 進制 amp 與運算 否則 來看 二進制位 位運算符在C裏面並沒有學到,所以算是新知識了,至於用途嘛,我還不太清楚,先來看看吧。 &: 參與運算的兩個數,若相應二進制位數的值都為1,則該結果值是1,否則是0,類似於“與”,例如: System.ou

Tensorflow學習(4)

import tensorflow as tf #定義新增神經層的函式def add_layer(),它有四個引數:輸入值、輸入的大小、輸出的大小和激勵函式 #我們設定預設的激勵函式是None fro

Html5學習(4)iframe

本來不是H5的東西.不過看到這個用法有點小激動.自己試試吧 <!DOCTYPE html> <html> <head> <meta charset="

學習啟程

  我是西安工業大學莘莘學子中最為普通的一名大二生,在這個需要發奮圖強的年紀,我已經沉淪了好久,沒有目標,沒有動力,只是一味地學習著學校要求的課程,只想著不要掛科。看著我身邊的同學越來越優秀,而我只是躲在自己的安樂窩裡,我的內心湧起了波瀾,要麼學好,要麼玩好,不能在虛度光陰了

的WCF(3):在WCF中實現雙工通訊

雙工(Duplex)模式的訊息交換方式體現在訊息交換過程中,參與的雙方均可以向對方傳送訊息。基於雙工MEP訊息交換可以看成是多個基本模式下(比如請求-回覆模式和單項模式)訊息交換的組合。雙工MEP又具有一些變體,比如典型的訂閱-釋出模式就可以看成是雙工模式的一種表現形式。雙工訊息交換模式使服務端回撥(Call

Netty學習----原始碼分析Netty記憶體洩漏檢測

1、圖說Netty直接記憶體管理 2、Netty 直接記憶體的使用示例 ByteBuf buf = Unpooled.directBuffer(512); System.out.println(buf); // Si

opencv學習--opencv內的6種影象邊緣檢測演算法的實現

     如上篇部落格所述,影象邊緣檢測演算法主要有Sobel, Scarry, Canny, Laplacian,Prewitt, Marr-Hildresh,現在進行總結     1.Sobel運算元 Sobel運算元是主要用於邊緣檢測的離散微分運算元,它

的Java開發學習------&gt;Workspace in use or cannot be created, choose a different one.--錯誤解決的方法

原因 tracking size ons create rac 分享 target mono 今天使用Eclipse時,突然卡死了。然後我強制關閉了Eclipse,再又一次打開的時候就報錯了,錯誤例如以下: Workspace in use or cann

的RabbitMQ學習3 (發布/訂閱)

fan 一點 簡單 圖片 數據 這一 auto sha 如果 在前面的教程中,我們創建了一個工作隊列。工作隊列背後的假設是,每個任務只被傳遞給一個工作人員。在這一部分,我們將做一些完全不同的事情 - 我們會向多個消費者傳遞信息。這種模式被稱為“發布/訂閱&rdq

的機器學習(四):回歸與工程應用

多個 算法 ati function RR numpy pen 圖片 bsp 內容:線性回歸;邏輯回歸,應用場景。 一、線性回歸 有監督學習,根據學習樣本{x->y},學習一個映射f:X->Y(線性相關),輸出預測結果y_i。最簡單的例子:y=ax+b 重要組成

的機器學習(六):決策樹

family 分配 根據 drop chrom labels arch ntp -o 決策樹概念: 分類決策樹模型是一種描述對實例進行分類的樹形結構。決策樹由結點和有向邊組成。結點有兩種類型:內部節點和葉節點,內部節點表示一個特征或屬性,葉節點表示一個類。 分類的時候,從根

的Android——學習、項目、心態

彌補 rdb HR 需求 學習資源 作品 思維 中國 網絡操作 學習Android也一年多了,項目做了五六個,有大有小,有難有易。一直以來都沒有好好總結過,今天周六休息,就寫下這一年多從事Android以來的一些感想和小經驗。涉及學習、項目和一些個人感受。 1.學習篇 我是

的Python學習(02)

我的Python學習之旅(02) 基本資料型別及變數的使用 list和tuple 條件判斷和迴圈 dict和set 好,接著上次的話題來說說Python的資料型別 首先,說個題外話,推薦學習python的大家去看看廖雪峰老師的部落格,講得

的Python學習(01)

我的Python學習之旅(01) 初識Python Hello World Python的輸入輸出 基本資料型別及變數的使用 list和tuple 條件判斷和迴圈 dict和set Python概要 Python

開發了5年android,開始了go學習

奧術大師 做了近5年的android開發,最近專案也是不怎麼忙,空閒的時候總會思考一些事情,不過作為移動開發,我個人覺得很有必要學習後臺開發,由於公司是Go語言開發的,瞭解go語言一段時間後,我發現go語言的強大。基於優雅的語法和其強大的併發性,我開啟我的go學習之旅。 golang強大的資料庫

的Web後端開發學習03

Python MTV(MVC) M: model 模型層 操作資料庫 T: template 模板層 顯示資料庫 V: view 控制層 接收使用者請求,響應請求 MTV步驟 開啟pycharm建立一個Django專案 ( 根據python版

記錄的Python學習(二)time庫的基本操作

1、time() 功能:獲取當前時間戳,即計算機內部時間值,浮點數  2、ctime() 功能:獲取當前時間並以易讀方式表示,返回字串 3、gmtime() 功能:獲取當前實踐,表示為計算機可處理的時間格式  4、時間格式化:如t=time.gmtime()  

記錄的Python學習(一)關於turtle庫的基本用法

關於庫函式的匯入方法:①import <> ②import <> as <> ③ from tutle import <>   1、turtle.setup(width,height,startx,starty)  /