Typical Functions of VPC

This section takes image cropping and resizing as an example to explain the API call sequence when the VPC processes images and provides sample code of typical functions to help you better understand the API call sequence.

Vision Preprocessing Core (VPC) supports image cropping, resizing, pasting, and format conversion. For details, see Function Description. For details about the input and output restrictions of the VPC function, see Restrictions.

API Call Sequence (for Cropping and Resizing)

If image cropping and resizing are involved during app development, ensure that your app contains the code logic for such image processing. For details about the API call sequence, see AscendCL API Call Sequence.

Figure 1 Cropping and resizing

The key APIs are described as follows (taking cropping and resizing as an example):

  1. Call acldvppCreateChannel to create an image processing channel.

    Before creating a channel, call acldvppCreateChannelDesc to create a channel description.

  2. Call acldvppCreateRoiConfig and acldvppCreateResizeConfig to create a crop ROI configuration and a resizing configuration, respectively. Then, call acldvppSetResizeConfigInterpolation to specify the resizing algorithm.
  3. Before cropping and resizing, call acldvppMalloc to allocate device memory as input and output buffers.
  4. Perform cropping and resizing.
    • About cropping:
      • Call the acldvppVpcCropAsync asynchronous API to crop a selected ROI from the input image and load the crop ROI to the output buffer as an output image.

        The cropped image will be resized again if cropArea is different from that of the output image.

      • Call the acldvppVpcCropAndPasteAsync asynchronous API to crop a selected ROI from the input image and paste the crop ROI on the destination image as an output image.
        • The cropped image will be resized again if the size of the cropArea is inconsistent with that of the pasteArea.
        • To paste the pasteArea on a canvas loaded to the output buffer, modify the code logic as follows: Allocate the output buffer and then load a canvas to the allocated buffer.
    • About resizing:
      • Call the acldvppVpcResizeAsync asynchronous API to resize the input image to the expected size of the output image.
      • Calculate the buffer for storing the resized image based on the YUV420SP format as follows: widthStride x heightStride x 3/2
    • Call aclrtSynchronizeStream to wait for the stream tasks to complete.
  5. Call acldvppFree to free the input and output buffers.
  6. Call acldvppDestroyRoiConfig and acldvppDestroyResizeConfig to destroy the crop ROI configuration and resizing configuration, respectively.
  7. Call acldvppDestroyChannel to destroy the image processing channel.

    After destroying the channel, call acldvppDestroyChannelDesc to destroy the channel description.

Sample Code for Image Resizing

You can view the complete code in Image Classification with ResNet-50 (Image Decoding+Resizing+Synchronous Inference).

This section focuses on the code logic of image resizing. For details about how to initialize and deinitialize AscendCL, see Initializing AscendCL. For details about how to allocate and deallocate runtime resources, see Runtime Resource Allocation and Deallocation.

After APIs are called, you need to add exception handling branches and record error logs and info logs. The following is a code snippet of key steps only, which is not ready to be built or run.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
// 1. Initialize AscendCL.

// 2. Allocate runtime resources.

// 3. Create image resizing configuration data and specify a resizing algorithm.
// resizeConfig_ is of type acldvppResizeConfig.
acldvppResizeConfig *resizeConfig_ = acldvppCreateResizeConfig();
aclError ret = acldvppSetResizeConfigInterpolation(resizeConfig, 0);

// 4. Create description of the data processing channel. dvppChannelDesc_ is of type acldvppChannelDesc.
dvppChannelDesc_ = acldvppCreateChannelDesc();

// 5. Create a data processing channel.
ret = acldvppCreateChannel(dvppChannelDesc_);

// 6. Allocate input buffer (run mode specific).
// Call aclrtGetRunMode to obtain the run mode of the software stack. If ACL_DEVICE is returned, allocate and use the device buffer. If ACL_HOST is returned, transfer the input image data to the device by using the aclrtMemcpy call. After the data transfer is complete, the buffer needs to be freed in a timely manner.
aclrtRunMode runMode;
ret = aclrtGetRunMode(&runMode);
// inputPicWidth and inputPicHeight respectively indicate the width and height of an image after alignment. The following uses a YUV420SP image as an example.
uint32_t resizeInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;
if(runMode == ACL_HOST){ 
    //Allocate host buffer vpcInHostBuffer.
    void* vpcInHostBuffer = nullptr;
    vpcInHostBuffer = malloc(resizeInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, vpcInHostBuffer, resizeInBufferSize);
    // Allocate the device buffer resizeInDevBuffer_.
    ret = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize);
    // Transfer the input image data to the device by using the aclrtMemcpy call.
    ret = aclrtMemcpy(resizeInDevBuffer_, resizeInBufferSize, vpcInHostBuffer, resizeInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);
    // Free the buffer in a timely manner after data transfer is complete.
    free(vpcInHostBuffer);
} else {
    // Allocate input buffer resizeInDevBuffer_ on the device.
    ret = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, resizeInDevBuffer_, resizeInBufferSize);
}

