DriveWorks SDK Reference
3.0.4260 Release
For Test and Development only

image/docs/mainsection.md
Go to the documentation of this file.
1 # Copyright (c) 2019-2020 NVIDIA CORPORATION. All rights reserved.
2 
3 @page image_mainsection Image
4 @tableofcontents
5 
6 @note SW Release Applicability: This module is available in both **NVIDIA DriveWorks** and **NVIDIA DRIVE Software** releases.
7 
8 @section image_about About This Module
9 The image module is composed of 3 submodules
10 
11 @section image_intro Image
12 
13 The image module contains structures and methods that allow the user to create and set images handles that are compatible with NVIDIA<sup>&reg;</sup> DriveWorks modules. An image is represented generically as a handle `::dwImageHandle_t`, which can be passed to a DriveWorks module for processing,
14 or more specifically as a C struct. The struct differs in content based on the type of image and the properties. All images share common properties:
15 
16 #### Image Properties
17 The image properties are:
18 - the type (see next section)
19 - the size in pixel (width and height):
20 - the format represented as an enum DW_IMAGE_FORMAT_COLORSPACE_PIXELTYPE(_PIXELORDER) where the COLORSPACE (RGB, YUV, RAW etc...) describes the appearance of the individual pixel, the PIXELTYPE (UINT8, FLOAT16 etc...) describes the trivial datatype of each pixel and the PIXELORDER (PLANAR, SEMIPLANAR) which describes how the specific color space is arranged in memory. The PIXELORDER can be INTERLEAVED (name is omitted) in which case the individual channels of the COLORSPACE are contiguous, PLANAR in which the channels are separated in different planes or SEMIPLANAR in which some channels are contiguous, some not (see YUV420)
21 - the meta which is the collection of metadata information and pointers to datalines. This field is filled by the dwSensorCamera and contains parsed datalines (in the form of sensor specific info) and uint8_t pointers pointing to the memory location of the raw datalines. This is supported not supported in GL images and it will appear only when dealing with RAW images
22 - the memoryLayout can be: `::DW_IMAGE_MEMORY_TYPE_DEFAULT`, `::DW_IMAGE_MEMORY_TYPE_PITCH`, `::DW_IMAGE_MEMORY_TYPE_BLOCK` and represents the arrangement of data in memory. Only CUDA and NVMEDIA can handle both types, CPU is stricktly pitch and GL is stricktly block, The default memory layout will automatically choose the proper layout (once given to a DW module)
23 
24 #### Image Types
25 
26 Any image can be created by calling `dwImage_create()` and should be followed by a `dwImage_destroy()` when the image is not needed anymore. The creation is specific to the type of image and there are 4 supported types. After the image is created it is possible to pass the handle to DriveWorks modules, if they accept the opaque handle, otherwise it's possible to retrieve a struct specific to the image type. The struct allows direct access to the content of the image and any modification will affect original image.
27 
28 ##### CPU Images
29 
30 A CPU image is stored as a pitch memory buffer represented by an array of pointers, an array of pitches and properties. Its content can be retrieved from a dwImageHandle_t by calling dwImage_getCPU() and it will return a dwImageCPU and it contains:
31 - dwImageProperties prop: image properties
32 - size_t pitch[] : the pitches, one per image plane
33 - uint8_t *data[]: the pointers to the actual data, one pointer per image plane
34 - `::dwTime_t` timestamp_us : the timestamp of acquisition from a sensor. If the image is created by the user, it is 0
35 
36 The CPU image is created by specifying ::DW_IMAGE_CPU type in the properties and calling
37 - dwImage_create(): will create the handle and also allocate memory for data[] based on the properties. Destroying such image will also free the memory
38 - dwImage_createAndBindBuffer(): will create the handle but not allocate memory, instead data[] will point to the buffers allocated and passed by the user. The function trusts that the user buffers match the properties specified. Destroying such image will only destroy the handle, the ownership of the buffer remains on the user
39 
40 ##### CUDA Images
41 
42 A CUDA Image can have 2 forms, a Pitch pointer or CUDA Array form. The two forms are allocated and occupy different domains on GPU memory, one being a Pitch linear pointer, the other being a Block memory cuda Array (thought of as a Texture). It is possible to retrieve the content by calling dwImage_getCUDA() and receiving a dwImageCUDA struct, containing:
43 - dwImageProperties prop: image properties
44 - size_t pitch[] : the pitches, one per image plane. The pitches are used to access content only for pitch linear pointers
45 - void *dptr[]: the pointers to the actual pitch linear data on GPU device, one per image plane. Valid if prop.memoryLayout is ::DW_IMAGE_MEMORY_TYPE_PITCH (or DEFAULT)
46 - cudaArray_t array[]: the block memory cuda arrays, one per image plane. Valid if prop.memoryLayout is ::DW_IMAGE_MEMORY_TYPE_BLOCK
47 - `::dwTime_t` timestamp_us : the timestamp of acquisition from a sensor. If the image is created by the user, it is 0
48 
49 The CUDA image is created by specifying DW_IMAGE_CUDA type in the properties and calling
50 - dwImage_create(): will create the handle and also allocate memory for dptr[] for pitch layouts and for arrays[] for block layouts, based on properties. Destroying such image will also free the device memory
51 - dwImage_createAndBindBuffer(): will create the handle but not allocate memory, instead dptr[] will point to the buffers allocated using cuda functions (ie cudaMallocPitch()) and passed by the user. The function trusts that the user buffers match the properties specified. Destroying such image will only destroy the handle, the ownership of the buffer remains on the user
52 - dwImage_createAndBindCUDAArray(): will create the handle but not allocate cudaArrays, instead array[] will point to the cudaArray allocated by the user calling cudaMallocArray(). The behavior is analogous to the function above
53 
54 ##### GL Images
55 
56 A GL image is stored as a GLuint texture present on the GPU. An invalid texture has texID of 0 but it has a positive value when properly created. It is possible to retrieve the ocntent by calling dwImage_getGL() and will receive a dwImageGL and it contains:
57 - dwImageProperties prop: image properties
58 - GLuint tex: the index of the texture on the GPU
59 - GLenum target: the GL texture target. In almost all use cases it is a GL_TEXTURE_2D
60 - `::dwTime_t` timestamp_us : the timestamp of acquisition from a sensor. If the image is created by the user, it is 0
61 
62 The GL image is created by specifying DW_IMAGE_GL type in the properties and calling
63 - dwImage_create(): will create the handle and also generate a GL texture, based on properties and target. Destroying such image will also destroys the GL texture
64 - dwImage_createAndBindGLTexture(): will create the handle and use the GL texture created by the user. The function trusts that the user buffers match the properties specified. Destroying such image will only destroy the handle, the ownership of the texture remains on the user
65 
66 ##### NvMedia Images
67 
68 An NvMedia image is stored as a pointer to the low level NvMedia API image struct.
69 For specific information on NvMedia images, see the following information in _NVIDIA DRIVE 5.1 PDK_:
70 - "Image Processing and Management" in "Understanding NvMedia".
71 - "NvMedia API for Tegra" in the API Reference. (Click the API tab to access the API Reference.)
72 
73 It is possible to access the pointer by calling dwImage_getNvMedia() and receive a dwImageNvMedia that contains:
74 - dwImageProperties prop: image properties
75 - NvMediaImage *img: pointer to the low level NvMedia image
76 - `::dwTime_t` timestamp_us : the timestamp of acquisition from a sensor. If the image is created by the user, it is 0
77 
78 The NvMedia image is created by specifying ::DW_IMAGE_NVMEDIA type in the properties and calling
79 - dwImage_create(): will create the handle and also create a NvMediaImage using low level NvMedia API calls, based on properties. Destroying such image will also destroys the NvMediaImage using the low level NvMedia API
80 - dwImage_createAndBindNvMedia(): will create the handle and use NvMediaImage created by the user. The function trusts that the user NvMediaImage matches the properties specified. Destroying such image will only destroy the handle, the ownership of the NvMediaImage remains on the user
81 
82 @section image_storage Storage in Memory
83 
84 Images can be stored in memory in various formats. One dimension of this variation is interleaved vs planar storage for multi-channel images. For example, an interleaved RGB image has 1 plane with 3 channels. A YUV420 planar image has 3 planes, with 1 channel each.
85 
86 Memory layout can be either pitch or block, depending on the type. CPU images are always pitch, GL images are always block, whereas CUDA and NvMedia images can be either.
87 
88 @section image_formats ImageFormats
89 The image format describes data type, color space and arrangement of the pixels
90 
91 #### Interleaved formats
92 - DW_IMAGE_FORMAT_R: single channel grayScale
93 - DW_IMAGE_FORMAT_RG: two-channels single plane (RGRGRGRG...) representing Red Green (or X Y coordinates)
94 - DW_IMAGE_FORMAT_RGB: 3-channels single planae (RGBRGBRGBRGB)
95 - DW_IMAGE_FORMAT_RGBA: 4-channels single plane (RGBARGBARGBA), Red Green Blue Alpha. Alpha channel used for color blending
96 - DW_IMAGE_FORMAT_RGBX: 4-channels single plane (RGBXRGBXRGBX), Red Green Blue X-empty, for HW acceleration
97 - DW_IMAGE_FORMAT_VUYX: 4-channles single plane (VUYXVUYXVUYX), V U Y-luminace X-empty, representing YUV444
98 
99 #### Planar formats
100 - DW_IMAGE_FORMAT_RGB_DATATYPE_PLANAR: 3 planes, 1 channel each, Red Green Blue
101 - DW_IMAGE_FORMAT_RCB_DATATYPE_PLANAR: 3 planes, 1 channel each, Red Clear Blue, Clear represents unfiltered color channel, non tonemapped
102 - DW_IMAGE_FORMAT_RCC_DATATYPE_PLANAR: 3 planes, 1 channel each, Red Clear Clear, Clear represents unfiltered color channel, non tonemapped
103 - DW_IMAGE_FORMAT_YUV420_DATATYPE_PLANAR: 3 planes, 1 channel each, Y-luminance U V, representing YUV420 with U and V at half resolution
104 - DW_IMAGE_FORMAT_YUV_DATATYPE_PLANAR: 3 planes, 1 channel each, Y-luminance U V, representing YUV444
105 
106 #### other formats
107 - DW_IMAGE_FORMAT_YUV420_DATATYPE_SEMIPLANAR: 2 planes, 1 channel + 2 channels (YYYYYYY... UVUVUVUVUV), representing YUV420 with U and V at half resolution
108 
109 #### RAW
110 - DW_IMAGE_FORMAT_RAW_UINT16: RAW color array from images arriving from the sensor. The color array is describet in dwCameraRawFormat
111 - DW_IMAGE_FORMAT_RAW_FLOAT16: result of debayering of RAW_UINT16
112 
113 @section image_format_conversion Image Format Conversion
114 
115 Images can be converted into a different format, while retaining the same type (for converting type, see Image Streamer). The user must allocate the output image and the conversion will be based on the properties of the input and output images. Only CUDA and NvMedia images support this operation. The converter will not change the size of the image. If all properties are identical, the converter will perform an identical copy.
116 
117 #### Table for supported format conversions
118 
119 | From | To |
120 |-----------|-----------|
121 | any format and layout | same format and layout (simple copy) |
122 | any format, layout `::DW_IMAGE_MEMORY_TYPE_PITCH` | same format, layout `::DW_IMAGE_MEMORY_TYPE_BLOCK` |
123 | any format, layout `::DW_IMAGE_MEMORY_TYPE_BLOCK` | same format, layout `::DW_IMAGE_MEMORY_TYPE_PITCH` |
124 | `::DW_IMAGE_FORMAT_RGB_UINT8` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
125 | `::DW_IMAGE_FORMAT_RGB_UINT8` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
126 | `::DW_IMAGE_FORMAT_RGB_UINT8` | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` |
127 | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
128 | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
129 | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGB_FLOAT16` |
130 | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` |
131 | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` |
132 | `::DW_IMAGE_FORMAT_RGBA_UINT8` | `::DW_IMAGE_FORMAT_RGB_UINT8` |
133 | `::DW_IMAGE_FORMAT_RGBA_UINT8` | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` |
134 | `::DW_IMAGE_FORMAT_RGBA_UINT8` | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` |
135 | `::DW_IMAGE_FORMAT_RGBA_UINT8` | `::DW_IMAGE_FORMAT_R_UINT8` |
136 | `::DW_IMAGE_FORMAT_RGBA_UINT8` | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` |
137 | `::DW_IMAGE_FORMAT_RGBA_UINT8` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
138 | `::DW_IMAGE_FORMAT_RGBA_FLOAT16` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
139 | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` | `::DW_IMAGE_FORMAT_RGB_UINT8` |
140 | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` |
141 | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` | `::DW_IMAGE_FORMAT_R_UINT8` |
142 | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
143 | `::DW_IMAGE_FORMAT_YUV420_UINT16_SEMIPLANAR` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
144 | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` |
145 | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
146 | `::DW_IMAGE_FORMAT_YUV420_UINT16_SEMIPLANAR` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
147 | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
148 | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGB_UINT8` |
149 | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_YUV420_UINT8_SEMIPLANAR` |
150 | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_R_UINT8` |
151 | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` |
152 | `::DW_IMAGE_FORMAT_YUV420_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
153 | `::DW_IMAGE_FORMAT_VUYX_UINT8` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
154 | `::DW_IMAGE_FORMAT_VUYX_UINT8` | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` |
155 | `::DW_IMAGE_FORMAT_VUYX_UINT8` | `::DW_IMAGE_FORMAT_YUV_UINT8_PLANAR` |
156 | `::DW_IMAGE_FORMAT_VUYX_UINT16` | `::DW_IMAGE_FORMAT_RGBA_FLOAT16` |
157 | `::DW_IMAGE_FORMAT_VUYX_UINT16` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
158 | `::DW_IMAGE_FORMAT_VUYX_UINT16` | `::DW_IMAGE_FORMAT_YUV_UINT16_PLANAR` |
159 | `::DW_IMAGE_FORMAT_YUV_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGBA_UINT8` |
160 | `::DW_IMAGE_FORMAT_YUV_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_RGB_UINT8_PLANAR` |
161 | `::DW_IMAGE_FORMAT_YUV_UINT8_PLANAR` | `::DW_IMAGE_FORMAT_VUYX_UINT8` |
162 | `::DW_IMAGE_FORMAT_YUV_UINT16_PLANAR` | `::DW_IMAGE_FORMAT_RGBA_FLOAT16` |
163 | `::DW_IMAGE_FORMAT_YUV_UINT16_PLANAR` | `::DW_IMAGE_FORMAT_RGB_FLOAT16_PLANAR` |
164 | `::DW_IMAGE_FORMAT_YUV_UINT16_PLANAR` | `::DW_IMAGE_FORMAT_VUYX_UINT16` |
165 
166 @section image_streamer Image Streamer
167 
168 An image streamer converts an image from a type X to a type Y, preserving the rest of the properties (see note A). All streamers (see note B) need to be initialized in order to allocate the necessary resources for the streaming (for example an image pool), depending on the type of streamer. On low level, all streamers differ in behavior and performance, so the choice and number of streamers should be planned wisely.
169 The idea of streaming is based on the logic of producer and consumer.
170 -# the producer sends an image through the stream. It is possible to send images in a sequence up to the maximum size of the streamer's internal pool (4). At this point the producer waits for the consumer
171 -# the consumer receives the converted image and consumes it
172 -# the consumer returns the image to the producer
173 -# the producer returns the image, freeing the taken location in the pool. The producer will wait for the consumer based on a timeout
174 
175 #### Supported Image Streamer Inputs and Outputs
176 
177 The following table describes the possible streaming combinations, given by image type (@ref dwImageType).
178 
179 | From (column) \ To (row) | CPU | GL | CUDA | NvMedia |
180 |-------------|:----------:|:----------:|:----------:|:----------:|
181 | CPU | - | X* | X* | X |
182 | GL | X* | - | X | X |
183 | CUDA| X | X* | X | X |
184 | NvMedia | X | X | X | X (ideal for cross-processing) |
185 
186 @note * Supported on iGPU only.
187 
188 #### Streamable Image Formats and Types
189 
190 The following table describes image format (@ref dwImageFormat) for each combination of image types (@ref dwImageType).
191 
192 | From (column) \ To (row) | CPU | GL | CUDA | NvMedia |
193 |-------------|:----------:|:----------:|:----------:|:----------:|
194 | CPU | - | RGBA, R, UINT8 | ALL | RGBA, R, YUV420 p/s,<br> YUV422 p/s, RAW,<br> UINT8, UINT16 |
195 | GL | RGBA, UINT8 | - | RGBA, UINT8 | RGBA, UINT8 |
196 | CUDA| ALL | RGBA, UINT8 | ALL | RGBA, YUV420 p/s,<br> YUV422 p/s, UINT8 |
197 | NvMedia | RGBA, YUV420 p/s,<br> YUV422 p/s, UINT8 | RGBA, UINT8 | RGBA, YUV420 p/s,<br> YUV422 p/s, UINT8 | RGBA, YUV420 p/p,<br> YUV422 p/p, RAW,<br> UINT8, UINT16 |
198 
199 Note A: In some cases (CPU->CUDA, CUDA->CPU, NvMedia->CUDA, CUDA->NvMedia) it is possible to stream into an image with a different memory layout
200 
201 Note B: The streamer NvMedia->CPU is the only streamer that does not allocate any resources because it performs a direct mapping between source and destination. For this reason it has some limitations but also provides maximum performance.
202 The streamer CUDA->GL on DGPU on a DrivePX2 platform, due to temporary technical limitations, allocates extra resources from the one needed and perform extra operations during the stream, leading to performance penalties.
203 
204 #### Underlying streaming mechanism for each combination
205 
206 The following table describes the mechanism for each streaming combination. 'X' indicates the combination is not available.
207 
208 |From (column) \ To (row) |CPU|CUDA Pitch|CUDA Block|GL|NvMedia|
209 |-|:-:|:-:|:-:|:-:|:-:|
210 |CPU|X|cudaMemcpy2DAsync|cudaMemcpy2DToArrayAsync|glBufferData - GL_STATIC_DRAW|NvMediaImagePutBits|
211 |CUDA Pitch|cudaMemcpy2DAsync|X|X|cudaMemcpy3DAsync (iGPU, X86) - GL->CPU->CUDA (dGPU)|EGL|
212 |CUDA Block|cudaMemcpy2DFromArrayAsync|X|X|cudaMemcpy3DAsync (iGPU, X86) - GL->CPU->CUDA (dGPU)|EGL|
213 |GL|glReadPixels|cudaMemcpy3DAsync (iGPU, X86) - X (dGPU)|cudaMemcpy3DAsync (iGPU, X86) - X (dGPU)|X|EGL|
214 |NvMedia|direct map (only for pitch linear)|EGL|EGL|EGL|X|
215 
216 #### Expected performance on NVIDIA DRIVE AGX Developer Kit
217 
218 The following table gives the streaming performance on NVIDIA DRIVE AGX Developer Kit. Values are given in microseconds and represent the average of 1000 runs; std and spike values are in parenthesis.
219 
220 'D' indicates dGPU performance and 'I' iGPU. If 'D' or 'I' is not specified, then the performance is independent of the GPU.
221 
222 ||RGBA 8bit|RAW 16bit|YUV 420 SP 8bit|
223 |-|:-:|:-:|:-:|
224 |CPU->CUDA| 20 D (4.2, 117) <br> 402 I (38.8, 643)| 20 D (5.1, 160) <br> 364 I (38.0, 804)| 34 D (8.6, 404) <br> 426 I (38.3, 654)|
225 |CPU->GL| 11 (7.9, 263)| NA| NA|
226 |CPU->NvMedia| 19 (3.5, 56) | 690 (4.1, 711)| NA|
227 |CUDA->CPU| 24 D (6.4, 139) <br> 407 I (29.2. 616)| 23 D (4.6, 147) <br> 422 I (35.6, 798)| 41 D (7.1, 168) <br> 449 I (56.1, 632)|
228 |CUDA->GL| 175 (73.9, 1436)| NA| NA|
229 |CUDA->NvMedia| NA| NA| NA|
230 |NvMedia->CPU| 7 (3.9, 71)| 8 (3.1, 35)| 14 (5.3, 138)|
231 |NvMedia->CUDA| 52 D (11.6, 2161) <br> 34 I (7.5, 908)| 49 D (9.4, 2020) <br> 37 I (11.8, 724)| 71 D (12.6, 3786) <br> 36 I (16.5, 923)|
232 |NvMedia->GL| 38 (13.2, 282)| NA| NA|
233 |GL->CPU| 75 (25.1, 784) | NA| NA|
234 |GL->CUDA| 1950 (146.4, 2411)| NA| NA|
235 |GL->NvMedia| 136 (180.9, 1635)| NA| NA|
236 
237 Note 1: GL-based times were taken on iGPU
238 
239 Note 2: Some streamers, especially EGL-based, have spikes for the first few frames, due to hidden optimizations that are performed during the first few iterations. Similar spikes may also occur for CUDA images.
240 
241 @section image_frame_capture Frame Capture
242 
243 A frame capture has 2 purposes:
244 - capture the content of an onscreen Window into a dwImageGL
245 - serialize a rogue dwImageGL or dwImageCUDA into a h264/h265 stream without needing to use a sensor camera
246 This module is ideal for recording a video of a DW based application being rendered on screen
247 
248 @section image_use_cases Relevant Tutorials
249 
250 - @ref image_usecase5
251 - @ref image_usecase2
252 - @ref image_usecase4
253 - @ref image_usecase3
254 - @ref image_usecase1
255 
256 @section image_apis APIs
257 
258 - @ref image_group