日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

计算机视觉-图像缩放算法-cuda实现

發布時間:2024/3/24 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 计算机视觉-图像缩放算法-cuda实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一.CUDA

CUDA是顯卡廠商NVIDIA(英偉達)推出的運算平臺,能夠將數據數據復制到GPU,在GPU中進行計算,然后再返回給CPU端。CUDA將GPU稱為設備側或者Device,將CPU稱為Host側,按照下圖進行劃分,真正進行計算的是其中的Thread。

CUDA的極簡使用流程
1.寫核函數,是指在Device上運行的函數,用__global__ 標識。
2.在Device上申請空間,使用CUDA自帶的cudaMalloc函數。
3.把要進行計算的數據拷貝到Device,也就是上一步申請到的空間。使用cudaMemcpy函數。
4.在Host中調用核函數,使用Device進行計算。
5.將計算的結果從Device拷貝回Host。

二.圖像縮放算法

圖像縮放這個事,所有操作圖片的人都做過,但是程序是如何計算的?
首先,確定縮放目標圖的大小,創建一張空白的目標圖。
然后,從原圖中為目標圖的每一個像素點找到對應的值。
成熟的縮放算法有很多,在這里只介紹其中最簡單的兩個。
最近鄰點插值法雙線性插值法

三.最近鄰點插值法

1.算法

1.針對目標圖中每一個像素點,按照縮放比例去原圖中找對應的點,比值不為整數的就選目標圖中最近的點。
2.給目標圖取對應的值。

源圖像與目標圖像寬的比例為:

srcWidth / dstWidth

源圖像與目標圖像高的比例為:

srcHeight / dstHeight

由目標圖坐標找原圖像坐標就是:

srcX = dstX * (srcWidth / dstWidth)
srcY = dstY * (srcHeight / dstHeight)

2.代碼

代碼使用的是C++、CUDA

//文件名是test1.cu #include<opencv2/opencv.hpp> #include<iostream> #include <string> #include <stdio.h> #include<vector> using namespace cv; using namespace std;__global__ void resize1GPU(const unsigned char* src, int srcWidth, int srcHeight, unsigned char* dst, int dstWidth, int dstHeight) {//核函數會在每個thread上運行,這里求的x、y是當前thread的坐標,同時也代表當前要處理的像素的坐標int y = blockIdx.y * blockDim.y + threadIdx.y;int x = blockIdx.x * blockDim.x + threadIdx.x; if (x >= dstWidth || y >= dstHeight) return;//以指針的形式操作圖像,outPosition是指目標圖像素在內存中的位置 int outPosition = y * dstWidth + x; //求取對應原圖的像素點,srcPosition是指原圖像素在內存中的位置 int srcX = x * srcWidth / dstWidth; //如果出現浮點數,這里就會向下取整,以此來表示最近鄰int srcY = y * srcHeight / dstHeight; //(如果不喜歡向下取整,也可以選擇四舍五入)int srcPosition = srcY * srcWidth + srcX; //為目標圖像素賦值。RGB三通道,在內存中的位置是挨著的。dst[outPosition * 3 + 0] = src[srcPosition * 3 + 0]; dst[outPosition * 3 + 1] = src[srcPosition * 3 + 1];dst[outPosition * 3 + 2] = src[srcPosition * 3 + 2]; }int main() {Mat src = imread("1.jpg"); //使用opencvint srcWidth = src.cols;int srcHeight = src.rows;int dstWidth = 256; //目標圖的大小int dstHeight = 256;unsigned char* devSrc;unsigned char* devDst;//在GPU上為兩張圖申請存儲空間cudaMalloc((void**)&devSrc, srcWidth * srcHeight * 3 * sizeof(unsigned char)); cudaMalloc((void**)&devDst, dstWidth * dstHeight * 3 * sizeof(unsigned char));//把原圖復制到GPU上,注意圖片數據格式的變化cudaMemcpy(devSrc, (unsigned char*)(src.data), srcWidth * srcHeight * 3 * sizeof(unsigned char), cudaMemcpyHostToDevice);dim3 blocks((dstWidth + 15) / 16, (dstHeight + 15) / 16);dim3 threads(16, 16);//調用核函數,重點關注blocks與threads的設置,這樣設置是為了讓thread的坐標代表目標圖像素的坐標resize1GPU <<<blocks, threads>>> (devSrc, srcWidth, srcHeight, devDst, dstWidth, dstHeight);//將處理完的目標圖拷貝回來Mat dst(Size(dstWidth, dstHeight), CV_8UC3);cudaMemcpy(dst.data, devDst, dstWidth * dstHeight * 3 * sizeof(unsigned char), cudaMemcpyDeviceToHost);//使用opencv保存新圖片vector<int> comprocession_params;comprocession_params.push_back(IMWRITE_PNG_COMPRESSION);comprocession_params.push_back(9);imwrite("nearest_neighbor.png", dst,comprocession_params);cudaFree(devSrc);cudaFree(devDst);return 0; }

四.雙線性插值法

1.算法

雙線性插值的像素對應公式也是根據縮放比例
不一樣的是,不再是找原圖的1個點,而是找到原圖的4個點,然后再求出目標圖的像素值。
先思考這樣一個問題:如下圖,已知下圖中所有點的坐標,并且已知Q12,Q22,Q11,Q21四點的值,假設所有點的值符合線性變化,那么如何求P點的值。