// 7. Allocate output buffer resizeOutBufferDev_. The buffer size resizeOutBufferSize_ is calculated based on the formula.
// outputPicWidth and outputPicHeight respectively indicate the width and height after image alignment. The following uses a YUV420SP image as an example.
uint32_t resizeOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;
ret = acldvppMalloc(&resizeOutBufferDev_, resizeOutBufferSize_);

// 8. Create the description of the input image to be resized and set the attribute values.
// resizeInputDesc_ is of type acldvppPicDesc.
resizeInputDesc_ = acldvppCreatePicDesc();
acldvppSetPicDescData(resizeInputDesc_, resizeInDevBuffer_);
acldvppSetPicDescFormat(resizeInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
acldvppSetPicDescWidth(resizeInputDesc_, inputWidth_);
acldvppSetPicDescHeight(resizeInputDesc_, inputHeight_);
acldvppSetPicDescWidthStride(resizeInputDesc_, inputWidthStride);
acldvppSetPicDescHeightStride(resizeInputDesc_, inputHeightStride);
acldvppSetPicDescSize(resizeInputDesc_, resizeInBufferSize);

// 9. Create the description of the resized image and set the attribute values.
// If the resized output image is used as the input for model inference, the output width and height must meet the requirements of the model.
// resizeOutputDesc_ is of type acldvppPicDesc.
resizeOutputDesc_ = acldvppCreatePicDesc();
acldvppSetPicDescData(resizeOutputDesc_, resizeOutBufferDev_);
acldvppSetPicDescFormat(resizeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); 
acldvppSetPicDescWidth(resizeOutputDesc_, resizeOutputWidth_);
acldvppSetPicDescHeight(resizeOutputDesc_, resizeOutputHeight_);
acldvppSetPicDescWidthStride(resizeOutputDesc_, resizeOutputWidthStride);
acldvppSetPicDescHeightStride(resizeOutputDesc_, resizeOutputHeightStride);
acldvppSetPicDescSize(resizeOutputDesc_, resizeOutBufferSize_);

// 10. Perform asynchronous resizing and call aclrtSynchronizeStream to wait for the stream tasks to complete.
ret = acldvppVpcResizeAsync(dvppChannelDesc_, resizeInputDesc_,
        resizeOutputDesc_, resizeConfig_, stream_);
ret = aclrtSynchronizeStream(stream_);

// 11. After resizing is complete, destroy the allocations, including the description of the input and output images, as well as the input and output buffers.
acldvppDestroyPicDesc(resizeInputDesc_);
acldvppDestroyPicDesc(resizeOutputDesc_);

if(runMode == ACL_HOST){ 
    // In this mode, the processing result is on the device. Therefore, you need to call the memory copy API to transfer the result data, and then free the device buffer.
    // Allocate host buffer vpcOutHostBuffer.
    void* vpcOutHostBuffer = nullptr;
    vpcOutHostBuffer = malloc(resizeOutBufferSize_);
    // Transfer the processing result of the device to the host by using the aclrtMemcpy call.
    ret = aclrtMemcpy(vpcOutHostBuffer, resizeOutBufferSize_, resizeOutBufferDev_, resizeOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);
    // Free the input and output buffer on the device.
    (void)acldvppFree(resizeInDevBuffer_);
    (void)acldvppFree(resizeOutBufferDev_);
    // Free the buffer after the data is used.
    free(vpcOutHostBuffer);
} else { 
    // The process is running on the device, and the processing result is also on the device. Free the device buffer when the data is no longer needed.
    (void)acldvppFree(resizeInDevBuffer_);
    (void)acldvppFree(resizeOutBufferDev_);
}
acldvppDestroyChannel(dvppChannelDesc_);
(void)acldvppDestroyChannelDesc(dvppChannelDesc_);
dvppChannelDesc_ = nullptr;

// 12. Deallocate runtime resources.

// 13. Deinitialize AscendCL.

// ....

Sample Code for Format Conversion

You can convert formats by using either of the following methods:
  • When you are implementing image cropping or resizing with the respective API call (such as acldvppVpcCropAsync), set the formats of the input and output images to different values.
  • Alternatively, call acldvppVpcConvertColorAsync.

    Atlas 200/300/500 Inference Product and Atlas Training Series Product do not support this API.

This section focuses on the code logic of format. For details about how to initialize and deinitialize AscendCL, see Initializing AscendCL. For details about how to allocate and deallocate runtime resources, see Runtime Resource Allocation and Deallocation.

After APIs are called, you need to add exception handling branches and record error logs and info logs. The following is a code snippet of key steps only, which is not ready to be built or run.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// 1. Initialize AscendCL.

// 2. Allocate runtime resources.

// 3. Create description of the data processing channel. dvppChannelDesc_ is of type acldvppChannelDesc.
dvppChannelDesc_ = acldvppCreateChannelDesc();

// 4. Create a data processing channel.
aclError ret = acldvppCreateChannel(dvppChannelDesc_);

// 5. Allocate input buffer (run mode specific).
// Call aclrtGetRunMode to obtain the run mode of the software stack. If ACL_DEVICE is returned, allocate and use the device buffer. If ACL_HOST is returned, transfer the input image data to the device by using the aclrtMemcpy call. After the data transfer is complete, the buffer needs to be freed in a timely manner.
aclrtRunMode runMode;
ret = aclrtGetRunMode(&runMode);
// inputPicWidth and inputPicHeight respectively indicate the width and height of an image after alignment. The following uses a YUV420SP image as an example.
uint32_t inBufferSize = inputPicWidth * inputPicHeight * 3 / 2;
if(runMode == ACL_HOST){ 
    // Allocate host buffer vpcInHostBuffer.
    void* vpcInHostBuffer = nullptr;
    vpcInHostBuffer = malloc(inBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, vpcInHostBuffer, inBufferSize);
    // Allocate the device buffer inDevBuffer_.
    ret = acldvppMalloc(&inDevBuffer_, inBufferSize);
    // Transfer the input image data to the device by using the aclrtMemcpy call.
    ret = aclrtMemcpy(inDevBuffer_, inBufferSize, vpcInHostBuffer, inBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);
    // Free the buffer in a timely manner after data transfer is complete.
    free(vpcInHostBuffer);
} else {
    // Allocate input buffer inDevBuffer_ on the device.
    ret = acldvppMalloc(&inDevBuffer_, inBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, inDevBuffer_, inBufferSize);
}

// 6. Allocate the CSC output buffer outBufferDev_. The buffer size outBufferSize_ is obtained based on the calculation formula.
// outputPicWidth and outputPicHeight respectively indicate the width and height after image alignment. The following uses a YUV420SP image as an example.
uint32_t outBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;
ret = acldvppMalloc(&outBufferDev_, outBufferSize_);

// 7. Create the description of the input image for CSC and set the attribute values.
// inputDesc_ is of type acldvppPicDesc.
inputDesc_ = acldvppCreatePicDesc();
acldvppSetPicDescData(inputDesc_, inDevBuffer_);
acldvppSetPicDescFormat(inputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
acldvppSetPicDescWidth(inputDesc_, inputWidth_);
acldvppSetPicDescHeight(inputDesc_, inputHeight_);
acldvppSetPicDescWidthStride(inputDesc_, inputWidthStride);
acldvppSetPicDescHeightStride(inputDesc_, inputHeightStride);
acldvppSetPicDescSize(inputDesc_, inBufferSize);

// 8. Create the description of the output image for CSC and set the attribute values. The output height and width must be the same as those of the input.
// If the CSC output image is used as the input for model inference, the output width and height must meet the requirements of the model.
// outputDesc_ is of type acldvppPicDesc. 
outputDesc_= acldvppCreatePicDesc();
acldvppSetPicDescData(outputDesc_, outBufferDev_);
acldvppSetPicDescFormat(outputDesc_, PIXEL_FORMAT_YUV_400); 
acldvppSetPicDescWidth(outputDesc_, outputWidth_);
acldvppSetPicDescHeight(outputDesc_, outputHeight_);
acldvppSetPicDescWidthStride(outputDesc_, outputWidthStride);
acldvppSetPicDescHeightStride(outputDesc_, outputHeightStride);
acldvppSetPicDescSize(outputDesc_, outBufferSize_);

// 9. Perform asynchronous CSC and call aclrtSynchronizeStream to wait for the stream tasks to complete.
ret = acldvppVpcConvertColorAsync(dvppChannelDesc_, inputDesc_, outputDesc_, stream_);
ret = aclrtSynchronizeStream(stream_);

// 10. After CSC is complete, destroy the allocations, including the description of the input and output images, as well as the input and output buffers.
acldvppDestroyPicDesc(inputDesc_);
acldvppDestroyPicDesc(outputDesc_);

if(runMode == ACL_HOST){ 
    // In this mode, the processing result is on the device. Therefore, you need to call the memory copy API to transfer the result data, and then free the device buffer.
    // Allocate host buffer vpcOutHostBuffer.
    void* vpcOutHostBuffer = nullptr;
    vpcOutHostBuffer = malloc(outBufferSize_);
    // Transfer the processing result of the device to the host by using the aclrtMemcpy call.
    ret = aclrtMemcpy(vpcOutHostBuffer, outBufferSize_, outBufferDev_, outBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);
    // Free the input and output buffer on the device.
    (void)acldvppFree(inDevBuffer_);
    (void)acldvppFree(outBufferDev_);
    // Free the buffer after the data is used.
    free(vpcOutHostBuffer);
} else { 
    // The process is running on the device, and the processing result is also on the device. Free the device buffer when the data is no longer needed.
    (void)acldvppFree(inDevBuffer_);
    (void)acldvppFree(outBufferDev_);
}
acldvppDestroyChannel(dvppChannelDesc_);
(void)acldvppDestroyChannelDesc(dvppChannelDesc_);
dvppChannelDesc_ = nullptr;

// 11. Deallocate runtime resources.

// 12. Deinitialize AscendCL.

// ....

Sample Code for Image Cropping and Resizing (Single-Image, Single-ROI)

Call acldvppVpcCropResizeAsync to crop an image from the input image based on the specified ROI, and then store the cropped image to the output memory as the output image. In addition, you can specify the resizing algorithm. The cropped image will be resized again if cropArea is different from that of the output image.

You can view the complete code in Image Classification with ResNet-50 (Image Decoding+Cropping and Resizing+Image Encoding+Synchronous Inference).

This section focuses on the code logic of image cropping and resizing. For details about how to initialize and deinitialize AscendCL, see Initializing AscendCL. For details about how to allocate and deallocate runtime resources, see Runtime Resource Allocation and Deallocation.

After APIs are called, you need to add exception handling branches and record error logs and info logs. The following is a code snippet of key steps only, which is not ready to be built or run.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
// 1. Initialize AscendCL.

// 2. Allocate runtime resources.

// 3. Create resizing configuration data and specify the cropping area.
// resizeConfig_ is of type acldvppResizeConfig.
resizeConfig_ = acldvppCreateResizeConfig();
aclError ret = acldvppSetResizeConfigInterpolation(resizeConfig_, 0);
// cropArea_ is of type acldvppRoiConfig.
cropArea_ = acldvppCreateRoiConfig(550, 749, 480, 679);

// 4. Create description of the data processing channel. dvppChannelDesc_ is of type acldvppChannelDesc.
dvppChannelDesc_ = acldvppCreateChannelDesc();

// 5. Create a data processing channel.
ret = acldvppCreateChannel(dvppChannelDesc_);

// 6. Allocate input buffer (run mode specific).
// Call aclrtGetRunMode to obtain the run mode of the software stack. If ACL_DEVICE is returned, allocate and use the device buffer. If ACL_HOST is returned, transfer the input image data to the device by using the aclrtMemcpy call. After the data transfer is complete, the buffer needs to be freed in a timely manner.
aclrtRunMode runMode;
ret = aclrtGetRunMode(&runMode);
// inputPicWidth and inputPicHeight respectively indicate the width and height of an image after alignment. The following uses a YUV420SP image as an example.
uint32_t cropInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;
if(runMode == ACL_HOST){ 
    // Allocate host buffer cropInHostBuffer.
    void* cropInHostBuffer = nullptr;
    cropInHostBuffer = malloc(cropInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, cropInHostBuffer, cropInBufferSize);
    // Allocate the device buffer cropInDevBuffer_.
    ret = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize);
    // Transfer the image data to the device by using the aclrtMemcpy call.
    ret = aclrtMemcpy(cropInDevBuffer_, cropInBufferSize, cropInHostBuffer, cropInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);
    // Free the buffer in a timely manner after data transfer is complete.
    free(cropInHostBuffer);
} else { 
    // Allocate input buffer cropInDevBuffer_ on the device.
    ret = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, cropInDevBuffer_, cropInBufferSize);
}

