Program Listing for File xf_hog_descriptor_pm.hpp

Return to documentation for file (/tmp/ws/src/vitis_common/include/imgproc/xf_hog_descriptor_pm.hpp)

/*
 * Copyright 2019 Xilinx, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _XF_HOG_DESCRIPTOR_PM_HPP_
#define _XF_HOG_DESCRIPTOR_PM_HPP_

#ifndef __cplusplus
#error C++ is needed to include this header
#endif

#include "../core/xf_math.h"

// to convert the radians value to degrees
#define XF_NORM_FACTOR 58671 // (180/PI)  in  Q6.10

/***********************************************************************************************
 * xFHOGPhaseMagnitudeKernel : The Gradient Phase and Gradient magnitude Computation Kernel.
 *       This kernel takes two gradients in XF_9SP depth and computes the angles and magnitude
 *       for each pixel and store this in a XF_9UP images.
 *
 *  The Input arguments are _gradx_stream, _grady_stream
 *  _gradx_stream --> Gradient X data from the gradient computation function of
 *          depth XF_9SP.
 *  _grady_stream --> Gradient Y data from the gradient computation function of
 *          depth XF_9SP.
 *  _phase_stream --> phase computed image of depth XF_16UP.
 *  _mag_stream   --> magnitude computed image of depth XF_16UP.
 *
 *  Depending on NPC, 1 or 8 pixels are read and gradient values are calculated.
 **********************************************************************************************/
template <int ROWS,
          int COLS,
          int DEPTH_SRC,
          int DEPTH_DST,
          int NPC,
          int WORDWIDTH_SRC,
          int WORDWIDTH_DST,
          int COLS_TRIP>
void xFHOGPhaseMagnitudeKernel(hls::stream<XF_SNAME(WORDWIDTH_SRC)>& _gradx_stream,
                               hls::stream<XF_SNAME(WORDWIDTH_SRC)>& _grady_stream,
                               hls::stream<XF_SNAME(WORDWIDTH_DST)>& _phase_stream,
                               hls::stream<XF_SNAME(WORDWIDTH_DST)>& _mag_stream,
                               uint16_t height,
                               uint16_t width) {
    // Data in the packed format
    XF_SNAME(WORDWIDTH_SRC) grad_x_packed_val, grad_y_packed_val;
    XF_SNAME(WORDWIDTH_DST) phase_packed_val, mag_packed_val;

    // declaring the loop variables
    uint16_t i, j;
    uint16_t k, l;

    // VARIABLES FOR PHASE KERNEL
    // Fixed point format of x and y, x = QM1.N1, y = QM2.N2 // Q9.0 format input
    int M1, N1, M2, N2;
    M1 = XF_PIXELDEPTH(DEPTH_SRC);
    N1 = 0;
    M2 = M1;
    N2 = N1;

rowLoop:
    for (i = 0; i < height; i++) {
// clang-format off
        #pragma HLS LOOP_TRIPCOUNT min=ROWS max=ROWS
        #pragma HLS LOOP_FLATTEN OFF
    // clang-format on

    colLoop:
        for (j = 0; j < width; j++) {
// clang-format off
            #pragma HLS LOOP_TRIPCOUNT min=COLS_TRIP max=COLS_TRIP
            #pragma HLS PIPELINE
            // clang-format on

            grad_x_packed_val = (XF_SNAME(WORDWIDTH_SRC))(_gradx_stream.read());
            grad_y_packed_val = (XF_SNAME(WORDWIDTH_SRC))(_grady_stream.read());

            uchar_t step_src = XF_PIXELDEPTH(DEPTH_SRC);
            uchar_t step_dst = XF_PIXELDEPTH(DEPTH_DST);
            uint16_t proc_loop_src = XF_PIXELDEPTH(DEPTH_SRC) << XF_BITSHIFT(NPC);
            uint16_t proc_loop_dst = XF_PIXELDEPTH(DEPTH_DST) << XF_BITSHIFT(NPC);

        procLoop:
            for (k = 0, l = 0; k < proc_loop_src, l < proc_loop_dst; k += step_src, l += step_dst) {
// clang-format off
                #pragma HLS UNROLL
                // clang-format on

                XF_PTNAME(DEPTH_SRC)
                g_x = grad_x_packed_val.range(k + (step_src - 1), k); // Get bits from certain range of positions.
                XF_PTNAME(DEPTH_SRC)
                g_y = grad_y_packed_val.range(k + (step_src - 1), k); // Get bits from certain range of positions.

                int16_t g_x_16_p, g_x_16_m, g_y_16_p, g_y_16_m;
                g_x_16_p = g_x_16_m = g_x;
                g_y_16_p = g_y_16_m = g_y;

                // output will be in the radians
                int16_t ret = 0;
                int result_temp = 0;

                ret = xf::cv::Atan2LUT8(g_x_16_p, g_y_16_p, M1, N1, M2, N2);

                if ((ret < 0) || ((ret == 0) && (g_y_16_p < 0)))
                    result_temp = ret + XF_PI_FIXED + XF_PI_FIXED;
                else
                    result_temp = ret;

                // converting the radians value to degree
                // instead of removing complete 22 fractional bits, we shift only 15 times, for we have some precision
                // for HoG gradient computation
                XF_PTNAME(DEPTH_DST) result_phase = ((XF_NORM_FACTOR * result_temp) >> 15); // Q9.7 format

                // absolute difference of the input data
                __HOG_ABS(g_x_16_m);
                __HOG_ABS(g_y_16_m);

                ap_uint17_t gx_sq = (uchar_t)g_x_16_m * (uchar_t)g_x_16_m;
                ap_uint17_t gy_sq = (uchar_t)g_y_16_m * (uchar_t)g_y_16_m;

                // perform square root for the result_tmp
                ap_uint<17> sum_sq_grad = gx_sq + gy_sq;
                ap_ufixed<31, 31, AP_TRN, AP_SAT> tmp_mag = ((ap_uint<31>)sum_sq_grad) << 14;
                XF_PTNAME(DEPTH_DST) result_mag = xFSqrtHOG<16>(tmp_mag); // Q9.7 format

                // packing the output pixel data
                phase_packed_val.range(l + (step_dst - 1), l) = result_phase;
                mag_packed_val.range(l + (step_dst - 1), l) = result_mag;
            } // end of proc loop

            _phase_stream.write(phase_packed_val);
            _mag_stream.write(mag_packed_val);
        } // end of col loop
    }     // end of row loop
} // end of function

