使用OpenCL+OpenCV實現圖像旋轉(二)

4、host端程序代碼

Host端程序處理流程就是按照前面“程序設計”一節編寫的。除了調用OpenCL+OpenCV的API函數,其他的地方都是按照C/C++語法編寫的。

具體代碼如下:

1.	// ImageRotate.cpp : 定義控制檯應用程序的入口點。  
2.	//  
3.	  
4.	#include "stdafx.h"  
5.	#include <iostream>  
6.	#include <fstream>  
7.	#include <sstream>  
8.	  
9.	#include <opencv2/opencv.hpp>  
10.	  
11.	#ifdef __APPLE__  
12.	#include <OpenCL/cl.h>  
13.	#else  
14.	#include <CL/cl.h>  
15.	#endif  
16.	  
17.	using namespace cv;  
18.	  
19.	int _tmain(int argc, _TCHAR* argv[])  
20.	{  
21.	    cl_int ciErrNum;  
22.	    const char *fileName = "ImageRotate.cl";  
23.	    int width = 0, height = 0;  
24.	    float cos_theta = 0.7071067811865476, sin_theta = 0.7071067811865475;  //for degree 45  
25.	    //float cos_theta = 0.5, sin_theta = 0.5;  
26.	    const char* imageName = "F:\\code\\pic\\test01.jpg";  
27.	    char *bufInput = NULL, *bufOutput = NULL;  
28.	  
29.	  
30.	    //read one jpeg pic and store it in a Mat variable.  
31.	    Mat img = imread(imageName);  
32.	    if (!img.data) {  
33.	        std::cout << "fail to open the file:" << imageName << std::endl;  
34.	    }  
35.	  
36.	    //the type of img is RGB, convert to gray image.  
37.	    Mat imgGray;  
38.	    cvtColor(img, imgGray, CV_BGR2GRAY);  
39.	    width = imgGray.cols;  
40.	    height = imgGray.rows;  
41.	    std::cout << "picture width: " << width << ", height: " << height << std::endl;  
42.	      
43.	    //save the source data of original gray image.  
44.	    FILE *yuvFileOrg = NULL;  
45.	    fopen_s(&yuvFileOrg, "gray_org.yuv", "wb");  
46.	    fwrite(imgGray.data, width * height * sizeof(unsigned char), 1, yuvFileOrg);  
47.	    fclose(yuvFileOrg);  
48.	    yuvFileOrg = NULL;    
49.	  
50.	    //display the original gray image in a window.  
51.	    namedWindow( imageName, CV_WINDOW_AUTOSIZE );  
52.	    imshow(imageName, imgGray);  
53.	    //waitKey(0);  
54.	  
55.	    //allocate the input buffer to store the original gray image  
56.	    if (NULL == (bufInput = (char *)malloc(width * height * sizeof(char)))) {  
57.	        std::cerr << "Failed to malloc buffer for input image. " << std::endl;  
58.	        return NULL;  
59.	    }  
60.	  
61.	    //allocate the output buffer to store the image rotated.  
62.	    if (NULL == (bufOutput = (char *)malloc(width * height * sizeof(char)))) {  
63.	        std::cerr << "Failed to malloc buffer for output image. " << std::endl;  
64.	        return NULL;  
65.	    }  
66.	  
67.	    //copy the data of gray image to the input buffer. initialize the output buffer by zero.   
68.	    memcpy(bufInput, imgGray.data, width * height * sizeof(unsigned char));  
69.	    memset(bufOutput, 0, width * height * sizeof(unsigned char));  
70.	      
71.	    //use the first platform  
72.	    cl_platform_id platform;  
73.	    ciErrNum = clGetPlatformIDs(1, &platform, NULL);  
74.	  
75.	    //use the first device  
76.	    cl_device_id device;  
77.	    ciErrNum = clGetDeviceIDs(  
78.	        platform,  
79.	        CL_DEVICE_TYPE_ALL,  
80.	        1,  
81.	        &device,  
82.	        NULL);  
83.	  
84.	    cl_context_properties cps[3] = {  
85.	        CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0  
86.	    };  
87.	    //create the context  
88.	    cl_context ctx = clCreateContext(  
89.	        cps,  
90.	        1,  
91.	        &device,  
92.	        NULL,  
93.	        NULL,  
94.	        &ciErrNum);  
95.	  
96.	    //create the command queue  
97.	    cl_command_queue myqueue = clCreateCommandQueue(  
98.	        ctx,  
99.	        device,  
100.	        0,  
101.	        &ciErrNum);  
102.	          
103.	    //allocate space for original image on the device  
104.	    cl_mem bufferA = clCreateBuffer(  
105.	        ctx,  
106.	        CL_MEM_READ_ONLY,  
107.	        width * height * sizeof(unsigned char),  
108.	        NULL,  
109.	        &ciErrNum);  
110.	    //copy input buffer to the device  
111.	    ciErrNum = clEnqueueWriteBuffer(  
112.	        myqueue,  
113.	        bufferA,  
114.	        CL_TRUE,  
115.	        0,  
116.	        width * height * sizeof(unsigned char),  
117.	        (void *)bufInput,  
118.	        0,  
119.	        NULL,  
120.	        NULL);    
121.	  
122.	    //allocate space for rotated image on the device  
123.	    cl_mem bufferC = clCreateBuffer(  
124.	        ctx,  
125.	        CL_MEM_READ_WRITE,  
126.	        width * height * sizeof(unsigned char),  
127.	        NULL,  
128.	        &ciErrNum);  
129.	  
130.	    //open kernel file and read the content to a string variable.  
131.	    std::ifstream kernelFile("ImageRotate.cl", std::ios::in);  
132.	    if (!kernelFile.is_open()) {  
133.	        std::cerr << "Failed to open file for reading: " << fileName << std::endl;  
134.	        return NULL;  
135.	    }  
136.	    std::ostringstream oss;  
137.	    oss << kernelFile.rdbuf();  
138.	    std::string srcStdStr = oss.str();  
139.	    const char *srcStr = srcStdStr.c_str();  
140.	    kernelFile.close();  
141.	  
142.	    //create the program with source code of kernel.  
143.	    cl_program myprog = clCreateProgramWithSource(  
144.	        ctx,  
145.	        1,  
146.	        (const char**)&srcStr,  
147.	        NULL,  
148.	        &ciErrNum);  
149.	  
150.	    //compile the program. passing NULL for the 'device_list' argument targets all devices in the context  
151.	    ciErrNum = clBuildProgram(myprog, 0, NULL, NULL, NULL, NULL);  
152.	  
153.	    //create the kernel  
154.	    cl_kernel mykernel = clCreateKernel(  
155.	        myprog,  
156.	        "img_rotate",  
157.	        &ciErrNum);  
158.	  
159.	    //set the kernel arguments  
160.	    clSetKernelArg(mykernel, 0, sizeof(cl_mem), (void *)&bufferC);  
161.	    clSetKernelArg(mykernel, 1, sizeof(cl_mem), (void *)&bufferA);  
162.	    clSetKernelArg(mykernel, 2, sizeof(cl_int), (void *)&width);  
163.	    clSetKernelArg(mykernel, 3, sizeof(cl_int), (void *)&height);  
164.	    clSetKernelArg(mykernel, 4, sizeof(cl_float), (void *)&cos_theta);  
165.	    clSetKernelArg(mykernel, 5, sizeof(cl_float), (void *)&sin_theta);  
166.	  
167.	    //set local and global workgroup sizes  
168.	    size_t localws[2] = {1, 1};  
169.	    size_t globalws[2] = {width, height};  
170.	  
171.	    //execute the kernel  
172.	    ciErrNum = clEnqueueNDRangeKernel(  
173.	        myqueue,  
174.	        mykernel,  
175.	        2,  
176.	        NULL,  
177.	        globalws,  
178.	        localws,  
179.	        0,  
180.	        NULL,  
181.	        NULL);  
182.	  
183.	    //read the output data back to the host  
184.	    ciErrNum = clEnqueueReadBuffer(  
185.	        myqueue,  
186.	        bufferC,  
187.	        CL_TRUE,  
188.	        0,  
189.	        width * height * sizeof(unsigned char),  
190.	        bufOutput,  
191.	        0,  
192.	        NULL,  
193.	        NULL);  
194.	  
195.	    //copy the output data from output buffer to Mat variable.   
196.	    memcpy(imgGray.data, bufOutput, width * height * sizeof(unsigned char));  
197.	  
198.	    //save the source data for gray image rotated  
199.	    FILE *yuvFile = NULL;  
200.	    fopen_s(&yuvFile, "gray.yuv", "wb");  
201.	    fwrite(imgGray.data, width * height * sizeof(unsigned char), 1, yuvFile);  
202.	    fclose(yuvFile);  
203.	    yuvFile = NULL;  
204.	  
205.	    //save the gray image rotated.  
206.	    imwrite("test_gray.jpg", imgGray);  
207.	  
208.	    //show the gray image rotated.  
209.	    const char *winName = "gray_image_rotated";  
210.	    namedWindow(winName, CV_WINDOW_AUTOSIZE );  
211.	    imshow(winName, imgGray);     
212.	    waitKey(0);  
213.	    destroyAllWindows();  
214.	  
215.	    //release all resource  
216.	    if (bufInput != NULL)  
217.	        free(bufInput);  
218.	  
219.	    if (bufOutput != NULL)  
220.	        free(bufOutput);  
221.	  
222.	    if (bufferA != 0)  
223.	        clReleaseMemObject(bufferA);  
224.	  
225.	    if (bufferC != 0)  
226.	        clReleaseMemObject(bufferC);  
227.	  
228.	    if (myqueue != 0)  
229.	        clReleaseCommandQueue(myqueue);  
230.	  
231.	    if (mykernel != 0)  
232.	        clReleaseKernel(mykernel);  
233.	  
234.	    if (myprog != 0)  
235.	        clReleaseProgram(myprog);  
236.	  
237.	    if (ctx != 0)  
238.	        clReleaseContext(ctx);  
239.	  
240.	    return 0;  
241.	}  

5、程序處理結果

原始的灰度圖像如下所示:


經過45度旋轉的圖像如下:


將sin、cos值都設置爲0.5時的處理結果如下:

經過45度旋轉的圖像上面有很多暗點,那些暗點是在設備端分配的buffer中原始的點。意味着那些區域並非每個點都有對應的點旋轉過來。

在kernel程序中計算座標點時,使用的是float類型,最後獲取圖像時是將float轉換爲int了。應該是因爲精度損失導致某些座標點上沒有對應的像素點,所以保留了buffer中原有的數據。

而當sin、cos設置爲0.5時,圖像看着就沒有暗紋。按照0.5計算很少有精度的損失,所以就不存在上面的問題。

是因爲旋轉算法精度不夠,還是程序哪裏實現錯了,這是個問題,將在後面的學習中去尋找問題的答案。

(完)
發佈了58 篇原創文章 · 獲贊 156 · 訪問量 70萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章