// 7. Allocate output buffer cropOutBufferDev_ on the device. The buffer size cropOutBufferSize_ is calculated based on the formula.
// outputPicWidth and outputPicHeight respectively indicate the width and height after image alignment. The following uses a YUV420SP image as an example.
uint32_t cropOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;
ret = acldvppMalloc(&cropOutBufferDev_, cropOutBufferSize_);

// 8. Create the description of the input image and set the attribute values. cropInputDesc_ is of type acldvppPicDesc.
cropInputDesc_ = acldvppCreatePicDesc();
acldvppSetPicDescData(cropInputDesc_, cropInDevBuffer_);
acldvppSetPicDescFormat(cropInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
acldvppSetPicDescWidth(cropInputDesc_, inputWidth_);
acldvppSetPicDescHeight(cropInputDesc_, inputHeight_);
acldvppSetPicDescWidthStride(cropInputDesc_, inputWidthStride);
acldvppSetPicDescHeightStride(cropInputDesc_, inputHeightStride);
acldvppSetPicDescSize(cropInputDesc_, cropInBufferSize);

// 9. Create the description of the output image and set the attribute values. cropOutputDesc_ is of type acldvppPicDesc.
// If the cropped output image is used as the input for model inference, the output width and height must meet the requirements of the model.
cropOutputDesc_ = acldvppCreatePicDesc();
acldvppSetPicDescData(cropOutputDesc_, cropOutBufferDev_);
acldvppSetPicDescFormat(cropOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); 
acldvppSetPicDescWidth(cropOutputDesc_, OutputWidth_);
acldvppSetPicDescHeight(cropOutputDesc_, OutputHeight_);
acldvppSetPicDescWidthStride(cropOutputDesc_, OutputWidthStride);
acldvppSetPicDescHeightStride(cropOutputDesc_, OutputHeightStride);
acldvppSetPicDescSize(cropOutputDesc_, cropOutBufferSize_);

// 10. Perform asynchronous cropping and resizing, and call aclrtSynchronizeStream to wait for the stream tasks to complete.
ret = acldvppVpcCropResizeAsync(dvppChannelDesc_, cropInputDesc_,
        cropOutputDesc_, cropArea_, resizeConfig_, stream_);
ret = aclrtSynchronizeStream(stream_);

// 11. After cropping and pasting are complete, destroy the allocations, including the description of the input and output images, input and output buffers, channel description, and channel.
acldvppDestroyRoiConfig(cropArea_);
acldvppDestroyResizeConfig(resizeConfig_);
acldvppDestroyPicDesc(cropInputDesc_);
acldvppDestroyPicDesc(cropOutputDesc_);
if(runMode == ACL_HOST){ 
    // In this mode, the processing result is on the device. Therefore, you need to call the memory copy API to transfer the result data, and then free the device buffer.
    // Allocate host buffer cropOutHostBuffer.
    void* cropOutHostBuffer = nullptr;
    cropOutHostBuffer = malloc(cropOutBufferSize_);
    // Transfer the processing result of the device to the host by using the aclrtMemcpy call.
    ret = aclrtMemcpy(cropOutHostBuffer, cropOutBufferSize_, cropOutBufferDev_, cropOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);
    // Free the input and output buffer on the device.
    (void)acldvppFree(cropInDevBuffer_);
    (void)acldvppFree(cropOutBufferDev_);
    // Free the buffer after the data is used.
    free(cropOutHostBuffer);
} else { 
    // The process is running on the device, and the processing result is also on the device. Free the device buffer when the data is no longer needed.
    (void)acldvppFree(cropInDevBuffer_);
    (void)acldvppFree(cropOutBufferDev_);
}
acldvppDestroyChannel(dvppChannelDesc_);
(void)acldvppDestroyChannelDesc(dvppChannelDesc_);
dvppChannelDesc_ = nullptr;

// 12. Deallocate runtime resources.

// 13. Deinitialize AscendCL.

// ....

Sample Code for Image Cropping, Resizing, and Pasting (Single-Image, Single-ROI)

Call acldvppVpcCropResizePasteAsync to crop an image from the input image based on the specified ROI, and paste the cropped ROI to the specified position on the destination image as the output image. In addition, you can specify the resizing algorithm. The cropped image will be resized again if the size of the cropArea is inconsistent with that of the pasteArea. To paste the pasteArea on a canvas loaded to the output buffer, modify the code logic as follows: Allocate the output buffer and then load a canvas to the allocated buffer.

You can view the complete code in Image Classification with ResNet-50 (Image Decoding+Cropping and Resizing+Image Encoding+Synchronous Inference).

This section focuses on the code logic of image cropping, resizing, and pasting. For details about how to initialize and deinitialize AscendCL, see Initializing AscendCL. For details about how to allocate and deallocate runtime resources, see Runtime Resource Allocation and Deallocation.

After APIs are called, you need to add exception handling branches and record error logs and info logs. The following is a code snippet of key steps only, which is not ready to be built or run.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
// 1. Initialize AscendCL.

// 2. Allocate runtime resources.

// 3. Create resizing configuration data, and specify cropArea_ and pasteArea_.
// resizeConfig_ is of type acldvppResizeConfig.
resizeConfig_ = acldvppCreateResizeConfig();
aclError ret = acldvppSetResizeConfigInterpolation(resizeConfig_, 0);
// cropArea_ and pasteArea_ are of type acldvppRoiConfig.
cropArea_ = acldvppCreateRoiConfig(512, 711, 512, 711);
pasteArea_ = acldvppCreateRoiConfig(16, 215, 16, 215);

// 4. Create description of the data processing channel. dvppChannelDesc_ is of type acldvppChannelDesc.
dvppChannelDesc_ = acldvppCreateChannelDesc();

// 5. Create a data processing channel.
ret = acldvppCreateChannel(dvppChannelDesc_);

// 6. Allocate input buffer (run mode specific).
// Call aclrtGetRunMode to obtain the run mode of the software stack. If ACL_DEVICE is returned, allocate and use the device buffer. If ACL_HOST is returned, transfer the input image data to the device by using the aclrtMemcpy call. After the data transfer is complete, the buffer needs to be freed in a timely manner.
aclrtRunMode runMode;
ret = aclrtGetRunMode(&runMode);
// inputPicWidth and inputPicHeight respectively indicate the width and height of an image after alignment. The following uses a YUV420SP image as an example.
uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;
if(runMode == ACL_HOST){ 
    //Allocate host buffer vpcInHostBuffer.
    void* vpcInHostBuffer = nullptr;
    vpcInHostBuffer = malloc(vpcInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize);
    // Allocate the device buffer vpcInDevBuffer_.
    ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);
    // Transfer the input image data to the device by using the aclrtMemcpy call.
    ret = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);
    // Free the buffer in a timely manner after data transfer is complete.
    free(vpcInHostBuffer);
} else {
    // Allocate input buffer vpcInDevBuffer_ on the device.
    ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize);
}