由線性假設有以下等式:

(R1-Q11) / (Q21-Q11) = (x-x1) / (x2-x1)
(R2-Q12) / (Q22-Q12) = (x-x1) / (x2-x1)
(R2-P) / (R2-R1) = (y2-y) / (y2-y1)

先由前兩個等式求出R1,R2,做了一次線性插值
再由R1,R2求出P,又做了一次線性插值,這也是算法名字的由來。

最后求得
把這個求值算法轉移到圖像中,將坐標變成離散的情況。Q的四個點的坐標之間相差1,故進一步化簡為:

P=(Q11)(x2- x)(y2-y) + (Q21)(x- x1)(y2- y) + (Q12)(x2- x)(- y1) +
(Q22)(x - x1)(y- y1)

1.由目標圖中的像素,算出原圖中的坐標(浮點數),一定能找到距離這個坐標最近的四個像素點。
2.用雙線性插值計算出這點的值。

2.代碼

//文件名是test2.cu #include<opencv2/opencv.hpp> #include<iostream> #include <string> #include <stdio.h> #include<vector> using namespace cv; using namespace std;__global__ void resize2GPU(const unsigned char* src, int srcWidth, int srcHeight, unsigned char* dst, int dstWidth, int dstHeight) {int y = blockIdx.y * blockDim.y + threadIdx.y;int x = blockIdx.x * blockDim.x + threadIdx.x;if (x >= dstWidth || y >= dstHeight) return;int dstOffset = y * dstWidth + x; //目標圖像素在內存中的位置 //根據縮放比例,計算在原圖的坐標(浮點值)int srcXf = x * ((float)srcWidth / dstWidth);int srcYf = y * ((float)srcHeight / dstHeight);//向下取整,得到四個像素中,左上的像素坐標int srcX = (int)srcXf;int srcY = (int)srcYf; //u就是上面算法中的x-x1,1-u就是x2-xint u = srcXf - srcX; int v = srcYf - srcY;//P=(Q11)(x2- x)(y2-y) + (Q21)(x- x1)(y2- y) + (Q12)(x2- x)(- y1) + (Q22)(x - x1)(y- y1)dst[dstOffset] = 0;dst[dstOffset] += (1 - u) * (1 - v) * src[(srcY * srcWidth + srcX)]; dst[dstOffset] += (1 - u) * v * src[((srcY + 1) * srcWidth + srcX)];dst[dstOffset] += u * (1 - v) * src[(srcY * srcWidth + srcX + 1)];dst[dstOffset] += u * v * src[((srcY + 1) * srcWidth + srcX + 1)]; //(srcY+1)*srcWidth+srcX+1)是右下角的像素點在內存中的位置 } //主函數和上一個算法代碼一樣,唯一區別就是,為了代碼簡單,把圖片變成了灰度圖 int main() {Mat src = imread("1.jpg", 0);int srcWidth = src.cols;int srcHeight = src.rows;int dstWidth = 512;int dstHeight = 512;unsigned char* devSrc;unsigned char* devDst;cudaMalloc((void**)&devSrc, srcWidth * srcHeight * sizeof(unsigned char));cudaMalloc((void**)&devDst, dstWidth * dstHeight * sizeof(unsigned char));cudaMemcpy(devSrc, src.data, srcWidth * srcHeight * sizeof(unsigned char), cudaMemcpyHostToDevice);dim3 blocks((dstWidth + 15) / 16, (dstHeight + 15) / 16);dim3 threads(16, 16);resize2GPU << <blocks, threads >> > (devSrc, srcWidth, srcHeight, devDst, dstWidth, dstHeight);Mat dst(Size(dstWidth, dstHeight), CV_8UC1);cudaMemcpy(dst.data, devDst, dstWidth * dstHeight * sizeof(unsigned char), cudaMemcpyDeviceToHost);vector<int> comprocession_params;comprocession_params.push_back(IMWRITE_PNG_COMPRESSION);comprocession_params.push_back(9);imwrite("Bilinear_Interpolation.png", dst,comprocession_params);cudaFree(devSrc);cudaFree(devDst);return 0; }

3.遺留問題

1.當出現坐標在邊界時,會出現(i+1,j)、(i,j+1)、(i+1,j+1)的點在實際的圖中不存在?此時可以用(i,j)、(i-1,j)、(i,j-1)、(i-1,j-1)。
2.當按縮放比計算坐標后,與原圖像中的點發生重合,怎么選取剩下3個點?無論我們怎么選取,其實其余3點的權重都是0,所以都不影響。
3.目標圖像的原點(0, 0)點和原始圖像的原點肯定是重合的,但是目標圖的中心點不一定與原圖的中心點重合。整體圖像會發生偏移。把浮點坐標的計算方法改為:

4.我的電腦沒有英偉達顯卡,租了一個云計算平臺來運行.cu格式的代碼。
使用以下兩個命令行
編譯:nvcc test1.cu pkg-config opencv --libs --cflags opencv -o test1
運行:./test1

CUDA-圖像縮放

總結

以上是生活随笔為你收集整理的计算机视觉-图像缩放算法-cuda实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。