// nodeless version of the Not kernel vx_status vxNot(vx_image input, vx_image output) { vx_uint32 y, x, width = 0, height = 0; void *dst_base = NULL; void *src_base = NULL; vx_imagepatch_addressing_t dst_addr, src_addr; vx_rectangle_t rect; vx_status status = VX_SUCCESS; status = vxGetValidRegionImage(input, &rect); status |= vxAccessImagePatch(input, &rect, 0, &src_addr, (void **)&src_base, VX_READ_ONLY); status |= vxAccessImagePatch(output, &rect, 0, &dst_addr, (void **)&dst_base, VX_WRITE_ONLY); height = src_addr.dim_y; width = src_addr.dim_x; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { vx_uint8 *src = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint8 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = ~*src; } } status |= vxCommitImagePatch(input, NULL, 0, &src_addr, src_base); status |= vxCommitImagePatch(output, &rect, 0, &dst_addr, dst_base); return status; }
// generic bitwise op static vx_status vxBinaryU8Op(vx_image in1, vx_image in2, vx_image output, bitwiseOp op) { vx_uint32 y, x, width = 0, height = 0; void *dst_base = NULL; void *src_base[2] = {NULL, NULL}; vx_imagepatch_addressing_t dst_addr, src_addr[2]; vx_rectangle_t rect; vx_status status = VX_SUCCESS; status = vxGetValidRegionImage(in1, &rect); status |= vxAccessImagePatch(in1, &rect, 0, &src_addr[0], (void **)&src_base[0], VX_READ_ONLY); status |= vxAccessImagePatch(in2, &rect, 0, &src_addr[1], (void **)&src_base[1], VX_READ_ONLY); status |= vxAccessImagePatch(output, &rect, 0, &dst_addr, (void **)&dst_base, VX_WRITE_ONLY); width = src_addr[0].dim_x; height = src_addr[0].dim_y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { vx_uint8 *src[2] = { vxFormatImagePatchAddress2d(src_base[0], x, y, &src_addr[0]), vxFormatImagePatchAddress2d(src_base[1], x, y, &src_addr[1]), }; vx_uint8 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = op(*src[0], *src[1]); } } status |= vxCommitImagePatch(in1, NULL, 0, &src_addr[0], src_base[0]); status |= vxCommitImagePatch(in2, NULL, 0, &src_addr[1], src_base[1]); status |= vxCommitImagePatch(output, &rect, 0, &dst_addr, dst_base); return status; }
static vx_status vxMagnitudeKernel(vx_node node, vx_reference *parameters, vx_uint32 num) { vx_status status = VX_FAILURE; if (num == 3) { vx_image grad_x = (vx_image)parameters[0]; vx_image grad_y = (vx_image)parameters[1]; vx_image output = (vx_image)parameters[2]; vx_uint32 y, x; vx_fourcc format = 0; vx_uint8 *dst_base = NULL; vx_int16 *src_base_x = NULL; vx_int16 *src_base_y = NULL; vx_imagepatch_addressing_t dst_addr, src_addr_x, src_addr_y; vx_rectangle rect; vx_uint32 value; if (grad_x == 0 || grad_y == 0) return VX_ERROR_INVALID_PARAMETERS; vxQueryImage(output, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format)); rect = vxGetValidRegionImage(grad_x); status = VX_SUCCESS; status |= vxAccessImagePatch(grad_x, rect, 0, &src_addr_x, (void **)&src_base_x); status |= vxAccessImagePatch(grad_y, rect, 0, &src_addr_y, (void **)&src_base_y); status |= vxAccessImagePatch(output, rect, 0, &dst_addr, (void **)&dst_base); for (y = 0; y < src_addr_x.dim_y; y++) { for (x = 0; x < src_addr_x.dim_x; x++) { vx_int16 *in_x = vxFormatImagePatchAddress2d(src_base_x, x, y, &src_addr_x); vx_int16 *in_y = vxFormatImagePatchAddress2d(src_base_y, x, y, &src_addr_y); if (format == FOURCC_U8) { vx_uint8 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); vx_int32 grad[2] = {in_x[0]*in_x[0], in_y[0]*in_y[0]}; vx_float64 sum = grad[0] + grad[1]; value = ((vx_int32)sqrt(sum))/4; *dst = (vx_uint8)(value > UINT8_MAX ? UINT8_MAX : value); } else if (format == FOURCC_S16) { vx_int16 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); vx_int32 grad[2] = {in_x[0]*in_x[0], in_y[0]*in_y[0]}; vx_float64 sum = grad[0] + grad[1]; value = (vx_int32)sqrt(sum); *dst = (vx_int16)(value > INT16_MAX ? INT16_MAX : value); } } } status |= vxCommitImagePatch(grad_x, 0, 0, &src_addr_x, src_base_x); status |= vxCommitImagePatch(grad_y, 0, 0, &src_addr_y, src_base_y); status |= vxCommitImagePatch(output, rect, 0, &dst_addr, dst_base); vxReleaseRectangle(&rect); } return status; }
static vx_status vxPhaseKernel(vx_node node, vx_reference *parameters, vx_uint32 num) { vx_status status = VX_FAILURE; if (num == 3) { vx_image grad_x = (vx_image)parameters[0]; vx_image grad_y = (vx_image)parameters[1]; vx_image output = (vx_image)parameters[2]; vx_uint32 y, x; vx_uint8 *dst_base = NULL; vx_int16 *src_base_x = NULL; vx_int16 *src_base_y = NULL; vx_imagepatch_addressing_t dst_addr, src_addr_x, src_addr_y; vx_rectangle rect; if (grad_x == 0 && grad_y == 0) return VX_ERROR_INVALID_PARAMETERS; rect = vxGetValidRegionImage(grad_x); status = VX_SUCCESS; status |= vxAccessImagePatch(grad_x, rect, 0, &src_addr_x, (void **)&src_base_x); status |= vxAccessImagePatch(grad_y, rect, 0, &src_addr_y, (void **)&src_base_y); status |= vxAccessImagePatch(output, rect, 0, &dst_addr, (void **)&dst_base); for (y = 0; y < dst_addr.dim_y; y++) { for (x = 0; x < dst_addr.dim_x; x++) { vx_int16 *in_x = vxFormatImagePatchAddress2d(src_base_x, x, y, &src_addr_x); vx_int16 *in_y = vxFormatImagePatchAddress2d(src_base_y, x, y, &src_addr_y); vx_uint8 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); /* -M_PI to M_PI */ double arct = atan2((double)in_y[0],(double)in_x[0]); /* 0.0 - 1.0 */ double norm = arct; if (arct < 0.0) { norm = VX_TAU + arct; } /* 0 - 255 */ *dst = (vx_uint8)((vx_uint32)(norm * 255u) & 0xFFu); if (in_y[0] != 0 || in_x[0] != 0) { VX_PRINT(VX_ZONE_INFO, "atan2(%d,%d) = %lf [norm=%lf] dst=%02x\n", in_y[0], in_x[0], arct, norm, *dst); } } } status |= vxCommitImagePatch(grad_x, 0, 0, &src_addr_x, src_base_x); status |= vxCommitImagePatch(grad_y, 0, 0, &src_addr_y, src_base_y); status |= vxCommitImagePatch(output, rect, 0, &dst_addr, dst_base); vxReleaseRectangle(&rect); } return status; }
vx_status vxConvolution3x3(vx_image src, vx_image dst, vx_int16 conv[3][3], const vx_border_mode_t *borders) { vx_uint32 y, x; void *src_base = NULL; void *dst_base = NULL; vx_imagepatch_addressing_t src_addr, dst_addr; vx_rectangle_t rect; vx_enum dst_format = VX_DF_IMAGE_VIRT; vx_status status = VX_SUCCESS; vx_uint32 low_x = 0, low_y = 0, high_x, high_y; status = vxGetValidRegionImage(src, &rect); status |= vxAccessImagePatch(src, &rect, 0, &src_addr, &src_base, VX_READ_ONLY); status |= vxAccessImagePatch(dst, &rect, 0, &dst_addr, &dst_base, VX_WRITE_ONLY); status |= vxQueryImage(dst, VX_IMAGE_ATTRIBUTE_FORMAT, &dst_format, sizeof(dst_format)); high_x = src_addr.dim_x; high_y = src_addr.dim_y; if (borders->mode == VX_BORDER_MODE_UNDEFINED) { ++low_x; --high_x; ++low_y; --high_y; vxAlterRectangle(&rect, 1, 1, -1, -1); } //printf("%s Rectangle = {%u,%u x %u,%u}\n",__FUNCTION__, rect.start_x, rect.start_y, rect.end_x, rect.end_y); for (y = low_y; y < high_y; y++) { for (x = low_x; x < high_x; x++) { vx_int32 value = vx_convolve8with16(src_base, x, y, &src_addr, conv, borders); if (dst_format == VX_DF_IMAGE_U8) { vx_uint8 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = vx_clamp_u8_i32(value); } else { vx_int16 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = vx_clamp_s16_i32(value); } } } status |= vxCommitImagePatch(src, NULL, 0, &src_addr, src_base); status |= vxCommitImagePatch(dst, &rect, 0, &dst_addr, dst_base); return status; }
// read image int ReadImage(vx_image image, vx_rectangle_t * rectFull, FILE * fp) { // get number of planes, image format, and pixel type vx_df_image format = VX_DF_IMAGE_VIRT; vx_size num_planes = 0; ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &num_planes, sizeof(num_planes))); // read all image planes into vx_image and check if EOF has occured while reading bool eofDetected = false; for (vx_uint32 plane = 0; plane < (vx_uint32)num_planes; plane++){ vx_imagepatch_addressing_t addr; vx_uint8 * src = NULL; ERROR_CHECK(vxAccessImagePatch(image, rectFull, plane, &addr, (void **)&src, VX_WRITE_ONLY)); vx_size width = (addr.dim_x * addr.scale_x) / VX_SCALE_UNITY; vx_size width_in_bytes = (format == VX_DF_IMAGE_U1_AMD) ? ((width + 7) >> 3) : (width * addr.stride_x); for (vx_uint32 y = 0; y < addr.dim_y; y += addr.step_y){ vx_uint8 *srcp = (vx_uint8 *)vxFormatImagePatchAddress2d(src, 0, y, &addr); if (fread(srcp, 1, width_in_bytes, fp) != width_in_bytes) { eofDetected = true; break; } } ERROR_CHECK(vxCommitImagePatch(image, rectFull, plane, &addr, src)); } // return 1 if EOF detected, other 0 return eofDetected ? 1 : 0; }
static vx_status map_vx_image(vx_image vxImg, uint32_t *width, uint32_t *height, mem_info_t *mem_info, vx_enum usage) { vx_size vxImgSize; vx_status status = VX_SUCCESS; vx_rectangle_t rect; vx_imagepatch_addressing_t vxImg_addr; void *vxImg_base = NULL; status = vxGetValidRegionImage(vxImg, &rect); if(status != VX_SUCCESS) return status; status = vxAccessImagePatch(vxImg, &rect, 0, &vxImg_addr, (void **)&vxImg_base, usage); if(status != VX_SUCCESS) return status; *width = vxImg_addr.dim_x; *height = vxImg_addr.dim_y; status = get_vx_image_size(vxImg, &vxImgSize); if(status != VX_SUCCESS) return status; mem_info->len = vxImgSize; mem_info->ptr = vxImg_base; mem_info->vxImg_addr = vxImg_addr; return status; }
static vx_status VX_CALLBACK vxCopyImagePtrKernel(vx_node node, const vx_reference *parameters, vx_uint32 num) { vx_status status = VX_FAILURE; if (num == 2) { vx_scalar input = (vx_scalar)parameters[0]; vx_image output = (vx_image)parameters[1]; vx_uint32 width = 0, height = 0, p = 0, y = 0, len = 0; vx_size planes = 0; void *src = NULL; void *dst = NULL; vx_imagepatch_addressing_t dst_addr; vx_rectangle_t rect; vx_uint8 *srcp = NULL; vxReadScalarValue(input, &src); srcp = (vx_uint8 *)src; status = VX_SUCCESS; // assume success until an error occurs. status |= vxQueryImage(output, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width)); status |= vxQueryImage(output, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height)); status |= vxQueryImage(output, VX_IMAGE_ATTRIBUTE_PLANES, &planes, sizeof(planes)); rect.start_x = rect.start_y = 0; rect.end_x = width; rect.end_y = height; for (p = 0; p < planes && status == VX_SUCCESS; p++) { status = VX_SUCCESS; status |= vxAccessImagePatch(output, &rect, p, &dst_addr, &dst, VX_WRITE_ONLY); for (y = 0; y < height && status == VX_SUCCESS; y+=dst_addr.step_y) { vx_uint8 *dstp = vxFormatImagePatchAddress2d(dst, 0, y, &dst_addr); len = (dst_addr.stride_x * dst_addr.dim_x * dst_addr.scale_x) / VX_SCALE_UNITY; memcpy(dstp, srcp, len); srcp += len; } if (status == VX_SUCCESS) { status |= vxCommitImagePatch(output, &rect, p, &dst_addr, dst); } } } else { status = VX_ERROR_INVALID_PARAMETERS; } return status; }
// write image int WriteImage(vx_image image, vx_rectangle_t * rectFull, FILE * fp) { // get number of planes, image format, and pixel type vx_df_image format = VX_DF_IMAGE_VIRT; vx_size num_planes = 0; ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &num_planes, sizeof(num_planes))); // write all image planes from vx_image bool eofDetected = false; for (vx_uint32 plane = 0; plane < (vx_uint32)num_planes; plane++){ vx_imagepatch_addressing_t addr; vx_uint8 * src = NULL; ERROR_CHECK(vxAccessImagePatch(image, rectFull, plane, &addr, (void **)&src, VX_READ_ONLY)); vx_size width = (addr.dim_x * addr.scale_x) / VX_SCALE_UNITY; vx_size width_in_bytes = (format == VX_DF_IMAGE_U1_AMD) ? ((width + 7) >> 3) : (width * addr.stride_x); for (vx_uint32 y = 0; y < addr.dim_y; y += addr.step_y){ vx_uint8 *srcp = (vx_uint8 *)vxFormatImagePatchAddress2d(src, 0, y, &addr); fwrite(srcp, 1, width_in_bytes, fp); } ERROR_CHECK(vxCommitImagePatch(image, rectFull, plane, &addr, src)); } return 0; }
// Compute checksum of rectangular region specified within an image void ComputeChecksum(char checkSumString[64], vx_image image, vx_rectangle_t * rectRegion) { // get number of planes vx_df_image format = VX_DF_IMAGE_VIRT; vx_size num_planes = 0; ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &num_planes, sizeof(num_planes))); // compute checksum CHasher checksum; checksum.Initialize(); for (vx_uint32 plane = 0; plane < (vx_uint32)num_planes; plane++) { vx_imagepatch_addressing_t addr; vx_uint8 * base_ptr = nullptr; ERROR_CHECK(vxAccessImagePatch(image, rectRegion, plane, &addr, (void **)&base_ptr, VX_READ_ONLY)); vx_uint32 width = ((addr.dim_x * addr.scale_x) / VX_SCALE_UNITY); vx_uint32 height = ((addr.dim_y * addr.scale_y) / VX_SCALE_UNITY); vx_uint32 width_in_bytes = (format == VX_DF_IMAGE_U1_AMD) ? ((width + 7) >> 3) : (width * addr.stride_x); for (vx_uint32 y = 0; y < height; y++) { checksum.Process(base_ptr + y * addr.stride_y, width_in_bytes); } ERROR_CHECK(vxCommitImagePatch(image, rectRegion, plane, &addr, base_ptr)); } // copy the checksum string strcpy(checkSumString, checksum.GetCheckSum()); }
//////// // main() has all the OpenVX application code for this exercise. // Command-line usage: // % solution_exercise2 [<video-sequence>|<camera-device-number>] // When neither video sequence nor camera device number is specified, // it defaults to the video sequence in "PETS09-S1-L1-View001.avi". int main( int argc, char * argv[] ) { // Get default video sequence when nothing is specified on command-line and // instantiate OpenCV GUI module for reading input RGB images and displaying // the image with OpenVX results. const char * video_sequence = argv[1]; CGuiModule gui( video_sequence ); // Try to grab the first video frame from the sequence using cv::VideoCapture // and check if a video frame is available. if( !gui.Grab() ) { printf( "ERROR: input has no video\n" ); return 1; } //////// // Set the application configuration parameters. Note that input video // sequence is an 8-bit RGB image with dimensions given by gui.GetWidth() // and gui.GetHeight(). The parameters for the Harris corners algorithm are: // max_keypoint_count - maximum number of keypoints to track // harris_strength_thresh - minimum threshold score to keep a corner // (computed using the normalized Sobel kernel) // harris_min_distance - radial L2 distance for non-max suppression // harris_k_sensitivity - sensitivity threshold k from the Harris-Stephens // harris_gradient_size - window size for gradient computation // harris_block_size - block window size used to compute the // Harris corner score // lk_pyramid_levels - number of pyramid levels for LK optical flow // lk_termination - can be VX_TERM_CRITERIA_ITERATIONS or // VX_TERM_CRITERIA_EPSILON or // VX_TERM_CRITERIA_BOTH // lk_epsilon - error for terminating the algorithm // lk_num_iterations - number of iterations // lk_use_initial_estimate - turn on/off use of initial estimates // lk_window_dimension - size of window on which to perform the algorithm vx_uint32 width = gui.GetWidth(); vx_uint32 height = gui.GetHeight(); vx_size max_keypoint_count = 10000; vx_float32 harris_strength_thresh = 0.0005f; vx_float32 harris_min_distance = 5.0f; vx_float32 harris_k_sensitivity = 0.04f; vx_int32 harris_gradient_size = 3; vx_int32 harris_block_size = 3; vx_uint32 lk_pyramid_levels = 6; vx_float32 lk_pyramid_scale = VX_SCALE_PYRAMID_HALF; vx_enum lk_termination = VX_TERM_CRITERIA_BOTH; vx_float32 lk_epsilon = 0.01f; vx_uint32 lk_num_iterations = 5; vx_bool lk_use_initial_estimate = vx_false_e; vx_uint32 lk_window_dimension = 6; //////// // Create the OpenVX context and make sure the returned context is valid and // register the log_callback to receive messages from OpenVX framework. vx_context context = vxCreateContext(); ERROR_CHECK_OBJECT( context ); vxRegisterLogCallback( context, log_callback, vx_false_e ); //////// // Create OpenVX image object for input RGB image. vx_image input_rgb_image = vxCreateImage( context, width, height, VX_DF_IMAGE_RGB ); ERROR_CHECK_OBJECT( input_rgb_image ); ////////******** // OpenVX optical flow functionality requires pyramids of the current input // image and the previous image. It also requires keypoints that correspond // to the previous pyramid and will output updated keypoints into // another keypoint array. To be able to toggle between the current and // the previous buffers, you need to use OpenVX delay objects and vxAgeDelay(). // Create OpenVX pyramid and array object exemplars and create OpenVX delay // objects for both to hold two of each. Note that the exemplar objects are not // needed once the delay objects are created. // // TODO STEP 01:******** // 1. Use vxCreatePyramid API to create a pyramid exemplar with the // same dimensions as the input image, VX_DF_IMAGE_U8 as image format, // lk_pyramid_levels as levels, and lk_pyramid_scale as scale. // We gave code for this in comments. // 2. Use vxCreateArray API to create an array exemplar with // keypoint data type with num_keypoint_count as capacity. // You need to add missing parameters to code in comments. // 3. Use vxCreateDelay API to create delay objects for pyramid and // keypoint array using the exemplars created using the two steps above. // Use 2 delay slots for both of the delay objects. // We gave code for one in comments; do similar for the other. // 4. Release the pyramid and keypoint array exemplar objects. // We gave code for one in comments; do similar for the other. // 5. Use ERROR_CHECK_OBJECT/STATUS macros for proper error checking. // We gave few error checks; do similar for the others. // vx_pyramid pyramidExemplar = vxCreatePyramid( context, lk_pyramid_levels, // lk_pyramid_scale, width, height, VX_DF_IMAGE_U8 ); // ERROR_CHECK_OBJECT( pyramidExemplar ); // vx_delay pyramidDelay = vxCreateDelay( context, ( vx_reference )pyramidExemplar, 2 ); // ERROR_CHECK_OBJECT( pyramidDelay ); // ERROR_CHECK_STATUS( vxReleasePyramid( &pyramidExemplar ) ); // vx_array keypointsExemplar = vxCreateArray( /* Fill in parameters */ ); // vx_delay keypointsDelay = vxCreateDelay( /* Fill in parameters */ ); ////////******** // An object from a delay slot can be accessed using vxGetReferenceFromDelay API. // You need to use index = 0 for the current object and index = -1 for the previous object. // // TODO STEP 02:******** // 1. Use vxGetReferenceFromDelay API to get the current and previous // pyramid objects from pyramid delay object. Note that you need // to typecast the vx_reference object to vx_pyramid. // We gave code for one in comments; do similar for the other. // 2. Similarly, get the current and previous keypoint array objects from // the keypoint delay object. // We gave code for one in comments; do similar for the other. // 3. Use ERROR_CHECK_OBJECT for proper error checking. // We gave one error check; do similar for the others. // vx_pyramid currentPyramid = ( vx_pyramid ) vxGetReferenceFromDelay( pyramidDelay, 0 ); // vx_pyramid previousPyramid = ( vx_pyramid ) vxGetReferenceFromDelay( /* Fill in parameters */ ); // vx_array currentKeypoints = ( vx_array ) vxGetReferenceFromDelay( /* Fill in parameters */ ); // vx_array previousKeypoints = ( vx_array ) vxGetReferenceFromDelay( keypointsDelay, -1 ); // ERROR_CHECK_OBJECT( currentPyramid ); ////////******** // Harris and optical flow algorithms require their own graph objects. // The Harris graph needs to extract gray scale image out of input RGB, // compute an initial set of keypoints, and compute an initial pyramid for use // by the optical flow graph. // // TODO STEP 03:******** // 1. Create two graph objects: one for the Harris corner detector and // the other for feature tracking using optical flow using the // vxCreateGraph API. // We gave code for one graph; do similar for the other. // 2. Use ERROR_CHECK_OBJECT to check the objects. // We gave one error check; do similar for the other. // vx_graph graphHarris = vxCreateGraph( context ); // vx_graph graphTrack = /* Fill in here */; // ERROR_CHECK_OBJECT( graphHarris ); ////////******** // Harris and pyramid computation expect input to be an 8-bit image. // Given that input is an RGB image, it is best to extract a gray image // from RGB image, which requires two steps: // - perform RGB to IYUV color conversion // - extract Y channel from IYUV image // This requires two intermediate OpenVX image objects. Since you don't // need to access these objects from the application, they can be virtual // objects that can be created using the vxCreateVirtualImage API. // // TODO STEP 04:******** // 1. Create an IYUV image and a U8 image (for Y channel) with the same // dimensions as the input RGB image. Note that the image formats for // IYUV and U8 images are VX_DF_IMAGE_IYUV and VX_DF_IMAGE_U8. // Note that virtual objects are specific to a graph, so you // need to create two sets, one for each graph. // We gave one fully in comments and you need to fill in missing // parameters for the others. // 2. Use ERROR_CHECK_OBJECT to check the objects. // We gave one error check in comments; do similar for others. // vx_image harris_yuv_image = vxCreateVirtualImage( graphHarris, width, height, VX_DF_IMAGE_IYUV ); // vx_image harris_luma_image = vxCreateVirtualImage( graphHarris, /* Fill in parameters */ ); // vx_image opticalflow_yuv_image = vxCreateVirtualImage( graphTrack, /* Fill in parameters */ ); // vx_image opticalflow_luma_image = vxCreateVirtualImage( /* Fill in parameters */ ); // ERROR_CHECK_OBJECT( harris_yuv_image ); ////////******** // The Harris corner detector and optical flow nodes (see "VX/vx_nodes.h") // take strength_thresh, min_distance, sensitivity, epsilon, // num_iterations, and use_initial_estimate parameters as scalar // data objects. So, you need to create scalar objects with the corresponding // configuration parameters. // // TODO STEP 05:******** // 1. Create scalar data objects of VX_TYPE_FLOAT32 for strength_thresh, // min_distance, sensitivity, and epsilon. Set their // initial values to harris_strength_thresh, harris_min_distance, // harris_k_sensitivity, and lk_epsilon. // We gave code full code for one scalar in comments; fill in // missing arguments for other ones. // 2. Similarly, create scalar objects for num_iterations and // use_initial_estimate with initial values: lk_num_iterations and // lk_use_initial_estimate. Make sure to use proper data types for // these parameters. // We gave code full code for one scalar in comments; fill in // missing arguments for the other. // 3. Use ERROR_CHECK_OBJECT to check proper creation of objects. // We gave the error check for one scalar; do similar for other 5 scalars. // vx_scalar strength_thresh = NULL; // vxCreateScalar( context, VX_TYPE_FLOAT32, &harris_strength_thresh ); // vx_scalar min_distance = NULL; // vxCreateScalar( context, /* Fill in parameters */ ); // vx_scalar sensitivity = NULL; // vxCreateScalar( /* Fill in parameters */ ); // vx_scalar epsilon = NULL; // vxCreateScalar( /* Fill in parameters */ ); // vx_scalar num_iterations = NULL; // vxCreateScalar( context, VX_TYPE_UINT32, /* Fill in parameter */ ); // vx_scalar use_initial_estimate = NULL; // vxCreateScalar( context, VX_TYPE_BOOL, &lk_use_initial_estimate ); // ERROR_CHECK_OBJECT( strength_thresh ); ////////******** // Now all the objects have been created for building the graphs. // First, build a graph that performs Harris corner detection and initial pyramid computation. // See "VX/vx_nodes.h" for APIs how to add nodes into a graph. // // TODO STEP 06:******** // 1. Use vxColorConvertNode and vxChannelExtractNode APIs to get gray // scale image for Harris and Pyramid computation from the input // RGB image. Add these nodes into Harris graph. // We gave code in comments with a missing parameter for you to fill in. // 2. Use vxGaussianPyramidNode API to add pyramid computation node. // You need to use the current pyramid from the pyramid delay object. // We gave code in comments with a missing parameter for you to fill in. // 3. Use vxHarrisCornersNode API to add a Harris corners node. // You need to use the current keypoints from keypoints delay object. // We gave code in comments with few missing parameters for you to fill in. // 4. Use ERROR_CHECK_OBJECT to check proper creation of objects. // 5. Release node and virtual objects immediately since the graph // retains references to them. // 6. Call vxVerifyGraph to check for any errors in the graph. // Fill in missing parameter in commented code. // vx_node nodesHarris[] = // { // vxColorConvertNode( graphHarris, input_rgb_image, harris_yuv_image ), // vxChannelExtractNode( graphHarris, /* Fill in parameter */, VX_CHANNEL_Y, harris_luma_image ), // vxGaussianPyramidNode( graphHarris, /* Fill in parameter */, currentPyramid ), // vxHarrisCornersNode( graphHarris, /* Fill in missing parameters */, currentKeypoints, NULL ) // }; // for( vx_size i = 0; i < sizeof( nodesHarris ) / sizeof( nodesHarris[0] ); i++ ) // { // ERROR_CHECK_OBJECT( nodesHarris[i] ); // ERROR_CHECK_STATUS( vxReleaseNode( &nodesHarris[i] ) ); // } // ERROR_CHECK_STATUS( vxReleaseImage( &harris_yuv_image ) ); // ERROR_CHECK_STATUS( vxReleaseImage( &harris_luma_image ) ); // ERROR_CHECK_STATUS( vxVerifyGraph( /* Fill in parameter */ ) ); ////////******** // Now, build a graph that performs pyramid computation and feature // tracking using optical flow. // // TODO STEP 07:******** // 1. Use vxColorConvertNode and vxChannelExtractNode APIs to get a gray // scale image for Harris and Pyramid computation from the input // RGB image. Add these nodes into Harris graph. // We gave the code in comments for color convert node; do similar // one for the channel extract node. // 2. Use vxGaussianPyramidNode API to add pyramid computation node. // You need to use the current pyramid from the pyramid delay object. // Most of the code is given in the comments; fill in the missing parameter. // 3. Use vxOpticalFlowPyrLKNode API to add an optical flow node. You need to // use the current and previous keypoints from the keypoints delay object. // Fill in the missing parameters in commented code. // 4. Use ERROR_CHECK_OBJECT to check proper creation of objects. // 5. Release node and virtual objects immediately since the graph // retains references to them. // 6. Call vxVerifyGraph to check for any errors in the graph. // Fill in the missing parameter in commented code. // vx_node nodesTrack[] = // { // vxColorConvertNode( graphTrack, input_rgb_image, opticalflow_yuv_image ), // vxChannelExtractNode( graphTrack, /* Fill in parameters */ ), // vxGaussianPyramidNode( graphTrack, /* Fill in parameter */, currentPyramid ), // vxOpticalFlowPyrLKNode( graphTrack, /* Fill in parameters */ ) // }; // for( vx_size i = 0; i < sizeof( nodesTrack ) / sizeof( nodesTrack[0] ); i++ ) // { // ERROR_CHECK_OBJECT( nodesTrack[i] ); // ERROR_CHECK_STATUS( vxReleaseNode( &nodesTrack[i] ) ); // } // ERROR_CHECK_STATUS( vxReleaseImage( &opticalflow_yuv_image ) ); // ERROR_CHECK_STATUS( vxReleaseImage( &opticalflow_luma_image ) ); // ERROR_CHECK_STATUS( vxVerifyGraph( /* Fill in parameter */ ) ); //////// // Process the video sequence frame by frame until the end of sequence or aborted. for( int frame_index = 0; !gui.AbortRequested(); frame_index++ ) { //////// // Copy the input RGB frame from OpenCV to OpenVX. // In order to do this, you need to use vxAccessImagePatch and vxCommitImagePatch APIs. // See "VX/vx_api.h" for the description of these APIs. vx_rectangle_t cv_rgb_image_region; cv_rgb_image_region.start_x = 0; cv_rgb_image_region.start_y = 0; cv_rgb_image_region.end_x = width; cv_rgb_image_region.end_y = height; vx_imagepatch_addressing_t cv_rgb_image_layout; cv_rgb_image_layout.stride_x = 3; cv_rgb_image_layout.stride_y = gui.GetStride(); vx_uint8 * cv_rgb_image_buffer = gui.GetBuffer(); ERROR_CHECK_STATUS( vxAccessImagePatch( input_rgb_image, &cv_rgb_image_region, 0, &cv_rgb_image_layout, ( void ** )&cv_rgb_image_buffer, VX_WRITE_ONLY ) ); ERROR_CHECK_STATUS( vxCommitImagePatch( input_rgb_image, &cv_rgb_image_region, 0, &cv_rgb_image_layout, cv_rgb_image_buffer ) ); ////////******** // Now that input RGB image is ready, just run a graph. // Run Harris at the beginning to initialize the previous keypoints. // // TODO STEP 08:******** // 1. Run a graph using vxProcessGraph API. Select Harris graph // if the frame_index == 0 (i.e., the first frame of the video // sequence), otherwise, select the feature tracking graph. // 2. Use ERROR_CHECK_STATUS for error checking. ////////******** // To mark the keypoints in display, you need to access the output // keypoint array and draw each item on the output window using gui.DrawArrow(). // // TODO STEP 09:******** // 1. Use vxGetReferenceFromDelay API to get the current and previous // keypoints array objects from the keypoints delay object. // Make sure to typecast the vx_reference object to vx_array. // We gave one for the previous previous keypoint array in comments; // do a similar one for the current keypoint array. // 2. OpenVX array object has an attribute that keeps the current // number of items in the array. The name of the attribute is // VX_ARRAY_ATTRIBUTE_NUMITEMS and its value is of type vx_size. // Use vxQueryArray API to get number of keypoints in the // current keypoint array data object, representing number of // corners detected in the input RGB image. // IMPORTANT: Read number of items into "num_corners" // because this variable is displayed by code segment below. // We gave most part of this statement in comment; just fill in the // missing parameter. // 3. The data items in output keypoint array are of type // vx_keypoint_t (see "VX/vx_types.h"). To access the array // buffer, use vxAccessArrayRange with start index = 0, // end index = number of items in the array, and usage mode = // VX_READ_ONLY. Note that the stride returned by this access // call is not guaranteed to be sizeof(vx_keypoint_t). // Also make sure that num_corners is > 0, because // vxAccessArrayRange expects end index > 0. // We gave the code for previous keypoint array in comment; // do similar one for the current keypoint array. // 4. For each item in the keypoint buffer, use vxArrayItem to // access an individual keypoint and draw a marker at (x,y) // using gui.DrawArrow() if tracking_status field of keypoint // is non-zero. Also count number of keypoints with // non-zero tracking_status into "num_tracking" variable. // We gave most of the code; fill in the missing parameters and uncomment. // 5. Hand the control of output keypoint buffer over back to // OpenVX framework by calling vxCommitArrayRange API. // We gave the code for previous keypoint array in comment; // do similar one for the current keypoint array. // 6. Use ERROR_CHECK_STATUS for error checking. vx_size num_corners = 0, num_tracking = 0; // previousKeypoints = ( vx_array )vxGetReferenceFromDelay( keypointsDelay, -1 ); // currentKeypoints = ( vx_array )vxGetReferenceFromDelay( /* Fill in parameters */ ); // ERROR_CHECK_OBJECT( currentKeypoints ); // ERROR_CHECK_OBJECT( previousKeypoints ); // ERROR_CHECK_STATUS( vxQueryArray( previousKeypoints, /* Fill in parameter */, &num_corners, sizeof( num_corners ) ) ); if( num_corners > 0 ) { vx_size kp_old_stride, kp_new_stride; vx_keypoint_t * kp_old_buf = NULL, * kp_new_buf = NULL; // ERROR_CHECK_STATUS( vxAccessArrayRange( previousKeypoints, 0, num_corners, // &kp_old_stride, ( void ** ) &kp_old_buf, VX_READ_ONLY ) ); // ERROR_CHECK_STATUS( vxAccessArrayRange( /* Fill in parameters */ ); for( vx_size i = 0; i < num_corners; i++ ) { // vx_keypoint_t * kp_old = &vxArrayItem( vx_keypoint_t, kp_old_buf, i, kp_old_stride ); // vx_keypoint_t * kp_new = &vxArrayItem( /* Fill in parameters */ ); // if( kp_new->tracking_status ) // { // num_tracking++; // gui.DrawArrow( kp_old->x, kp_old->y, kp_new->x, kp_new->y ); // } } // ERROR_CHECK_STATUS( vxCommitArrayRange( previousKeypoints, 0, num_corners, kp_old_buf ) ); // ERROR_CHECK_STATUS( vxCommitArrayRange( /* Fill in parameters */ ) ); } ////////******** // Flip the current and previous pyramid and keypoints in the delay objects. // // TODO STEP 10:******** // 1. Use vxAgeDelay API to flip the current and previous buffers in delay objects. // You need to call vxAgeDelay for both two delay objects. // 2. Use ERROR_CHECK_STATUS for error checking. // ERROR_CHECK_STATUS( vxAgeDelay( /* Fill in parameter */ ) ); // ERROR_CHECK_STATUS( vxAgeDelay( /* Fill in parameter */ ) ); //////// // Display the results and grab the next input RGB frame for the next iteration. char text[128]; sprintf( text, "Keyboard ESC/Q-Quit SPACE-Pause [FRAME %d]", frame_index ); gui.DrawText( 0, 16, text ); sprintf( text, "Number of Corners: %d [tracking %d]", ( int )num_corners, ( int )num_tracking ); gui.DrawText( 0, 36, text ); gui.Show(); if( !gui.Grab() ) { // Terminate the processing loop if the end of sequence is detected. gui.WaitForKey(); break; } } ////////******** // Query graph performance using VX_GRAPH_ATTRIBUTE_PERFORMANCE and print timing // in milliseconds. Note that time units of vx_perf_t fields are nanoseconds. // // TODO STEP 11:******** // 1. Use vxQueryGraph API with VX_GRAPH_ATTRIBUTE_PERFORMANCE to query graph performance. // We gave the attribute query for one graph in comments. Do the same for the second graph. // 2. Print the average and min execution times in milliseconds. Use the printf in comments. // vx_perf_t perfHarris = { 0 }, perfTrack = { 0 }; // ERROR_CHECK_STATUS( vxQueryGraph( graphHarris, VX_GRAPH_ATTRIBUTE_PERFORMANCE, &perfHarris, sizeof( perfHarris ) ) ); // ERROR_CHECK_STATUS( vxQueryGraph( /* Fill in parameters here for get performance of the other graph */ ); // printf( "GraphName NumFrames Avg(ms) Min(ms)\n" // "Harris %9d %7.3f %7.3f\n" // "Track %9d %7.3f %7.3f\n", // ( int )perfHarris.num, ( float )perfHarris.avg * 1e-6f, ( float )perfHarris.min * 1e-6f, // ( int )perfTrack.num, ( float )perfTrack.avg * 1e-6f, ( float )perfTrack.min * 1e-6f ); ////////******** // Release all the OpenVX objects created in this exercise, and make the context as the last one to release. // To release an OpenVX object, you need to call vxRelease<Object> API which takes a pointer to the object. // If the release operation is successful, the OpenVX framework will reset the object to NULL. // // TODO STEP 12:******** // 1. For releasing all other objects use vxRelease<Object> APIs. // You have to release 2 graph objects, 1 image object, 2 delay objects, // 6 scalar objects, and 1 context object. // 2. Use ERROR_CHECK_STATUS for error checking. // ERROR_CHECK_STATUS( vxReleaseContext( &context ) ); return 0; }
// nodeless version of the Convolve kernel vx_status vxConvolve(vx_image src, vx_convolution conv, vx_image dst, vx_border_mode_t *bordermode) { vx_int32 y, x, i; void *src_base = NULL; void *dst_base = NULL; vx_imagepatch_addressing_t src_addr, dst_addr; vx_rectangle_t rect; vx_size conv_width, conv_height; vx_int32 conv_radius_x, conv_radius_y; vx_int16 conv_mat[C_MAX_CONVOLUTION_DIM * C_MAX_CONVOLUTION_DIM] = {0}; vx_int32 sum = 0, value = 0; vx_uint32 scale = 1; vx_df_image src_format = 0; vx_df_image dst_format = 0; vx_status status = VX_SUCCESS; vx_int32 low_x, low_y, high_x, high_y; status |= vxQueryImage(src, VX_IMAGE_ATTRIBUTE_FORMAT, &src_format, sizeof(src_format)); status |= vxQueryImage(dst, VX_IMAGE_ATTRIBUTE_FORMAT, &dst_format, sizeof(dst_format)); status |= vxQueryConvolution(conv, VX_CONVOLUTION_ATTRIBUTE_COLUMNS, &conv_width, sizeof(conv_width)); status |= vxQueryConvolution(conv, VX_CONVOLUTION_ATTRIBUTE_ROWS, &conv_height, sizeof(conv_height)); status |= vxQueryConvolution(conv, VX_CONVOLUTION_ATTRIBUTE_SCALE, &scale, sizeof(scale)); conv_radius_x = (vx_int32)conv_width / 2; conv_radius_y = (vx_int32)conv_height / 2; status |= vxReadConvolutionCoefficients(conv, conv_mat); status |= vxGetValidRegionImage(src, &rect); status |= vxAccessImagePatch(src, &rect, 0, &src_addr, &src_base, VX_READ_ONLY); status |= vxAccessImagePatch(dst, &rect, 0, &dst_addr, &dst_base, VX_WRITE_ONLY); if (bordermode->mode == VX_BORDER_MODE_UNDEFINED) { low_x = conv_radius_x; high_x = ((src_addr.dim_x >= (vx_uint32)conv_radius_x) ? src_addr.dim_x - conv_radius_x : 0); low_y = conv_radius_y; high_y = ((src_addr.dim_y >= (vx_uint32)conv_radius_y) ? src_addr.dim_y - conv_radius_y : 0); vxAlterRectangle(&rect, conv_radius_x, conv_radius_y, -conv_radius_x, -conv_radius_y); } else { low_x = 0; high_x = src_addr.dim_x; low_y = 0; high_y = src_addr.dim_y; } for (y = low_y; y < high_y; ++y) { for (x = low_x; x < high_x; ++x) { sum = 0; if (src_format == VX_DF_IMAGE_U8) { vx_uint8 slice[C_MAX_CONVOLUTION_DIM * C_MAX_CONVOLUTION_DIM] = {0}; vxReadRectangle(src_base, &src_addr, bordermode, src_format, x, y, conv_radius_x, conv_radius_y, slice); for (i = 0; i < conv_width * conv_height; ++i) sum += conv_mat[conv_width * conv_height - 1 - i] * slice[i]; } else if (src_format == VX_DF_IMAGE_S16) { vx_int16 slice[C_MAX_CONVOLUTION_DIM * C_MAX_CONVOLUTION_DIM] = {0}; vxReadRectangle(src_base, &src_addr, bordermode, src_format, x, y, conv_radius_x, conv_radius_y, slice); for (i = 0; i < conv_width * conv_height; ++i) sum += conv_mat[conv_width * conv_height - 1 - i] * slice[i]; } value = sum / (vx_int32) scale; if (dst_format == VX_DF_IMAGE_U8) { vx_uint8 *dstp = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); if (value < 0) *dstp = 0; else if (value > UINT8_MAX) *dstp = UINT8_MAX; else *dstp = value; } else if (dst_format == VX_DF_IMAGE_S16) { vx_int16 *dstp = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); if (value < INT16_MIN) *dstp = INT16_MIN; else if (value > INT16_MAX) *dstp = INT16_MAX; else *dstp = value; } } } status |= vxCommitImagePatch(src, NULL, 0, &src_addr, src_base); status |= vxCommitImagePatch(dst, &rect, 0, &dst_addr, dst_base); return status; }
static vx_status vxChannelCombineKernel(vx_node node, vx_reference *parameters, vx_uint32 num) { vx_status status = VX_FAILURE; if (num == 5) { vx_image inputs[4] = { (vx_image)parameters[0], (vx_image)parameters[1], (vx_image)parameters[2], (vx_image)parameters[3], }; vx_image output = (vx_image)parameters[4]; vx_fourcc format = 0; vx_rectangle rect; vxQueryImage(output, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format)); rect = vxGetValidRegionImage(inputs[0]); if ((format == FOURCC_RGB) || (format == FOURCC_RGBX)) { /* write all the channels back out in interleaved format */ vx_imagepatch_addressing_t src_addrs[4]; vx_imagepatch_addressing_t dst_addr; void *base_src_ptrs[4] = {NULL, NULL, NULL, NULL}; void *base_dst_ptr = NULL; uint32_t x, y, p; uint32_t numplanes = 3; if (format == FOURCC_RGBX) { numplanes = 4; } // get the planes for (p = 0; p < numplanes; p++) { vxAccessImagePatch(inputs[p], rect, 0, &src_addrs[p], &base_src_ptrs[p]); } vxAccessImagePatch(output, rect, 0, &dst_addr, &base_dst_ptr); for (y = 0; y < dst_addr.dim_y; y+=dst_addr.step_y) { for (x = 0; x < dst_addr.dim_x; x+=dst_addr.step_x) { uint8_t *planes[4] = { vxFormatImagePatchAddress2d(base_src_ptrs[0], x, y, &src_addrs[0]), vxFormatImagePatchAddress2d(base_src_ptrs[1], x, y, &src_addrs[1]), vxFormatImagePatchAddress2d(base_src_ptrs[2], x, y, &src_addrs[2]), NULL, }; uint8_t *dst = vxFormatImagePatchAddress2d(base_dst_ptr, x, y, &dst_addr); dst[0] = planes[0][0]; dst[1] = planes[1][0]; dst[2] = planes[2][0]; if (format == FOURCC_RGBX) { planes[3] = vxFormatImagePatchAddress2d(base_src_ptrs[3], x, y, &src_addrs[3]); dst[3] = planes[3][0]; } } } // write the data back vxCommitImagePatch(output, rect, 0, &dst_addr, base_dst_ptr); // release the planes for (p = 0; p < numplanes; p++) { vxCommitImagePatch(inputs[p], 0, 0, &src_addrs[p], &base_src_ptrs[p]); } } else if (format == FOURCC_YUV4) { /* write all the channels back out in the planar format */ vx_imagepatch_addressing_t src_addrs[3]; vx_imagepatch_addressing_t dst_addrs[3]; void *base_src_ptrs[3] = {NULL, NULL, NULL}; void *base_dst_ptrs[3] = {NULL, NULL, NULL}; uint32_t x, y, p; // get the planes for (p = 0; p < 3; p++) { vxAccessImagePatch(inputs[p], rect, 0, &src_addrs[p], &base_src_ptrs[p]); vxAccessImagePatch(output, rect, 0, &dst_addrs[p], &base_dst_ptrs[p]); } for (y = 0; y < dst_addrs[0].dim_y; y+=dst_addrs[0].step_y) { for (x = 0; x < dst_addrs[0].dim_x; x+=dst_addrs[0].step_x) { uint8_t *planes[3] = { vxFormatImagePatchAddress2d(base_src_ptrs[0], x, y, &src_addrs[0]), vxFormatImagePatchAddress2d(base_src_ptrs[1], x, y, &src_addrs[1]), vxFormatImagePatchAddress2d(base_src_ptrs[2], x, y, &src_addrs[2]), }; uint8_t *dsts[3] = { vxFormatImagePatchAddress2d(base_dst_ptrs[0], x, y, &dst_addrs[0]), vxFormatImagePatchAddress2d(base_dst_ptrs[0], x, y, &dst_addrs[0]), vxFormatImagePatchAddress2d(base_dst_ptrs[0], x, y, &dst_addrs[0]), }; dsts[0][0] = planes[0][0]; dsts[1][0] = planes[1][0]; dsts[2][0] = planes[2][0]; } } // release the planes for (p = 0; p < 3; p++) { // write the data back vxCommitImagePatch(output, rect, 0, &dst_addrs[p], base_dst_ptrs[p]); // release the input vxCommitImagePatch(inputs[p], 0, 0, &src_addrs[p], &base_src_ptrs[p]); } } vxReleaseRectangle(&rect); status = VX_SUCCESS; } else status = VX_ERROR_INVALID_PARAMETERS; return status; }
static vx_status vxEqualizeHistKernel(vx_node node, vx_reference *parameters, vx_uint32 num) { vx_status status = VX_FAILURE; if (num == 2) { vx_image src = (vx_image)parameters[0]; vx_image dst = (vx_image)parameters[1]; vx_uint32 y, x, width = 0, height = 0; void *src_base = NULL; void *dst_base = NULL; vx_imagepatch_addressing_t src_addr, dst_addr; vx_rectangle rect; status = VX_SUCCESS; status |= vxQueryImage(src, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width)); status |= vxQueryImage(src, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height)); rect = vxCreateRectangle(vxGetContext(node), 0, 0, width, height); status |= vxAccessImagePatch(src, rect, 0, &src_addr, &src_base); status |= vxAccessImagePatch(dst, rect, 0, &dst_addr, &dst_base); if (status == VX_SUCCESS) { /* for 16-bit support (U16 or S16), the code can be duplicated with NUM_BINS = 65536 and PIXEL = vx_uint16. */ #define NUM_BINS 256 /* allocate a fixed-size temp array to store the image histogram & cumulative distribution */ vx_uint32 hist[NUM_BINS]; vx_uint32 cdf[NUM_BINS]; vx_uint32 sum = 0; vx_uint32 maxVal = 0; vx_float32 scaleFactor = 0.0f; /* calculate the distribution (histogram) */ memset(hist, 0, sizeof(hist)); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { vx_uint8 *src_ptr = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint8 pixel = *src_ptr; hist[pixel]++; } } /* calculate the cumulative distribution (summed histogram) */ for (x = 0; x < NUM_BINS; x++) { cdf[x] = sum; sum += hist[x]; } /* find the scale factor from the max cdf value */ maxVal = cdf[0]; for (x = 1; x < NUM_BINS; x++) { if (maxVal < cdf[x]) { maxVal = cdf[x]; } } scaleFactor = 255.0f / (float)maxVal; //printf("* maxVal = %d, scaleFactor = %f\n", maxVal, scaleFactor); /* map the src pixel values to the equalized pixel values */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { vx_uint8 *src_ptr = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint8 *dst_ptr = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); vx_uint32 equalized_int = cdf[(*src_ptr)]; *dst_ptr = (vx_uint8)(equalized_int * scaleFactor + 0.5f); } } } status |= vxCommitImagePatch(src, 0, 0, &src_addr, src_base); status |= vxCommitImagePatch(dst, rect, 0, &dst_addr, dst_base); vxReleaseRectangle(&rect); } return status; }
static vx_status vxHistogramKernel(vx_node node, vx_reference *parameters, vx_uint32 num) { vx_status status = VX_FAILURE; if (num == 2) { vx_image src_image = (vx_image)parameters[0]; vx_distribution dist = (vx_scalar)parameters[1]; vx_rectangle src_rect; vx_imagepatch_addressing_t src_addr; void *src_base = NULL, *dist_ptr = NULL; vx_fourcc format = 0; vx_uint32 y = 0, x = 0; vx_uint32 offset = 0, range = 0, numBins = 0, window_size = 0; vxQueryImage(src_image, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format)); vxQueryDistribution(dist, VX_DISTRIBUTION_ATTRIBUTE_BINS, &numBins, sizeof(numBins)); vxQueryDistribution(dist, VX_DISTRIBUTION_ATTRIBUTE_RANGE, &range, sizeof(range)); vxQueryDistribution(dist, VX_DISTRIBUTION_ATTRIBUTE_OFFSET, &offset, sizeof(offset)); vxQueryDistribution(dist, VX_DISTRIBUTION_ATTRIBUTE_WINDOW, &window_size, sizeof(window_size)); src_rect = vxGetValidRegionImage(src_image); status = VX_SUCCESS; status |= vxAccessImagePatch(src_image, src_rect, 0, &src_addr, &src_base); status |= vxAccessDistribution(dist, &dist_ptr); printf("distribution:%p bins:%u off:%u ws:%u range:%u\n", dist_ptr, numBins, offset, window_size, range); if (status == VX_SUCCESS) { vx_int32 *dist_tmp = dist_ptr; /* clear the distribution */ for (x = 0; x < numBins; x++) { dist_tmp[x] = 0; } for (y = 0; y < src_addr.dim_y; y++) { for (x = 0; x < src_addr.dim_x; x++) { if (format == FOURCC_U8) { vx_uint8 *src_ptr = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint8 pixel = *src_ptr; if ((offset <= (vx_size)pixel) && ((vx_size)pixel < (offset+range))) { vx_size index = (pixel - (vx_uint16)offset) / window_size; dist_tmp[index]++; } } else if (format == FOURCC_U16) { vx_uint16 *src_ptr = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint16 pixel = *src_ptr; if ((offset <= (vx_size)pixel) && ((vx_size)pixel < (offset+range))) { vx_size index = (pixel - (vx_uint16)offset) / window_size; dist_tmp[index]++; } } } } } status |= vxCommitDistribution(dist, dist_ptr); status |= vxCommitImagePatch(src_image, 0, 0, &src_addr, src_base); vxReleaseParameter(&src_rect); } return status; }
vx_status vxFReadImage(vx_array file, vx_image output) { vx_char *filename = NULL; vx_size filename_stride = 0; vx_uint8 *src = NULL; vx_uint32 p = 0u, y = 0u; vx_size planes = 0u; vx_imagepatch_addressing_t addr = {0}; vx_df_image format = VX_DF_IMAGE_VIRT; FILE *fp = NULL; vx_char tmp[VX_MAX_FILE_NAME] = {0}; vx_char *ext = NULL; vx_rectangle_t rect; vx_uint32 width = 0, height = 0; vx_status status = vxAccessArrayRange(file, 0, VX_MAX_FILE_NAME, &filename_stride, (void **)&filename, VX_READ_ONLY); if (status != VX_SUCCESS || filename_stride != sizeof(vx_char)) { vxAddLogEntry((vx_reference)file, VX_FAILURE, "Incorrect array "VX_FMT_REF"\n", file); return VX_FAILURE; } fp = fopen(filename, "rb"); if (fp == NULL) { vxAddLogEntry((vx_reference)file, VX_FAILURE, "Failed to open file %s\n",filename); return VX_FAILURE; } vxQueryImage(output, VX_IMAGE_PLANES, &planes, sizeof(planes)); vxQueryImage(output, VX_IMAGE_FORMAT, &format, sizeof(format)); ext = strrchr(filename, '.'); if (ext && (strcmp(ext, ".pgm") == 0 || strcmp(ext, ".PGM") == 0)) { FGETS(tmp, fp); // PX FGETS(tmp, fp); // comment FGETS(tmp, fp); // W H sscanf(tmp, "%u %u", &width, &height); FGETS(tmp, fp); // BPP // ! \todo double check image size? } else if (ext && (strcmp(ext, ".yuv") == 0 || strcmp(ext, ".rgb") == 0 || strcmp(ext, ".bw") == 0)) { sscanf(filename, "%*[^_]_%ux%u_%*s", &width, &height); } rect.start_x = rect.start_y = 0; rect.end_x = width; rect.end_y = height; for (p = 0; p < planes; p++) { status = vxAccessImagePatch(output, &rect, p, &addr, (void **)&src, VX_WRITE_ONLY); if (status == VX_SUCCESS) { for (y = 0; y < addr.dim_y; y+=addr.step_y) { vx_uint8 *srcp = vxFormatImagePatchAddress2d(src, 0, y, &addr); vx_size len = ((addr.dim_x * addr.scale_x)/VX_SCALE_UNITY); vx_size rlen = fread(srcp, addr.stride_x, len, fp); if (rlen != len) { status = VX_FAILURE; break; } } if (status == VX_SUCCESS) { status = vxCommitImagePatch(output, &rect, p, &addr, src); } if (status != VX_SUCCESS) { break; } } /* src pointer should be made NULL , otherwise the first plane data gets over written. */ src = NULL; } fclose(fp); vxCommitArrayRange(file, 0, 0, filename); return status; }
// nodeless version of the Phase kernel vx_status vxPhase(vx_image grad_x, vx_image grad_y, vx_image output) { vx_uint32 x; vx_uint32 y; vx_df_image format = 0; vx_uint8* dst_base = NULL; void* src_base_x = NULL; void* src_base_y = NULL; vx_imagepatch_addressing_t src_addr_x; vx_imagepatch_addressing_t src_addr_y; vx_imagepatch_addressing_t dst_addr; vx_rectangle_t rect; vx_status status = VX_FAILURE; if (grad_x == 0 && grad_y == 0) return VX_ERROR_INVALID_PARAMETERS; status = VX_SUCCESS; status |= vxQueryImage(grad_x, VX_IMAGE_FORMAT, &format, sizeof(format)); status |= vxGetValidRegionImage(grad_x, &rect); status |= vxAccessImagePatch(grad_x, &rect, 0, &src_addr_x, &src_base_x, VX_READ_ONLY); status |= vxAccessImagePatch(grad_y, &rect, 0, &src_addr_y, &src_base_y, VX_READ_ONLY); status |= vxAccessImagePatch(output, &rect, 0, &dst_addr, (void **)&dst_base, VX_WRITE_ONLY); for (y = 0; y < dst_addr.dim_y; y++) { for (x = 0; x < dst_addr.dim_x; x++) { void* in_x = vxFormatImagePatchAddress2d(src_base_x, x, y, &src_addr_x); void* in_y = vxFormatImagePatchAddress2d(src_base_y, x, y, &src_addr_y); vx_uint8* dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); /* -M_PI to M_PI */ double val_x; double val_y; if (format == VX_DF_IMAGE_F32) { val_x = (double)(((vx_float32*)in_x)[0]); val_y = (double)(((vx_float32*)in_y)[0]); } else // VX_DF_IMAGE_S16 { val_x = (double)(((vx_int16*)in_x)[0]); val_y = (double)(((vx_int16*)in_y)[0]); } double arct = atan2(val_y,val_x); /* 0 - TAU */ double norm = arct; if (arct < 0.0f) { norm = VX_TAU + arct; } /* 0.0 - 1.0 */ norm = norm / VX_TAU; /* 0 - 255 */ *dst = (vx_uint8)((vx_uint32)(norm * 256u + 0.5) & 0xFFu); if (val_y != 0 || val_x != 0) { VX_PRINT(VX_ZONE_INFO, "atan2(%d,%d) = %lf [norm=%lf] dst=%02x\n", val_y, val_x, arct, norm, *dst); } } } status |= vxCommitImagePatch(grad_x, NULL, 0, &src_addr_x, src_base_x); status |= vxCommitImagePatch(grad_y, NULL, 0, &src_addr_y, src_base_y); status |= vxCommitImagePatch(output, &rect, 0, &dst_addr, dst_base); return status; }
vx_status vxFWriteImage(vx_image input, vx_array file) { vx_char *filename = NULL; vx_size filename_stride = 0; vx_uint8 *src[4] = {NULL, NULL, NULL, NULL}; vx_uint32 p, y, sx, ex, sy, ey, width, height; vx_size planes; vx_imagepatch_addressing_t addr[4]; vx_df_image format; FILE *fp = NULL; vx_char *ext = NULL; size_t wrote = 0ul; vx_rectangle_t rect; vx_status status = vxAccessArrayRange(file, 0, VX_MAX_FILE_NAME, &filename_stride, (void **)&filename, VX_READ_ONLY); if (status != VX_SUCCESS || filename_stride != sizeof(vx_char)) { vxCommitArrayRange(file, 0, 0, filename); vxAddLogEntry((vx_reference)file, VX_FAILURE, "Incorrect array "VX_FMT_REF"\n", file); return VX_FAILURE; } //VX_PRINT(VX_ZONE_INFO, "filename=%s\n",filename); fp = fopen(filename, "wb+"); if (fp == NULL) { vxCommitArrayRange(file, 0, 0, filename); vxAddLogEntry((vx_reference)file, VX_FAILURE, "Failed to open file %s\n",filename); return VX_FAILURE; } status |= vxQueryImage(input, VX_IMAGE_WIDTH, &width, sizeof(width)); status |= vxQueryImage(input, VX_IMAGE_HEIGHT, &height, sizeof(height)); status |= vxQueryImage(input, VX_IMAGE_PLANES, &planes, sizeof(planes)); status |= vxQueryImage(input, VX_IMAGE_FORMAT, &format, sizeof(format)); status |= vxGetValidRegionImage(input, &rect); sx = rect.start_x; sy = rect.start_y; ex = rect.end_x; ey = rect.end_y; ext = strrchr(filename, '.'); if (ext && (strcmp(ext, ".pgm") == 0 || strcmp(ext, ".PGM") == 0)) { fprintf(fp, "P5\n# %s\n",filename); fprintf(fp, "%u %u\n", width, height); if (format == VX_DF_IMAGE_U8) fprintf(fp, "255\n"); else if (format == VX_DF_IMAGE_S16) fprintf(fp, "65535\n"); else if (format == VX_DF_IMAGE_U16) fprintf(fp, "65535\n"); } for (p = 0u; p < planes; p++) { status |= vxAccessImagePatch(input, &rect, p, &addr[p], (void **)&src[p], VX_READ_ONLY); } for (p = 0u; (p < planes) && (status == VX_SUCCESS); p++) { size_t len = addr[p].stride_x * (addr[p].dim_x * addr[p].scale_x)/VX_SCALE_UNITY; for (y = 0u; y < height; y+=addr[p].step_y) { vx_uint32 i = 0; vx_uint8 *ptr = NULL; uint8_t value = 0u; if (y < sy || y >= ey) { for (i = 0; i < width; ++i) { wrote += fwrite(&value, sizeof(value), 1, fp); } continue; } for (i = 0; i < sx; ++i) wrote += fwrite(&value, sizeof(value), 1, fp); ptr = vxFormatImagePatchAddress2d(src[p], 0, y - sy, &addr[p]); wrote += fwrite(ptr, 1, len, fp); for (i = 0; i < width - ex; ++i) wrote += fwrite(&value, sizeof(value), 1, fp); } if (wrote == 0) { vxAddLogEntry((vx_reference)file, VX_FAILURE, "Failed to write to file!\n"); status = VX_FAILURE; break; } if (status == VX_FAILURE) { vxAddLogEntry((vx_reference)file, VX_FAILURE, "Failed to write image to file correctly\n"); break; } } for (p = 0u; p < planes; p++) { status |= vxCommitImagePatch(input, NULL, p, &addr[p], src[p]); } if (status != VX_SUCCESS) { vxAddLogEntry((vx_reference)file, VX_FAILURE, "Failed to write image to file correctly\n"); } fflush(fp); fclose(fp); if (vxCommitArrayRange(file, 0, 0, filename) != VX_SUCCESS) { vxAddLogEntry((vx_reference)file, VX_FAILURE, "Failed to release handle to filename array!\n"); } return status; }
static vx_status vxCheckImageKernel(vx_node node, vx_reference *parameters, vx_uint32 num) { vx_status status = VX_SUCCESS; if (num == 3) { vx_image image = (vx_image)parameters[0]; vx_scalar fill = (vx_scalar)parameters[1]; vx_scalar errs = (vx_scalar)parameters[2]; packed_value_u value; vx_uint32 planes = 0u, count = 0u, errors = 0u; vx_uint32 x = 0u, y = 0u, p = 0u; vx_int32 i = 0; vx_imagepatch_addressing_t addr; vx_rectangle rect; value.dword[0] = 0xDEADBEEF; vxAccessScalarValue(fill, &value.dword[0]); vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &planes, sizeof(planes)); rect = vxGetValidRegionImage(image); for (p = 0u; (p < planes) && (rect); p++) { void *ptr = NULL; status = vxAccessImagePatch(image, rect, p, &addr, &ptr); if ((status == VX_SUCCESS) && (ptr)) { for (y = 0; y < addr.dim_y; y+=addr.step_y) { for (x = 0; x < addr.dim_x; x+=addr.step_x) { vx_uint8 *pixel = vxFormatImagePatchAddress2d(ptr, x, y, &addr); for (i = 0; i < addr.stride_x; i++) { count++; if (pixel[i] != value.bytes[i]) { errors++; } } } } if (errors > 0) { vxAddLogEntry(vxGetContext(node), VX_FAILURE, "Checked %p of %u sub-pixels with 0x%08x with %u errors\n", ptr, count, value.dword, errors); } vxCommitScalarValue(errs, &errors); status = vxCommitImagePatch(image, 0, p, &addr, ptr); if (status != VX_SUCCESS) { vxAddLogEntry(vxGetContext(node), VX_FAILURE, "Failed to set image patch for "VX_FMT_REF"\n", image); } } else { vxAddLogEntry(vxGetContext(node), VX_FAILURE, "Failed to get image patch for "VX_FMT_REF"\n", image); } } vxReleaseRectangle(&rect); if (errors > 0) { status = VX_FAILURE; } } return status; }
// nodeless version of the Fast9Corners kernel vx_status vxFast9Corners(vx_image src, vx_scalar sens, vx_scalar nonm, vx_array points, vx_scalar s_num_corners, vx_border_mode_t *bordermode) { vx_float32 b = 0.0f; vx_imagepatch_addressing_t src_addr; void *src_base = NULL; vx_rectangle_t rect; vx_uint8 tolerance = 0; vx_bool do_nonmax; vx_uint32 num_corners = 0; vx_size dst_capacity = 0; vx_keypoint_t kp; vx_status status = vxGetValidRegionImage(src, &rect); status |= vxReadScalarValue(sens, &b); status |= vxReadScalarValue(nonm, &do_nonmax); /* remove any pre-existing points */ status |= vxTruncateArray(points, 0); status |= vxAccessImagePatch(src, &rect, 0, &src_addr, &src_base, VX_READ_ONLY); tolerance = (vx_uint8)b; status |= vxQueryArray(points, VX_ARRAY_ATTRIBUTE_CAPACITY, &dst_capacity, sizeof(dst_capacity)); memset(&kp, 0, sizeof(kp)); if (status == VX_SUCCESS) { /*! \todo implement other Fast9 Corners border modes */ if (bordermode->mode == VX_BORDER_MODE_UNDEFINED) { vx_int32 y, x; for (y = APERTURE; y < (vx_int32)(src_addr.dim_y - APERTURE); y++) { for (x = APERTURE; x < (vx_int32)(src_addr.dim_x - APERTURE); x++) { vx_uint8 strength = vxGetFastCornerStrength(x, y, src_base, &src_addr, tolerance); if (strength > 0) { if (do_nonmax) { if (strength >= vxGetFastCornerStrength(x-1, y-1, src_base, &src_addr, tolerance) && strength >= vxGetFastCornerStrength(x, y-1, src_base, &src_addr, tolerance) && strength >= vxGetFastCornerStrength(x+1, y-1, src_base, &src_addr, tolerance) && strength >= vxGetFastCornerStrength(x-1, y, src_base, &src_addr, tolerance) && strength > vxGetFastCornerStrength(x+1, y, src_base, &src_addr, tolerance) && strength > vxGetFastCornerStrength(x-1, y+1, src_base, &src_addr, tolerance) && strength > vxGetFastCornerStrength(x, y+1, src_base, &src_addr, tolerance) && strength > vxGetFastCornerStrength(x+1, y+1, src_base, &src_addr, tolerance)) ; else continue; } if (num_corners < dst_capacity) { kp.x = x; kp.y = y; kp.strength = strength; status |= vxAddArrayItems(points, 1, &kp, 0); } num_corners++; } } } } else { status = VX_ERROR_NOT_IMPLEMENTED; } if (s_num_corners) status |= vxWriteScalarValue(s_num_corners, &num_corners); status |= vxCommitImagePatch(src, NULL, 0, &src_addr, src_base); } return status; }
// Compare rectangular region specified within an image and return number of pixels mismatching size_t CompareImage(vx_image image, vx_rectangle_t * rectRegion, vx_uint8 * refImage, float errLimitMin, float errLimitMax, int frameNumber, const char * fileNameRef) { // get number of planes, image format, and pixel type vx_df_image format = VX_DF_IMAGE_VIRT; vx_size num_planes = 0; vx_uint32 image_width = 0, image_height = 0; ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_WIDTH, &image_width, sizeof(image_width))); ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_HEIGHT, &image_height, sizeof(image_height))); ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &num_planes, sizeof(num_planes))); // set pixel type and compute frame size in bytes vx_enum pixelType = VX_TYPE_UINT8; // default if (format == VX_DF_IMAGE_S16) pixelType = VX_TYPE_INT16; else if (format == VX_DF_IMAGE_U16) pixelType = VX_TYPE_UINT16; else if (format == VX_DF_IMAGE_S32) pixelType = VX_TYPE_INT32; else if (format == VX_DF_IMAGE_U32) pixelType = VX_TYPE_UINT32; else if (format == VX_DF_IMAGE_F32_AMD || format == VX_DF_IMAGE_F32x3_AMD) pixelType = VX_TYPE_FLOAT32; // compare plane by plane vx_size errorPixelCountTotal = 0; vx_uint8 * pRefPlane = refImage; for (vx_uint32 plane = 0; plane < (vx_uint32)num_planes; plane++) { vx_imagepatch_addressing_t addr = { 0 }; vx_uint8 * base_ptr = nullptr; ERROR_CHECK(vxAccessImagePatch(image, rectRegion, plane, &addr, (void **)&base_ptr, VX_READ_ONLY)); vx_uint32 region_width = ((addr.dim_x * addr.scale_x) / VX_SCALE_UNITY); vx_uint32 region_height = (addr.dim_y * addr.scale_y) / VX_SCALE_UNITY; vx_uint32 plane_width = ((image_width * addr.scale_x) / VX_SCALE_UNITY); vx_uint32 plane_height = ((image_height * addr.scale_y) / VX_SCALE_UNITY); vx_uint32 plane_width_in_bytes = (format == VX_DF_IMAGE_U1_AMD) ? ((plane_width + 7) >> 3) : (plane_width * addr.stride_x); vx_uint32 start_x = ((rectRegion->start_x * addr.scale_x) / VX_SCALE_UNITY); vx_uint32 start_y = ((rectRegion->start_y * addr.scale_y) / VX_SCALE_UNITY); vx_uint8 * pRef = pRefPlane + start_y * plane_width_in_bytes + start_x * addr.stride_x; vx_size errorPixelCount = 0; if (pixelType == VX_TYPE_INT16) { errorPixelCount = ComparePixels((vx_int16 *)base_ptr, addr.stride_y, (vx_int16 *)pRef, plane_width_in_bytes, region_width, region_height, (vx_int32)errLimitMin, (vx_int32)errLimitMax); } else if (pixelType == VX_TYPE_UINT16) { errorPixelCount = ComparePixels((vx_uint16 *)base_ptr, addr.stride_y, (vx_uint16 *)pRef, plane_width_in_bytes, region_width, region_height, (vx_int32)errLimitMin, (vx_int32)errLimitMax); } else if (pixelType == VX_TYPE_INT32) { errorPixelCount = ComparePixels((vx_int32 *)base_ptr, addr.stride_y, (vx_int32 *)pRef, plane_width_in_bytes, region_width, region_height, (vx_int64)errLimitMin, (vx_int64)errLimitMax); } else if (pixelType == VX_TYPE_UINT32) { errorPixelCount = ComparePixels((vx_uint32 *)base_ptr, addr.stride_y, (vx_uint32 *)pRef, plane_width_in_bytes, region_width, region_height, (vx_int64)errLimitMin, (vx_int64)errLimitMax); } else if (pixelType == VX_TYPE_FLOAT32) { errorPixelCount = ComparePixels((vx_float32 *)base_ptr, addr.stride_y, (vx_float32 *)pRef, plane_width_in_bytes, region_width, region_height, (vx_float32)errLimitMin, (vx_float32)errLimitMax); } else if (format == VX_DF_IMAGE_U1_AMD) { errorPixelCount = ComparePixelsU001((vx_uint8 *)base_ptr, addr.stride_y, (vx_uint8 *)pRef, plane_width_in_bytes, region_width, region_height); } else { errorPixelCount = ComparePixels((vx_uint8 *)base_ptr, addr.stride_y, (vx_uint8 *)pRef, plane_width_in_bytes, region_width, region_height, (vx_int32)errLimitMin, (vx_int32)errLimitMax); } ERROR_CHECK(vxCommitImagePatch(image, rectRegion, plane, &addr, base_ptr)); // report results errorPixelCountTotal += errorPixelCount; if (errorPixelCount > 0) { char name[64]; vxGetReferenceName((vx_reference)image, name, sizeof(name)); printf("ERROR: Image COMPARE MISMATCHED %s plane#%d " VX_FMT_SIZE "-pixel(s) with frame#%d of %s\n", name, plane, errorPixelCount, frameNumber, fileNameRef ? fileNameRef : "???"); } // skip to begnning of next plane pRefPlane += plane_height * plane_width_in_bytes; } return errorPixelCountTotal; }
// nodeless version of the ConvertDepth kernel vx_status vxConvertDepth(vx_image input, vx_image output, vx_scalar spol, vx_scalar sshf) { vx_uint32 y, x; void *dst_base = NULL; void *src_base = NULL; vx_imagepatch_addressing_t dst_addr, src_addr; vx_rectangle_t rect; vx_enum format[2]; vx_enum policy = 0; vx_int32 shift = 0; vx_status status = VX_SUCCESS; status |= vxReadScalarValue(spol, &policy); status |= vxReadScalarValue(sshf, &shift); status |= vxQueryImage(input, VX_IMAGE_ATTRIBUTE_FORMAT, &format[0], sizeof(format[0])); status |= vxQueryImage(output, VX_IMAGE_ATTRIBUTE_FORMAT, &format[1], sizeof(format[1])); status |= vxGetValidRegionImage(input, &rect); status |= vxAccessImagePatch(input, &rect, 0, &src_addr, &src_base, VX_READ_ONLY); status |= vxAccessImagePatch(output, &rect, 0, &dst_addr, &dst_base, VX_WRITE_ONLY); for (y = 0; y < src_addr.dim_y; y++) { for (x = 0; x < src_addr.dim_x; x++) { if ((format[0] == VX_DF_IMAGE_U8) && (format[1] == VX_DF_IMAGE_U16)) { vx_uint8 *src = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint16 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = ((vx_uint16)(*src)) << shift; } else if ((format[0] == VX_DF_IMAGE_U8) && (format[1] == VX_DF_IMAGE_S16)) { vx_uint8 *src = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_int16 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = ((vx_int16)(*src)) << shift; } else if ((format[0] == VX_DF_IMAGE_U8) && (format[1] == VX_DF_IMAGE_U32)) { vx_uint8 *src = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint32 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = ((vx_uint32)(*src)) << shift; } else if ((format[0] == VX_DF_IMAGE_U16) && (format[1] == VX_DF_IMAGE_U32)) { vx_uint16 *src = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint32 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = ((vx_uint32)(*src)) << shift; } else if ((format[0] == VX_DF_IMAGE_S16) && (format[1] == VX_DF_IMAGE_S32)) { vx_int16 *src = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_int32 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); *dst = ((vx_int32)(*src)) << shift; } else if ((format[0] == VX_DF_IMAGE_U16) && (format[1] == VX_DF_IMAGE_U8)) { vx_uint16 *src = vxFormatImagePatchAddress2d(src_base, x, y, &src_addr); vx_uint8 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); if (policy == VX_CONVERT_POLICY_WRAP) { *dst = (vx_uint8)((*src) >> shift); } else if (policy == VX_CONVERT_POLICY_SATURATE) { vx_uint16 value = (*src) >> shift; value = (value > UINT8_MAX ? UINT8_MAX : value); *dst = (vx_uint8)value; }
static vx_status vxEdgeTrace(vx_image norm, vx_threshold threshold, vx_image output) { vx_rectangle_t rect; vx_imagepatch_addressing_t norm_addr, output_addr; void *norm_base = NULL, *output_base = NULL; vx_uint32 y = 0, x = 0; vx_int32 lower = 0, upper = 0; vx_status status = VX_SUCCESS; vxQueryThreshold(threshold, VX_THRESHOLD_ATTRIBUTE_THRESHOLD_LOWER, &lower, sizeof(lower)); vxQueryThreshold(threshold, VX_THRESHOLD_ATTRIBUTE_THRESHOLD_UPPER, &upper, sizeof(upper)); vxGetValidRegionImage(norm, &rect); status |= vxAccessImagePatch(norm, &rect, 0, &norm_addr, &norm_base, VX_READ_ONLY); status |= vxAccessImagePatch(output, &rect, 0, &output_addr, &output_base, VX_WRITE_ONLY); if (status == VX_SUCCESS) { const vx_uint8 NO = 0, MAYBE = 127, YES = 255; /* Initially we add all YES pixels to the stack. Later we only add MAYBE pixels to it, and we reset their state to YES afterwards; so we can never add the same pixel more than once. That means that the stack size is bounded by the image size. */ vx_uint32 (*tracing_stack)[2] = malloc(output_addr.dim_y * output_addr.dim_x * sizeof *tracing_stack); vx_uint32 (*stack_top)[2] = tracing_stack; for (y = 0; y < norm_addr.dim_y; y++) for (x = 0; x < norm_addr.dim_x; x++) { vx_uint16 *norm_ptr = vxFormatImagePatchAddress2d(norm_base, x, y, &norm_addr); vx_uint8 *output_ptr = vxFormatImagePatchAddress2d(output_base, x, y, &output_addr); if (*norm_ptr > upper) { *output_ptr = YES; (*stack_top)[0] = x; (*stack_top)[1] = y; ++stack_top; } else if (*norm_ptr <= lower) { *output_ptr = NO; } else { *output_ptr = MAYBE; } } while (stack_top != tracing_stack) { int i; --stack_top; x = (*stack_top)[0]; y = (*stack_top)[1]; for (i = 0; i < dimof(dir_offsets); ++i) { const struct offset_t offset = dir_offsets[i]; vx_uint32 new_x, new_y; vx_uint8 *output_ptr; if (x == 0 && offset.x < 0) continue; if (x == output_addr.dim_x - 1 && offset.x > 0) continue; if (y == 0 && offset.y < 0) continue; if (y == output_addr.dim_y - 1 && offset.y > 0) continue; new_x = x + offset.x; new_y = y + offset.y; output_ptr = vxFormatImagePatchAddress2d(output_base, new_x, new_y, &output_addr); if (*output_ptr != MAYBE) continue; *output_ptr = YES; (*stack_top)[0] = new_x; (*stack_top)[1] = new_y; ++stack_top; } } free(tracing_stack); for (y = 0; y < output_addr.dim_y; y++) for (x = 0; x < output_addr.dim_x; x++) { vx_uint8 *output_ptr = vxFormatImagePatchAddress2d(output_base, x, y, &output_addr); if (*output_ptr == MAYBE) *output_ptr = NO; } status |= vxCommitImagePatch(norm, 0, 0, &norm_addr, norm_base); status |= vxCommitImagePatch(output, &rect, 0, &output_addr, output_base); } return status; }
// nodeless version of NonLinearFilter kernel vx_status vxNonLinearFilter(vx_scalar function, vx_image src, vx_matrix mask, vx_image dst, vx_border_t *border) { vx_uint32 y, x; void *src_base = NULL; void *dst_base = NULL; vx_imagepatch_addressing_t src_addr, dst_addr; vx_rectangle_t rect; vx_uint32 low_x = 0, low_y = 0, high_x, high_y; vx_uint8 m[C_MAX_NONLINEAR_DIM * C_MAX_NONLINEAR_DIM]; vx_uint8 v[C_MAX_NONLINEAR_DIM * C_MAX_NONLINEAR_DIM]; vx_status status = vxGetValidRegionImage(src, &rect); status |= vxAccessImagePatch(src, &rect, 0, &src_addr, &src_base, VX_READ_ONLY); status |= vxAccessImagePatch(dst, &rect, 0, &dst_addr, &dst_base, VX_WRITE_ONLY); vx_enum func = 0; status |= vxCopyScalar(function, &func, VX_READ_ONLY, VX_MEMORY_TYPE_HOST); vx_size mrows, mcols; vx_enum mtype = 0; status |= vxQueryMatrix(mask, VX_MATRIX_ROWS, &mrows, sizeof(mrows)); status |= vxQueryMatrix(mask, VX_MATRIX_COLUMNS, &mcols, sizeof(mcols)); status |= vxQueryMatrix(mask, VX_MATRIX_TYPE, &mtype, sizeof(mtype)); vx_coordinates2d_t origin; status |= vxQueryMatrix(mask, VX_MATRIX_ORIGIN, &origin, sizeof(origin)); if ((mtype != VX_TYPE_UINT8) || (sizeof(m) < mrows * mcols)) status = VX_ERROR_INVALID_PARAMETERS; status |= vxCopyMatrix(mask, m, VX_READ_ONLY, VX_MEMORY_TYPE_HOST); if (status == VX_SUCCESS) { vx_size rx0 = origin.x; vx_size ry0 = origin.y; vx_size rx1 = mcols - origin.x - 1; vx_size ry1 = mrows - origin.y - 1; high_x = src_addr.dim_x; high_y = src_addr.dim_y; if (border->mode == VX_BORDER_UNDEFINED) { low_x += rx0; low_y += ry0; high_x -= rx1; high_y -= ry1; vxAlterRectangle(&rect, (vx_int32)rx0, (vx_int32)ry0, -(vx_int32)rx1, -(vx_int32)ry1); } for (y = low_y; y < high_y; y++) { for (x = low_x; x < high_x; x++) { vx_uint8 *dst = vxFormatImagePatchAddress2d(dst_base, x, y, &dst_addr); vx_int32 count = readMaskedRectangle_U8(src_base, &src_addr, border, VX_DF_IMAGE_U8, x, y, rx0, ry0, rx1, ry1, m, v); qsort(v, count, sizeof(vx_uint8), vx_uint8_compare); switch (func) { case VX_NONLINEAR_FILTER_MIN: *dst = v[0]; break; /* minimal value */ case VX_NONLINEAR_FILTER_MAX: *dst = v[count - 1]; break; /* maximum value */ case VX_NONLINEAR_FILTER_MEDIAN: *dst = v[count / 2]; break; /* pick the middle value */ } } } } status |= vxCommitImagePatch(src, NULL, 0, &src_addr, src_base); status |= vxCommitImagePatch(dst, &rect, 0, &dst_addr, dst_base); return status; }