// 7. Allocate output buffer vpcOutBufferDev_. The buffer size vpcOutBufferSize_ is calculated based on the formula.
// outputPicWidth and outputPicHeight respectively indicate the width and height after image alignment. The following uses a YUV420SP image as an example.
uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;
ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_);

// 8. Create the description of the input image and set the attribute values.
// In this sample, the decoding output buffer is used as the input of image cropping and pasting. vpcInputDesc_ is of type acldvppPicDesc.
vpcInputDesc_ = acldvppCreatePicDesc();
acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); 
acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_);
acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_);
acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride);
acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride);
acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize);

// 9. Create the description of the output image and set the attribute values.
// If the cropped and pasted output image is used as the input for model inference, the output width and height must meet the requirements of the model.
// vpcOutputDesc_ is of type acldvppPicDesc.
vpcOutputDesc_ = acldvppCreatePicDesc();
acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_);
acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth);
acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight);
acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride);
acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride);
acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_);

// 10. Perform asynchronous cropping and pasting, and call aclrtSynchronizeStream to wait for the stream tasks to complete.
ret = acldvppVpcCropResizePasteAsync(dvppChannelDesc_, vpcInputDesc_,
        vpcOutputDesc_, cropArea_, pasteArea_, resizeConfig_, stream_);
