No.6_1 OpenCL 圖像採樣器——圖像裁剪

簡介

在 OpenCL 1.1 中,已經支持對圖像的讀寫。本文描述如何通過 OpenCL API 調用,從一張較大的圖像中截取一塊矩形區域,供圖片瀏覽器顯示。該程序實現的功能和 No.1_YUV420pScissor 類似,不同的是 No.1_YUV420pScissor 中直接對像素數據進行處理,而該程序中通過 OpenCL 內置圖像讀寫函數來對像素數據進行採樣。

實現

該程序接收 No.2_2_FreeImage 中由函數 load_image 保存的二進制圖像數據,然後通過 OpenCL 來提取其中的部分矩形區域,將該矩形區域保存爲二進制圖像文件。最後將提取的矩形區域像素使用 No.2_2_FreeImage 中 store_image 函數保存爲位圖文件,供圖片瀏覽器查看。具體執行流程可參考 No.2_2_FreeImage。

由於截取的矩形區域圖像爲 256x256,在保存位圖文件時需要更新圖像格式和尺寸,需要對程序 No.2_2_FreeImage 中對應參數作相關調整,打上如下 patch,內容如下:

+FREE_IMAGE_FORMAT g_format = (FREE_IMAGE_FORMAT)13;
+int g_width = 256, g_height = 256;

完整代碼參見 No.1_OpenCLSampler

1.創建圖像對象

緩衝區對象和圖像對象都是內存對象,內存對象是對全局內存區域的引用。不同的是圖像對象除了像素數據,還包含了對圖像格式及圖像屬性的描述信息,例如圖像寬度、高度,以及深度等。

創建了兩個圖像對象,分別用來存放原始圖像數據和目標圖像數據。圖像對象和緩衝區對象類似,都是 cl_mem 類型。

cl_image_format image_format;
cl_mem in_buffer, out_buffer;

memset((void *)&image_format, 0, sizeof(cl_image_format));
image_format.image_channel_order = CL_RGBA;
image_format.image_channel_data_type = CL_UNORM_INT8;

in_buffer = clCreateImage2D(context,
                CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, &image_format,
                orig_width, orig_height, 0, src, &err);

out_buffer = clCreateImage2D(context, CL_MEM_WRITE_ONLY, &image_format,
                new_width, new_height, 0, NULL, &err);

其中 cl_image_format 用來定義圖像的格式,成員如下:

  • image_channel_order:指定每個像素的通道數目和通道佈局;
  • image_channel_data_type:描述每個通道的大小,表示的數據類型。

該程序在華爲榮耀8上運行。由於榮耀8只支持 OpenCL 1.1,該版本創建圖像對象對應的函數是 clCreateImage2D,如本文所示。在 OpenCL 1.2 中將函數 clCreateImage2D 和 clCreateImage3D 合併到了 clCreateImage,同時增加了 cl_image_desc 參數,用來描述圖像的屬性,包含圖像類型、寬度、高度和深度等信息。

2.圖像讀寫

圖像讀寫操作通過 OpenCL 內置的圖像讀寫函數 read_imageXwrite_imageX 來執行,圖像讀寫函數只能作用於圖像對象。在主機端,圖像對象使用 clSetKernelArg 傳遞給內核程序。內核代碼如下:

__constant  sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |
    CLK_FILTER_NEAREST | CLK_ADDRESS_CLAMP;

__kernel void rotate_rgba(__read_only image2d_t srcImg,
    __write_only image2d_t dstImg)
{
    const int x = get_global_id(0);
    const int y = get_global_id(1);

    // 根據旋轉後坐標讀取元素圖像元素值
    float4 value = read_imagef(srcImg, sampler, (int2)(x, y));
    write_imagef(dstImg, (int2)(x, y), value);
}

2.1採樣器

