This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDA4VM: Object Detection Application use IMX390

Part Number: TDA4VM

Dear Sir/madam,

Now I am using TDA4VMEVM.
There is "Object Detection Application" example for TDA4VMEVM.
But the "Object Detection Application" input data from NV12 files.
I want to replace input files with IMX390.
How can I use IMX390 as input data for "Object Detection Application"?
Is there IMX390 API that can capture video frame?
Is there any document that can reference for the problem?

Best regards

-Jason

  • Hi Jason,

    It is not single API, you need to integrate IMX390 sensor with the capture node and then use VISS node to convert capture output to YUV420. VISS node also requires other nodes, like AEWB. 

    Please refer to the single camera or multi camera examples. You could take capture -> VISS path from these example and then can feed the output object detection node. 

    Regards,

    Brijesh

  • Hi Brijesh,

    Thank you about your reply.
    Following your suggestion.
    I refer "Multi Camera VPAC Application".
    The configuration file of "Multi Camera VPAC Application" is app_multi_cam.cfg.
    The app_multi_cam.cfg have one item.
    # path to write the processed frames
    output_file_path /opt/vision_apps/app_cam_out

    The output of "Multi Camera VPAC Application" seem can to store.
    Am I right?

    If it is right,
    Can "Object Detection Application" feed from /opt/vision_apps/app_cam_out?

    "Multi Camera VPAC Application"(output) -> /opt/vision_apps/app_cam_out -> (input) "Object Detection Application"
    Is it OK?

    If it is OK.
    Can you guide me to setup app_multi_cam.cfg ?

    Best regards

    -Jason

  • Hi Jason,

    The output of the multi-cam example goes to the display, so we cannot directly connect to Object detection application? 

    You need to develop new example, where output of VISS goes as an input to Object detection example. 

    Regards,

    Brijesh

  • Hi Brijesh,

    Follow your suggestion.
    I want to modify multi-cam example.
    In order to get the output of VISS.
    But I can't find the output method of VISS from app_run_graph() (app_multi_cam/main.c).
    Could you give me suggestion about the output of VISS?
    Is there example code about the output of VISS?

    Best regards

    -Jason

  • Hi Jason,

    VISS output is stored in object array, obj->vissObj.output_arr. In the example, the output is give to either LDC or MSC. Can you please follow this code and add your algo code, instead of LDC/MSC? 

    Regards,

    Brijesh

  • Hi Brijesh,

    The app_multi_cam.cfg have a "en_out_viss_write" item.
    Does it mean to output VISS into files?
    I want to get VISS output by "en_out_viss_write".

    I tried to change "en_out_viss_write" as 1.
    I select only one IMX390 camera when interactive.

    mkdir /opt/vision_apps/app_cam_out
    source ./vision_apps_init.sh
    ./vx_app_multi_cam.out --cfg app_multi_cam.cfg

    But the DisplayPort0 hang.
    I can't find any files under output_file_path /opt/vision_apps/app_cam_out .

    Could you give me suggestion?

    The DisplayPort0 OK when "en_out_viss_write" is 0.
    So I don't think, it is camera problem.

    Best regards

    -Jason

  • Hi Jason,

    Do you want to save VISS output into a file? 

    Are you enabling VISS output in psdk_rtos_auto_j7_07_00_00_11\vision_apps\apps\basic_demos\app_multi_cam\config\app_multi_cam.cfg file? could you please check?

    Rgds,

    Brijesh

  • Hi Brijesh,

    Yes, I want to save VISS output into file.

    I always enable VISS output.

    Following is my app_multi_cam.cfg

    /*------------------------------------------*/

    # sensor selection
    # 0 : IMX390
    # 1 : AR0233
    # 2 : AR0820
    sensor_index 0

    # LDC 0-disable, 1-enable
    enable_ldc 0

    # Number of cameras enabled
    num_cameras_enabled 3

    # Number of frames to run
    num_frames_to_run 1000000

    # Show output in HDMI/eDP, 0-disable, 1-enable
    display_option 1

    # Supported usecase options 0, 1
    usecase_option 0

    # enable interactive mode 0-noninteractive, 1-interactive
    is_interactive 1

    # enable writing final output 0-disable, 1-enable
    en_out_img_write 0

    # enable writing csix output 0-disable, 1-enable
    en_out_capture_write 0

    # enable writing vis output 0-disable, 1-enable
    en_out_viss_write 1

    # enable writing ldc output 0-disable, 1-enable
    en_out_ldc_write 0

    # Number of frames to write per 's' command,
    num_frames_to_write 1

    # Number of frames to skip per 's' command, Eg. 0-no frame skip, 1-skip 1 frame, 2-skip 2 frames etc.
    num_frames_to_skip 0

    # path to write the processed frames
    output_file_path /opt/vision_apps/app_cam_out

    # Disable error detection by default
    enable_error_detection 0

    /*-------------------------------------------*/

    But the DisplayPort0 hang.
    I can't find any files under output_file_path /opt/vision_apps/app_cam_out .

    Best regards

    -Jason

  • Hi Brijesh,

    Is there any update about the problem?

    Can you duplicate the  error?

    Best regards

    -Jason

  • Hi Jason,

    Yes, please start new thread for the new question. 

    I am parallelly checking with the team. 

    Regards,

    Brijesh

  • Hi Brijesh,

    We are trying to run object detection on the camera feed from IMX390 similar to Jason here and we tried the process you mentioned above. Please find the design below. 

    Capture -> VISS -> LDC -> Scaler -> Preproc -> TIDL -> DrawDetections -> Mosaic -> Display

                                                     |                                                     ^

                                                     L __________________________|

    * Scaler is going to DrawDetections and Preproc.

    I am attaching a video of the output on the display. Can you help us rectify this error. Let me know if you need further information from me.

  • Hi Prithvi,

    I could not understand your graph, Is the scalar going to preprocess or to DrawDetection? What is Mosaic Node doing?

    Are you setting up parameters of the mosaic node correctly?

    If you just connect scalar output to Mosaic node, does it working fine? 

    I am not sure exactly where is the issue, but i am suspecting something to do with TIDL, DrawDetection Nodes. So can you just connect Scalar to Mosaic and confirm it is working fine?

    Regards,

    Brijesh

  • Hi Brijesh,

    One output of scalar is going to TIDL and the other output of scalar is going to DrawDetection. 

    I have taken the Mosaic node from tidl_od app and used it for our usecase. This node is a gray area for us since we do not completely understand the function of Mosaic node.

    When I connect the scalar to Mosaic and try to display the mosaic output image, the display shows one image, freezes after 1 frame, and the app crashes. I am unable to select the menu options after this.

    I am attaching the mosaic node files here. We are also adding add_graph_parameter_by_node_index as:

    if(status == VX_SUCCESS)
        {
            graph_parameter_index = 0;
            add_graph_parameter_by_node_index(obj->graph, obj->captureObj.node, 1);
            obj->captureObj.graph_parameter_index = graph_parameter_index;
            graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index;
            graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = APP_BUFFER_Q_DEPTH;
            graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference*)&obj->captureObj.raw_image_arr[0];
            graph_parameter_index++;
    
            add_graph_parameter_by_node_index(obj->graph, obj->postProcObj.node, 3);
            obj->postProcObj.graph_parameter_index = graph_parameter_index;
            graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index;
            graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = APP_BUFFER_Q_DEPTH;
            graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference*)&obj->postProcObj.results[0];
            graph_parameter_index++;
    		
    	add_graph_parameter_by_node_index(obj->graph, obj->imgMosaicObj.node, 2);
            obj->imgMosaicObj.graph_parameter_index = graph_parameter_index;
            graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index;
            graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = APP_BUFFER_Q_DEPTH;
            graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference*)&obj->imgMosaicObj.output_image[0];
            graph_parameter_index++;
    
            vxSetGraphScheduleConfig(obj->graph,
                    VX_GRAPH_SCHEDULE_MODE_QUEUE_AUTO,
                    graph_parameter_index,
                    graph_parameters_queue_params_list);
    
            tivxSetGraphPipelineDepth(obj->graph, APP_PIPELINE_DEPTH);
    
            tivxSetNodeParameterNumBufByIndex(obj->vissObj.node, 6, APP_BUFFER_Q_DEPTH);
            tivxSetNodeParameterNumBufByIndex(obj->vissObj.node, 9, APP_BUFFER_Q_DEPTH);
            tivxSetNodeParameterNumBufByIndex(obj->aewbObj.node, 4, APP_BUFFER_Q_DEPTH);
    
            tivxSetNodeParameterNumBufByIndex(obj->ldcObj.node, 7, APP_BUFFER_Q_DEPTH);
    
            /*This output is accessed slightly later in the pipeline by mosaic node so queue depth is larger */
            tivxSetNodeParameterNumBufByIndex(obj->scalerObj.node, 1, 6);
            tivxSetNodeParameterNumBufByIndex(obj->scalerObj.node, 2, 6);
    
            tivxSetNodeParameterNumBufByIndex(obj->preProcObj.node, 2, APP_BUFFER_Q_DEPTH);
    
            tivxSetNodeParameterNumBufByIndex(obj->tidlObj.node, 4, APP_BUFFER_Q_DEPTH);
            tivxSetNodeParameterNumBufByIndex(obj->tidlObj.node, 7, APP_BUFFER_Q_DEPTH);
    		
    		tivxSetNodeParameterNumBufByIndex(obj->drawDetectionsObj.node, 3, 2);
    
            tivxSetNodeParameterNumBufByIndex(obj->imgMosaicObj.node, 1, APP_BUFFER_Q_DEPTH);
    
            APP_PRINTF("Pipeline params setup done!\n");
    		printf("pipeline params graph done\n");
    

    Let me know if you need further information from me.

    /*
     *
     * Copyright (c) 2017 Texas Instruments Incorporated
     *
     * All rights reserved not granted herein.
     *
     * Limited License.
     *
     * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive
     * license under copyrights and patents it now or hereafter owns or controls to make,
     * have made, use, import, offer to sell and sell ("Utilize") this software subject to the
     * terms herein.  With respect to the foregoing patent license, such license is granted
     * solely to the extent that any such patent is necessary to Utilize the software alone.
     * The patent license shall not apply to any combinations which include this software,
     * other than combinations with devices manufactured by or for TI ("TI Devices").
     * No hardware patent is licensed hereunder.
     *
     * Redistributions must preserve existing copyright notices and reproduce this license
     * (including the above copyright notice and the disclaimer and (if applicable) source
     * code license limitations below) in the documentation and/or other materials provided
     * with the distribution
     *
     * Redistribution and use in binary form, without modification, are permitted provided
     * that the following conditions are met:
     *
     * *       No reverse engineering, decompilation, or disassembly of this software is
     * permitted with respect to any software provided in binary form.
     *
     * *       any redistribution and use are licensed by TI for use only with TI Devices.
     *
     * *       Nothing shall obligate TI to provide you with source code for the software
     * licensed and provided to you in object code.
     *
     * If software source code is provided to you, modification and redistribution of the
     * source code are permitted provided that the following conditions are met:
     *
     * *       any redistribution and use of the source code, including any resulting derivative
     * works, are licensed by TI for use only with TI Devices.
     *
     * *       any redistribution and use of any object code compiled from the source code
     * and any resulting derivative works, are licensed by TI for use only with TI Devices.
     *
     * Neither the name of Texas Instruments Incorporated nor the names of its suppliers
     *
     * may be used to endorse or promote products derived from this software without
     * specific prior written permission.
     *
     * DISCLAIMER.
     *
     * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     * OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    #include "app_img_mosaic_module.h"
    
    
    vx_status app_init_img_mosaic(vx_context context, ImgMosaicObj *imgMosaicObj, char *objName, vx_int32 bufq_depth)
    {
      vx_status status = VX_SUCCESS;
      vx_int32 i, q;
    
      imgMosaicObj->config = vxCreateUserDataObject(context, "ImgMosaicConfig", sizeof(tivxImgMosaicParams), NULL);
      status = vxGetStatus((vx_reference)imgMosaicObj->config);
    
      if(status == VX_SUCCESS)
      {
          status = vxCopyUserDataObject(imgMosaicObj->config, 0, sizeof(tivxImgMosaicParams),\
                    &imgMosaicObj->params, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
      }
    
      for(q = 0; q < bufq_depth; q++)
      {
        if(status == VX_SUCCESS)
        {
          imgMosaicObj->output_image[q] = vxCreateImage(context, imgMosaicObj->out_width, imgMosaicObj->out_height, VX_DF_IMAGE_NV12);
          status = vxGetStatus((vx_reference)imgMosaicObj->output_image[q]);
        }
      }
    
      if(status == VX_SUCCESS)
      {
          imgMosaicObj->kernel = tivxAddKernelImgMosaic(context, imgMosaicObj->num_inputs);
          status = vxGetStatus((vx_reference)imgMosaicObj->kernel);
      }
    
      for(i = 0; i < TIVX_IMG_MOSAIC_MAX_INPUTS; i++)
      {
        imgMosaicObj->input_arr[i] = NULL;
      }
    
      return status;
    }
    
    void app_deinit_img_mosaic(ImgMosaicObj *imgMosaicObj, vx_int32 bufq_depth)
    {
      vx_int32 q;
    
      vxReleaseUserDataObject(&imgMosaicObj->config);
      for(q = 0; q < bufq_depth; q++)
      {
        vxReleaseImage(&imgMosaicObj->output_image[q]);
      }
    
      return;
    }
    
    void app_delete_img_mosaic(ImgMosaicObj *imgMosaicObj)
    {
      if(imgMosaicObj->node != NULL)
      {
        vxReleaseNode(&imgMosaicObj->node);
      }
      if(imgMosaicObj->kernel != NULL)
      {
        vxRemoveKernel(imgMosaicObj->kernel);
      }
      return;
    }
    
    vx_status app_create_graph_img_mosaic(vx_graph graph, ImgMosaicObj *imgMosaicObj)
    {
    
      vx_status status = VX_SUCCESS;
    
      imgMosaicObj->node = tivxImgMosaicNode(graph,
                                             imgMosaicObj->kernel,
                                             imgMosaicObj->config,
                                             imgMosaicObj->output_image[0],
                                             imgMosaicObj->input_arr,
                                             imgMosaicObj->num_inputs);
    
      APP_ASSERT_VALID_REF(imgMosaicObj->node);
      #ifdef x86_64
      vxSetNodeTarget(imgMosaicObj->node, VX_TARGET_STRING, TIVX_TARGET_DSP1);
      #else
      vxSetNodeTarget(imgMosaicObj->node, VX_TARGET_STRING, TIVX_TARGET_VPAC_MSC1);
      #endif
      vxSetReferenceName((vx_reference)imgMosaicObj->node, "mosaic_node");
      status = vxGetStatus((vx_reference)imgMosaicObj->node);
      
      if(imgMosaicObj->en_out_imgmosaic_write == 1)
        {
    		printf("writing img mosaic output\n");
            APP_PRINTF("Adding image mosaic write node on graph .. \n");
            status = app_create_graph_imgmosaic_write_output(graph, imgMosaicObj);
            APP_PRINTF("Image mosaic write node added! \n");
        }
    
      return (status);
    
    }
    
    vx_status writeMosaicOutput(char* file_name, vx_image out_img)
    {
      vx_status status;
    
      status = vxGetStatus((vx_reference)out_img);
    
      if(status == VX_SUCCESS)
      {
        FILE * fp = fopen(file_name,"wb");
    
        if(fp == NULL)
        {
          printf("Unable to open file %s \n", file_name);
          return (VX_FAILURE);
        }
    
        {
          vx_rectangle_t rect;
          vx_imagepatch_addressing_t image_addr;
          vx_map_id map_id;
          void * data_ptr;
          vx_uint32  img_width;
          vx_uint32  img_height;
          vx_uint32  num_bytes;
    
          vxQueryImage(out_img, VX_IMAGE_WIDTH, &img_width, sizeof(vx_uint32));
          vxQueryImage(out_img, VX_IMAGE_HEIGHT, &img_height, sizeof(vx_uint32));
    
          rect.start_x = 0;
          rect.start_y = 0;
          rect.end_x = img_width;
          rect.end_y = img_height;
          status = vxMapImagePatch(out_img,
                                   &rect,
                                   0,
                                   &map_id,
                                   &image_addr,
                                   &data_ptr,
                                   VX_READ_ONLY,
                                   VX_MEMORY_TYPE_HOST,
                                   VX_NOGAP_X);
    
          //Copy Luma
          num_bytes = fwrite(data_ptr,1,img_width*img_height, fp);
    
          if(num_bytes != (img_width*img_height))
            printf("Luma bytes written = %d, expected = %d", num_bytes, img_width*img_height);
    
          vxUnmapImagePatch(out_img, map_id);
    
          status = vxMapImagePatch(out_img,
                                   &rect,
                                   1,
                                   &map_id,
                                   &image_addr,
                                   &data_ptr,
                                   VX_READ_ONLY,
                                   VX_MEMORY_TYPE_HOST,
                                   VX_NOGAP_X);
    
    
          //Copy CbCr
          num_bytes = fwrite(data_ptr,1,img_width*img_height/2, fp);
    
          if(num_bytes != (img_width*img_height/2))
            printf("CbCr bytes written = %d, expected = %d", num_bytes, img_width*img_height/2);
    
          vxUnmapImagePatch(out_img, map_id);
    
        }
    
        fclose(fp);
      }
    
      return(status);
    }
    
    
    vx_status app_create_graph_imgmosaic_write_output(vx_graph graph, ImgMosaicObj *imgMosaicObj)
    {
        vx_status status = VX_SUCCESS;
    
        vx_image output_img = imgMosaicObj->output_image[0];
    
        imgMosaicObj->write_node = tivxWriteImageNode(graph, output_img, imgMosaicObj->file_path, imgMosaicObj->file_prefix);
    	printf("img mosaic write node success\n");
        status = vxGetStatus((vx_reference)imgMosaicObj->write_node);
        vxSetNodeTarget(imgMosaicObj->write_node, VX_TARGET_STRING, TIVX_TARGET_A72_0);
        vxSetReferenceName((vx_reference)imgMosaicObj->write_node, "Image_Mosaic_Write_Node");
    
        vx_bool replicate[] = { vx_true_e, vx_false_e, vx_false_e};
        vxReplicateNode(graph, imgMosaicObj->write_node, replicate, 3);
    
        vxReleaseImage(&output_img);
    
        return (status);
    }
    
    vx_status app_send_cmd_imgmosaic_write_node(ImgMosaicObj *imgMosaicObj, vx_uint32 start_frame, vx_uint32 num_frames, vx_uint32 num_skip)
    {
        vx_status status = VX_SUCCESS;
    
        tivxFileIOWriteCmd write_cmd;
    
        write_cmd.start_frame = start_frame;
        write_cmd.num_frames = num_frames;
        write_cmd.num_skip = num_skip;
    
        status = vxCopyUserDataObject(imgMosaicObj->write_cmd, 0, sizeof(tivxFileIOWriteCmd),\
                      &write_cmd, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
    
        if(status == VX_SUCCESS)
        {
            vx_reference refs[2];
    
            refs[0] = (vx_reference)imgMosaicObj->write_cmd;
    
            status = tivxNodeSendCommand(imgMosaicObj->write_node, TIVX_CONTROL_CMD_SEND_TO_ALL_REPLICATED_NODES,
                                     TIVX_FILEIO_CMD_SET_FILE_WRITE,
                                     refs, 1u);
    
            if(VX_SUCCESS != status)
            {
                printf("Image Mosaic Node send command failed!\n");
            }
    
            APP_PRINTF("Image Mosaic node send command success!\n");
        }
    
        return (status);
    }
    
    vx_status clearImage(vx_image out_img)
    {
      vx_status status;
    
      status = vxGetStatus((vx_reference)out_img);
    
      if(status == VX_SUCCESS)
      {
        vx_rectangle_t rect;
        vx_imagepatch_addressing_t image_addr;
        vx_map_id map_id;
        void * data_ptr;
        vx_uint32  img_width;
        vx_uint32  img_height;
    
        vxQueryImage(out_img, VX_IMAGE_WIDTH, &img_width, sizeof(vx_uint32));
        vxQueryImage(out_img, VX_IMAGE_HEIGHT, &img_height, sizeof(vx_uint32));
    
        rect.start_x = 0;
        rect.start_y = 0;
        rect.end_x = img_width;
        rect.end_y = img_height;
        status = vxMapImagePatch(out_img,
                                 &rect,
                                 0,
                                 &map_id,
                                 &image_addr,
                                 &data_ptr,
                                 VX_WRITE_ONLY,
                                 VX_MEMORY_TYPE_HOST,
                                 VX_NOGAP_X);
    
        memset(data_ptr, 0, img_width * img_height);
    
        vxUnmapImagePatch(out_img, map_id);
    
        status = vxMapImagePatch(out_img,
                                 &rect,
                                 1,
                                 &map_id,
                                 &image_addr,
                                 &data_ptr,
                                 VX_WRITE_ONLY,
                                 VX_MEMORY_TYPE_HOST,
                                 VX_NOGAP_X);
    
        memset(data_ptr, 128, img_width*img_height/2);
    
        vxUnmapImagePatch(out_img, map_id);
    
      }
    
      return(status);
    }
    
    app_img_mosaic_module.h

  • Prithvi,

    Based on popular request I have put together a camera pipeline with app_tidl_od. Can you please check this thread? This will be part of next SDK release.