/*******************************************************************
 * xFPhaseMagnitude: This function acts as a wrapper function and
 *       calls the phaseMagnitude Kernel function.
 *******************************************************************/
template <int ROWS, int COLS, int DEPTH_SRC, int DEPTH_DST, int NPC, int WORDWIDTH_SRC, int WORDWIDTH_DST>
void xFHOGPhaseMagnitude(hls::stream<XF_SNAME(WORDWIDTH_SRC)>& _grad_x,
                         hls::stream<XF_SNAME(WORDWIDTH_SRC)>& _grad_y,
                         hls::stream<XF_SNAME(WORDWIDTH_DST)>& _phase_stream,
                         hls::stream<XF_SNAME(WORDWIDTH_DST)>& _mag_stream,
                         uint16_t height,
                         uint16_t width) {
#ifndef __SYNTHESIS__
    assert((DEPTH_SRC == XF_9SP) && "DEPTH_SRC must be XF_9SP");
    assert((DEPTH_DST == XF_16UP) && "DEPTH_DST must be of type XF_16UP");
    assert(((NPC == XF_NPPC1) || (NPC == XF_NPPC8) || (NPC == XF_NPPC16)) &&
           "NPC must be XF_NPPC1, XF_NPPC8 or XF_NPPC16");
    assert(((WORDWIDTH_SRC == XF_9UW) || (WORDWIDTH_SRC == XF_72UW) || (WORDWIDTH_SRC == XF_144UW)) &&
           "WORDWIDTH_SRC must be XF_9UW, XF_72UW or XF_144UW");
    assert(((WORDWIDTH_DST == XF_16UW) || (WORDWIDTH_DST == XF_128UW) || (WORDWIDTH_DST == XF_256UW)) &&
           "WORDWIDTH_DST must be XF_16UW, XF_128UW or XF_256UW");
#endif

    xFHOGPhaseMagnitudeKernel<ROWS, COLS, DEPTH_SRC, DEPTH_DST, NPC, WORDWIDTH_SRC, WORDWIDTH_DST,
                              (COLS >> XF_BITSHIFT(NPC))>(_grad_x, _grad_y, _phase_stream, _mag_stream, height, width);
}

#endif // _XF_HOG_DESCRIPTOR_PM_HPP_