採樣器對象描述了讀取圖像數據時如何對圖像進行採樣。圖像讀取函數 read_imageX 包含一個採樣器參數,該參數可以在主機端通過調用 OpenCL API 函數創建,然後使用 clSetKernelArg 傳遞給內核;也可以在內核程序中聲明,在內核程序中聲明的採樣器對象爲 sampler_t 類型的常量。採樣器對象包含了一些屬性,這些屬性描述了在讀取圖像對象的像素時如何採樣。分別是規格化浮點座標,尋址模式和過濾模式。

  • 規格化座標:指定傳遞的 x、y 和 z 座標值是規格化浮點座標還是非規格化座標值。可以是 CLK_NORMALIZED_COORDS_TRUE 或者 CLK_NORMALIZED_COORDS_FALSE 枚舉類型的值;
  • 尋址模式:指定圖像的尋址模式。即,當傳遞的座標值超過圖像座標區域時該如何處理。可以是下面的枚舉類型的值:
    CLK_ADDRESS_MIRRORED_REPEAT:圖像區域外的座標設置爲區域內座標的反射值對應的顏色;
    CLK_ADDRESS_REPEAT:圖像區域外的座標重複區域內座標的顏色,只對規格化座標有效;
    CLK_ADDRESS_CLAMP_TO_EDGE:圖像區域外的座標返回圖像邊緣的顏色;
    CLK_ADDRESS_CLAMP:圖像區域外座標返回的顏色和邊框顏色保持一致;
  • 過濾模式:指定使用的過濾模式。可以是 CLK_FILTER_NEARESTCLK_FILTER_LINEAR 枚舉類型值,分別表示最近鄰插值和雙線性插值。
邊框的顏色

當採樣器的尋址模式設置爲 CLK_ADDRESS_CLAMP 時,超過圖像區域的座標返回邊框的顏色。邊框顏色的選擇依賴圖像顏色通道,如下:

  • 如果圖像顏色通道是 CL_A,CL_INTENSITY,CL_Rx,CL_RA,CL_RGx,CL_RGBx,CL_ARGB,CL_BGRA 或 CL_RGBA,邊框顏色爲 (0.0f,0.0f, 0.0f,0.0f);
  • 如果圖像顏色的通道是 CL_R,CL_RG,CL_RGB 或 CL_LUMINANCE,邊框顏色爲(0.0f,0.0f,0.0f,1.0f)。

CL_RGBA 的顏色通道中,如果是全 0 則表示黑色,全 0xFF 表示白色。Alpha 通道如果是 1,則不透明,如果是 0 則全透明。

2.2座標

在圖像讀寫函數 read_imageXwrite_imageX 中,對於 2D 圖像對象,傳遞的 x 座標範圍是 [0, width-1],y 座標範圍是 [0, height-1],座標原點 [0, 0] 對應圖像的左下角。

2.3讀寫操作

對於不同的圖像對象,函數 read_imageX 返回由四個通道組成的顏色值,使用 x、 y、 z 和 w 來表示。x 表示紅色,y 表示綠色,z 表示藍色,w 表示 alpha 通道。函數 write_imageX 將四個通道表示的顏色值寫入圖像對象指定的座標位置。圖像數據類型 image2d_t,表示 2D 圖像,需要使用如下的限定符來修飾:

  • 對於內核執行操作的圖像對象,在聲明的時候需要使用 __read_only 限定符修飾;
  • 對於內核執行操作的圖像對象,在聲明的時候需要使用 __write_only 限定符修飾;
  • 同一個圖像對象不能同時支持讀寫操作,限定符使用不當將引發編譯錯誤。

3.讀取圖像數據

把命令添加到命令隊列中,將圖像對象指定區域的數據讀取到主機內存,以供圖片瀏覽器查看。該區域是一個矩形區域。

size_t origin[3] = {0 , 0, 0};
size_t region[3] = {new_width, new_height, 1};
err = clEnqueueReadImage(queue, out_buffer, CL_TRUE, origin, region, 0,
        0, des, 0, NULL, NULL);

部分參數說明如下:

  • origin:圖像中的偏移(x,y,z),以像素爲單位的。如果 image 是 2D 圖像對象,origin[2] 必須爲 0;
  • region:定義 1D,2D 或 3D 圖像的矩形區域,屬性爲(width,height,depth)。如果 image 是 2D 圖像對象, region[2] 必須是 1。

結果

該程序運行後,經過 No.2_2_FreeImage 處理顯示效果如下圖所示。

原始圖像

目標圖像

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章