ret = aclrtSynchronizeStream(stream_);

// 11. After cropping and pasting are complete, destroy the allocations, including the description of the input and output images, input and output buffers, channel description, and channel.
acldvppDestroyRoiConfig(cropArea_);
acldvppDestroyRoiConfig(pasteArea_);
acldvppDestroyResizeConfig(resizeConfig_);
acldvppDestroyPicDesc(vpcInputDesc_);
acldvppDestroyPicDesc(vpcOutputDesc_);

if(runMode == ACL_HOST){ 
    // In this mode, the processing result is on the device. Therefore, you need to call the memory copy API to transfer the result data, and then free the device buffer.
    // Allocate host buffer vpcOutHostBuffer.
    void* vpcOutHostBuffer = nullptr;
    vpcOutHostBuffer = malloc(vpcOutBufferSize_);
    // Transfer the processing result of the device to the host by using the aclrtMemcpy call.
    ret = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);
    // Free the input and output buffer on the device.
    (void)acldvppFree(vpcInDevBuffer_);
    (void)acldvppFree(vpcOutBufferDev_);
    // Free the buffer after the data is used.
    free(vpcOutHostBuffer);
} else { 
    // The process is running on the device, and the processing result is also on the device. Free the device buffer when the data is no longer needed.
    (void)acldvppFree(vpcInDevBuffer_);
    (void)acldvppFree(vpcOutBufferDev_);
}

