blob: 37d98fc4b491d676e1d3d482fa726f11372bcb02 [file] [log] [blame]
/** @file graph_process.c
* @brief
* This file contains the implementation of the graph inputs/outputs processing functions
*/
#include <VX/vx.h>
#include <VX/vxu.h>
#include <VX/vx_khr_nn.h>
#include "common.h"
#include "graph_process.h"
#include "utilities.h"
#include "./precisionConverter.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
#include <direct.h>
#define mkdir(dir, flags) _mkdir(dir)
#else
#include <sys/stat.h>
#endif
#define VX_MAX_TENSOR_DIMENSIONS 6
float* ResizeImage(vx_size dims[VX_MAX_TENSOR_DIMENSIONS], int chans, int width,
int height, vx_tensor input, unsigned char* image) {
float* resized_image = (float*) malloc(
dims[0] * dims[1] * chans * sizeof(float));
unsigned char* resized_image_uint = (unsigned char*) malloc(
dims[0] * dims[1] * chans);
vx_rectangle_t rect = { 0, 0, 0, 0 };
rect.end_x = width;
rect.end_y = height;
vx_rectangle_t rect_resized = { 0, 0, 0, 0 };
rect_resized.end_x = dims[0];
rect_resized.end_y = dims[1];
vx_context context = vxGetContext((vx_reference) input);
vx_image images[3];
vx_image resized_images[3];
vx_imagepatch_addressing_t addr = { 0 };
vx_imagepatch_addressing_t addr_resized = { 0 };
addr.dim_x = width;
addr.dim_y = height;
addr.stride_x = 3;
addr.stride_y = 3 * width;
addr.step_x = 1;
addr.step_y = 1;
addr_resized.dim_x = dims[0];
addr_resized.dim_y = dims[1];
addr_resized.stride_x = 3;
addr_resized.stride_y = 3 * dims[0];
addr_resized.step_x = 1;
addr_resized.step_y = 1;
for (int i = 0; i < 3; i++) {
images[i] = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
resized_images[i] = vxCreateImage(context, dims[0], dims[1],
VX_DF_IMAGE_U8);
vxCopyImagePatch(images[i], &rect, 0, &addr, image + i, VX_WRITE_ONLY,
VX_MEMORY_TYPE_HOST);
vxuScaleImage(context, images[i], resized_images[i],
VX_INTERPOLATION_BILINEAR);
vxReleaseImage(&images[i]);
vxCopyImagePatch(resized_images[i], &rect_resized, 0, &addr_resized,
resized_image_uint + i, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
vxReleaseImage(&resized_images[i]);
}
size_t imageSize = dims[0] * dims[1] * chans;
for (size_t i = 0; i < imageSize; ++i) {
resized_image[i] = (float) resized_image_uint[i];
}
free(resized_image_uint);
return resized_image;
}
float* CropImage(vx_size dims[VX_MAX_TENSOR_DIMENSIONS], int chans, int width,
int height, vx_tensor input, unsigned char* image) {
float* resized_image = (float*) malloc(
dims[0] * dims[1] * chans * sizeof(float));
unsigned char* resized_image_uint = (unsigned char*) malloc(
dims[0] * dims[1] * chans);
vx_rectangle_t rect = { 0, 0, 0, 0 };
rect.end_x = width;
rect.end_y = height;
vx_rectangle_t rect_resized = { 0, 0, 0, 0 };
rect_resized.end_x = dims[0];
rect_resized.end_y = dims[1];
vx_context context = vxGetContext((vx_reference) input);
vx_image images[3];
vx_image resized_images[3];
vx_imagepatch_addressing_t addr = { 0 };
vx_imagepatch_addressing_t addr_resized = { 0 };
addr.dim_x = width;
addr.dim_y = height;
addr.stride_x = 3;
addr.stride_y = 3 * width;
addr.step_x = 1;
addr.step_y = 1;
addr_resized.dim_x = dims[0];
addr_resized.dim_y = dims[1];
addr_resized.stride_x = 3;
addr_resized.stride_y = 3 * dims[0];
addr_resized.step_x = 1;
addr_resized.step_y = 1;
vx_rectangle_t rect_croped;
rect_croped.start_x = (width - dims[0])/2;
rect_croped.start_y = (height - dims[1])/2;
rect_croped.end_x = rect_croped.start_x + dims[0];
rect_croped.end_y = rect_croped.start_y + dims[1];
for (int i = 0; i < 3; i++) {
images[i] = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
vxCopyImagePatch(images[i], &rect, 0, &addr, image + i, VX_WRITE_ONLY,
VX_MEMORY_TYPE_HOST);
resized_images[i] = vxCreateImageFromROI(images[i], &rect_croped);
vxReleaseImage(&images[i]);
vxCopyImagePatch(resized_images[i], &rect_resized, 0, &addr_resized,
resized_image_uint + i, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
vxReleaseImage(&resized_images[i]);
}
size_t imageSize = dims[0] * dims[1] * chans;
for (size_t i = 0; i < imageSize; ++i) {
resized_image[i] = (float) resized_image_uint[i];
}
free(resized_image_uint);
return resized_image;
}
vx_status preprocess(vx_tensor input, const char * fName)
{
//1. Load image
//2. Normalize the image pixels the same way you used in the training process (i.e, mean substraction, scaling, etc)
//3. Scale each pixel with the scale factor ModelOptimizer reported
//4. Convert each pixel to the required precision (Q78, FP16, etc)
//5. Fill the input tensor with the pre-processed pixels
int width, height, chans;
vx_size dims_num = 0;
vx_size dims[VX_MAX_TENSOR_DIMENSIONS];
vx_status status = vxQueryTensor(input, VX_TENSOR_NUMBER_OF_DIMS, &dims_num, sizeof(dims_num));
status |= vxQueryTensor(input, VX_TENSOR_DIMS, dims, sizeof(dims));
unsigned char * image = loadImageFromFileUInt(fName, &width, &height, &chans);
float* resized_image = ResizeImage(dims, chans, width, height, input,
image);
float scaleFactor = 1.f / 8;
float meanValues[] = { 104.f, 117.f, 123.f };
subtractMeanImageAndScale(resized_image, dims[0], dims[1], chans, meanValues, scaleFactor);
status = imageToMDData(input, resized_image, dims[0], dims[1], chans);
freeImage(resized_image);
free (image);
return status;
}
vx_status postprocess(vx_tensor output, /*OUT*/ int* detected_class)
{
//1. Find top-N probabilities indices in the output tensor.
//2. Probabilities must be converted back to floating point number in order to be interpreted as percentages
//getProbabilitiesFromMDData(...)
vx_int16 mem[1000] = {0};
const vx_size view_start[2] = { 0, 0 };
const vx_size view_end[2] = { 1000, 1 };
const vx_size strides[2] = { sizeof(vx_int16), sizeof(vx_int16) * 1000 };
vx_status status = vxCopyTensorPatch(output, 2, view_start, view_end, strides, &mem[0], VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
if (status != VX_SUCCESS) { WriteLog("failed to read out the results form the graph"); return status; }
{
float max_prob = 0;
int res = 0;
//TODO: is there some define for this 1000??
for (int i = 0; i < 1000; ++i)
{
float prob = Q78ToFloat((char*)&mem[i]);
if (max_prob < prob)
{
max_prob = prob;
res = i;
}
}
*detected_class = res;
}
return VX_SUCCESS;
}
static vx_status saveTensorData(vx_tensor tensor, const char * fn)
{
if (!tensor) return VX_FAILURE;
FILE * f = fopen(fn, "wb");
vx_size dims_num;
vx_status status = vxQueryTensor(tensor, VX_TENSOR_NUMBER_OF_DIMS, &dims_num, sizeof(dims_num));
vx_size *dims = (vx_size*)malloc(dims_num * sizeof(vx_size));
if (!dims)
{
fclose(f);
return VX_ERROR_NO_MEMORY;
}
status = vxQueryTensor(tensor, VX_TENSOR_DIMS, dims, sizeof(vx_size) * dims_num);
if (status != VX_SUCCESS)
{
fclose(f);
free(dims);
return status;
}
vx_size count = 1;
for (vx_size i = 0; i < dims_num; ++i) count *= dims[i];
vx_size strides[VX_MAX_TENSOR_DIMENSIONS] = { sizeof(vx_int16) };
for (vx_size i = 0; i < dims_num - 1; ++i)
strides[i+1] = strides[i] * dims[i];
vx_int16 * buffer = malloc(count * sizeof(*buffer));
vx_size view_start[VX_MAX_TENSOR_DIMENSIONS] = { 0 };
status = vxCopyTensorPatch(tensor, dims_num, view_start, dims, strides, buffer, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
if (status == VX_SUCCESS)
{
fwrite((vx_int16*)buffer, sizeof(int16_t), count, f);
}
fclose(f);
free(buffer);
free(dims);
return status;
}
vx_status debugDumpLayers(ObjectRefContainerType * vxObjectsContainer)
{
mkdir("output", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
FILE * f = fopen("output/layers_dimensions.txt", "wt");
for (vx_size i = 0; i < vxObjectsContainer->count; ++i)
{
if (vxObjectsContainer->pObjects[i].type == VX_TYPE_TENSOR)
{
{
vx_size dims[VX_MAX_TENSOR_DIMENSIONS];
for (int i = 0; i < VX_MAX_TENSOR_DIMENSIONS; ++i) dims[i] = 0;
char fileName[256];
sprintf(fileName, "output/%s.tensor",vxObjectsContainer->pObjects[i].uniqueRef);
vx_status status = vxQueryTensor((vx_tensor)(vxObjectsContainer->pObjects[i].ref), VX_TENSOR_DIMS, &dims, sizeof(dims));
if (status != VX_SUCCESS) { printf("unable to get dims from tensor??\n"); return status; }
fprintf(f, "%s ", vxObjectsContainer->pObjects[i].uniqueRef);
for (vx_size j = 0; j < VX_MAX_TENSOR_DIMENSIONS; ++j)
fprintf(f, "%zu ", dims[j]);
fprintf(f, "\n");
saveTensorData((vx_tensor)vxObjectsContainer->pObjects[i].ref, fileName);
}
}
}
fclose(f);
return VX_SUCCESS;
}