Hi all,
I am trying to implement the Sobel filter using Vitis Vision Library 2021.2, Vitis HLS and Vivado 2021.2 on the Pynq-Z1 board. Based on the Pynq-Hello example, I tried to modify the Sobel L1 C++ example file to use DMA, but instead of getting the X-Y gradient outputs, I computed the final image using the magnitude function then I added the Vitis vision convert function to convert bit depth from 16 bits signed to 8bits unsigned. The synthesis and Vivado design worked correctly, however, the result is not correct.
This is my Vitis code
/*
* 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.
*/
////////
#include "hls_stream.h"
#include "common/xf_common.hpp"
#include "common/xf_infra.hpp"
#include "imgproc/xf_sobel.hpp"
#include "xf_config_params.h"
#include "ap_int.h"
#include "common/xf_utility.hpp"
#include "core/xf_convert_bitdepth.hpp"
#include "core/xf_magnitude.hpp"
///////
#include "xf_sobel_config.h"
///////
#define DATA_WIDTH 24
#define NPIX XF_NPPC1
/* set the height and width */
#define WIDTH 1920
#define HEIGHT 1080
#define FILTER_WIDTH 3
#define TYPE_IN XF_8UC3
#define TYPE_OUT XF_16SC1
#define OUT_TYPE XF_8UC1
#define XF_USE_URAM
typedef hls::stream<ap_axiu<DATA_WIDTH,1,1,1>> stream_t;
template <int W, int TYPE_IN, int ROWS, int COLS, int NPPC>
void axis2xfMat (hls::stream<ap_axiu<W, 1, 1, 1> >& AXI_video_strm, xf::cv::Mat<TYPE_IN, ROWS, COLS, NPPC>& img) {
ap_axiu<W, 1, 1, 1> axi;
const int m_pix_width = XF_PIXELWIDTH(TYPE_IN, NPPC) * XF_NPIXPERCYCLE(NPPC);
int rows = img.rows;
int cols = img.cols >> XF_BITSHIFT(NPPC);
assert(img.rows <= ROWS);
assert(img.cols <= COLS);
loop_row_axi2mat:
for (int i = 0; i < rows; i++) {
loop_col_zxi2mat:
for (int j = 0; j < cols; j++) {
#pragma HLS loop_flatten off
#pragma HLS pipeline II=1
AXI_video_strm.read(axi);
img.write(i*rows + j, axi.data(m_pix_width - 1, 0));
}
}
}
template <int W, int OUT_TYPE, int ROWS, int COLS, int NPPC>
void xfMat2axis(xf::cv::Mat<OUT_TYPE, ROWS, COLS, NPPC>& img, hls::stream<ap_axiu<W, 1, 1, 1> >& dst) {
ap_axiu<W, 1, 1, 1> axi;
int rows = img.rows;
int cols = img.cols >> XF_BITSHIFT(NPPC);
assert(img.rows <= ROWS);
assert(img.cols <= COLS);
const int m_pix_width = XF_PIXELWIDTH(OUT_TYPE, NPPC) * XF_NPIXPERCYCLE(NPPC);
loop_row_mat2axi:
for (int i = 0; i < rows; i++) {
loop_col_mat2axi:
for (int j = 0; j < cols; j++) {
#pragma HLS loop_flatten off
#pragma HLS pipeline II = 1
/*Assert last only in the last pixel*/
if ((j == cols-1) && (i == rows-1)) {
axi.last = 1;
} else {
axi.last = 0;
}
axi.data = 0;
axi.data(m_pix_width - 1, 0) = img.read(i*rows + j);
axi.keep = -1;
dst.write(axi);
}
}
}
void sobel_accel(stream_t& img_inp, stream_t& img_out, int shift, int rows, int cols)
{
#pragma HLS INTERFACE axis register both port=img_inp
#pragma HLS INTERFACE axis register both port=img_out
#pragma HLS INTERFACE s_axilite port=rows
#pragma HLS INTERFACE s_axilite port=cols
#pragma HLS INTERFACE s_axilite port=shift
#pragma HLS INTERFACE s_axilite port=return //bundle=control
xf::cv::Mat<TYPE_IN, HEIGHT, WIDTH, NPIX> in_mat(rows, cols);
xf::cv::Mat<TYPE_OUT, HEIGHT, WIDTH, NPIX> _dstgx(rows, cols);
xf::cv::Mat<TYPE_OUT, HEIGHT, WIDTH, NPIX> _dstgy(rows, cols);
xf::cv::Mat<TYPE_OUT, HEIGHT, WIDTH, NPIX> _img_out(rows, cols);
xf::cv::Mat<OUT_TYPE, HEIGHT, WIDTH, NPIX> _img_out2(rows, cols);
#pragma HLS DATAFLOW
axis2xfMat<DATA_WIDTH, TYPE_IN, HEIGHT, WIDTH, NPIX>(img_inp, in_mat);
xf::cv::Sobel<XF_BORDER_CONSTANT, FILTER_WIDTH, TYPE_IN, TYPE_OUT, HEIGHT, WIDTH, NPIX, false>(in_mat, _dstgx,_dstgy);
xf::cv::magnitude<XF_L2NORM ,TYPE_OUT,TYPE_OUT, HEIGHT, WIDTH, NPIX>(_dstgx,_dstgy,_img_out); //XF_L1NORM
xf::cv::convertTo<TYPE_OUT, OUT_TYPE, HEIGHT, WIDTH, NPIX>(_img_out, _img_out2, XF_CONVERT_16S_TO_8U, shift );
xfMat2axis<DATA_WIDTH, OUT_TYPE, HEIGHT, WIDTH, NPIX>(_img_out2, img_out);
}
Sobel_pl2.ipynb (819.5 KB)