acldvppDestroyChannel(dvppChannelDesc_);
(void)acldvppDestroyChannelDesc(dvppChannelDesc_);
dvppChannelDesc_ = nullptr;

// 12. Deallocate runtime resources.

// 13. Deinitialize AscendCL.

// ....

Sample Code for Image Cropping and Pasting (Single-Image, Multi-ROI)

Call acldvppVpcBatchCropAndPasteAsync to crop selected ROIs and paste the cropped ROIs to the specified positions on the destination image as the output image. The cropped image will be resized again if the size of the cropArea is inconsistent with that of the pasteArea. To paste the pasteArea on a canvas loaded to the output buffer, modify the code logic as follows: Allocate the output buffer and then load a canvas to the allocated buffer.

This section focuses on the code logic of image cropping and pasting. For details about how to initialize and deinitialize AscendCL, see Initializing AscendCL. For details about how to allocate and deallocate runtime resources, see Runtime Resource Allocation and Deallocation.

After APIs are called, you need to add exception handling branches and record error logs and info logs. The following is a code snippet of key steps only, which is not ready to be built or run.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// 1. Initialize AscendCL.

// 2. Allocate runtime resources.

// 3. Specify cropAreas_ and pasteAreas_, which are of type acldvppRoiConfig.
acldvppRoiConfig *cropAreas_[2], pasteAreas_[2];
cropAreas_[0] = acldvppCreateRoiConfig(512, 711, 512, 711);
cropAreas_[1] = acldvppCreateRoiConfig(512, 711, 512, 711);
pasteAreas_[0] = acldvppCreateRoiConfig(16, 215, 16, 215);
pasteAreas_[1] = acldvppCreateRoiConfig(16, 215, 16, 215);

// 4. Create description of the data processing channel. dvppChannelDesc_ is of type acldvppChannelDesc.
dvppChannelDesc_ = acldvppCreateChannelDesc();

// 5. Create a data processing channel.
aclError ret = acldvppCreateChannel(dvppChannelDesc_);

// 6. Allocate input buffer (run mode specific).
// Call aclrtGetRunMode to obtain the run mode of the software stack. If ACL_DEVICE is returned, allocate and use the device buffer. If ACL_HOST is returned, transfer the input image data to the device by using the aclrtMemcpy call. After the data transfer is complete, the buffer needs to be freed in a timely manner.
aclrtRunMode runMode;
ret = aclrtGetRunMode(&runMode);
// inputPicWidth and inputPicHeight respectively indicate the width and height of an image after alignment. The following uses a YUV420SP image as an example.
uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;
if(runMode == ACL_HOST){ 
    //Allocate host buffer vpcInHostBuffer.
    void* vpcInHostBuffer = nullptr;
    vpcInHostBuffer = malloc(vpcInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize);
    // Allocate the device buffer vpcInDevBuffer_.
    ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);
    //Transfer the image data from the host to the device by using the aclrtMemcpy call.
    ret = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);
    // Free the buffer in a timely manner after data transfer is complete.
    free(vpcInHostBuffer);
} else {
    // Allocate input buffer vpcInDevBuffer_ on the device.
    ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);
    // Load the input image into the buffer. The ReadPicFile function is defined by the user.
    ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize);
}

// 7. Allocate output buffer vpcOutBufferDev_. The buffer size vpcOutBufferSize_ is calculated based on the formula.
// outputPicWidth and outputPicHeight respectively indicate the width and height after image alignment. The following uses a YUV420SP image as an example.
uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;
ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_);

// 8. Create the description of the input image and set the attribute values.
// In this sample, the decoding output buffer is used as the input of image cropping and pasting. vpcInputDesc_ is of type acldvppPicDesc.
vpcInputBatchDesc_ = acldvppCreateBatchPicDesc(1);
vpcInputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, 0);
acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); 
acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_);
acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_);
acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride);
acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride);
acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize);

// 9. Create the description of the output image and set the attribute values.
// If the cropped and pasted output image is used as the input for model inference, the output width and height must meet the requirements of the model.
// vpcOutputDesc_ is of type acldvppPicDesc.
vpcOutputBatchDesc_ = acldvppCreateBatchPicDesc(2);
for (uint32_t index=0; index<2; ++index){
     vecOutPtr_.push_back(vpcOutBufferDev_);
     vpcOutputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, index);
    acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_);
    acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth);
    acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight);
    acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride);
    acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride);
    acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_);
}

// 10. Create an roiNums. Each image corresponds to the number of images to be cropped and pasted.

uint32_ttotalNum = 0;
std::unique_ptr<uint32_t[]> roiNums(new (std::nothrow) uint32_t[1]);
roiNums[0]=2;
// 11. Perform asynchronous cropping and pasting, and call aclrtSynchronizeStream to wait for the stream tasks to complete.
ret = acldvppVpcBatchCropAndPasteAsync(dvppChannelDesc_, vpcInputBatchDesc_, roiNums.get(), 1,
        vpcOutputBatchDesc_, cropAreas_, pasteAreas_, stream_);
ret = aclrtSynchronizeStream(stream_);

// 12. After cropping and pasting are complete, destroy the allocations, including the description of the input and output images, input and output buffers, channel description, and channel.
acldvppDestroyRoiConfig(cropAreas_[0]);
acldvppDestroyRoiConfig(cropAreas_[1]);
acldvppDestroyRoiConfig(pasteAreas_[0]);
acldvppDestroyRoiConfig(pasteAreas_[1]);
(void)acldvppFree(vpcInDevBuffer_);
for(uint32_t index=0; index<2; ++index){
if(runMode == ACL_HOST){ 
    // In this mode, the processing result is on the device. Therefore, you need to call the memory copy API to transfer the result data, and then free the device buffer.
    // Allocate host buffer vpcOutHostBuffer.
    void* vpcOutHostBuffer = nullptr;
    vpcOutHostBuffer = malloc(vpcOutBufferSize_);
    // Transfer the processing result of the device to the host by using the aclrtMemcpy call.
    ret = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);
    // Free the input and output buffer on the device.
    (void)acldvppFree(vpcOutBufferDev_);
    // Free the buffer after the data is used.
    free(vpcOutHostBuffer);
} else { 
    // The process is running on the device, and the processing result is also on the device. Free the device buffer when the data is no longer needed.
    
    (void)acldvppFree(vpcOutBufferDev_);
}
}
acldvppDestroyBatchPicDesc(vpcInputDesc_);
acldvppDestroyBatchPicDesc(vpcOutputDesc_);
acldvppDestroyChannel(dvppChannelDesc_);
(void)acldvppDestroyChannelDesc(dvppChannelDesc_);
dvppChannelDesc_ = nullptr;

// 13. Deallocate runtime resources.

// 14. Deinitialize AscendCL.

// ....