Program Listing for File xf_crop.hpp
↰ Return to documentation for file (/tmp/ws/src/vitis_common/include/imgproc/xf_crop.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_CROP_HPP_
#define _XF_CROP_HPP_
#ifndef __cplusplus
#error C++ is needed to include this header
#endif
typedef unsigned short uint16_t;
typedef unsigned char uchar;
#include "hls_stream.h"
#include "../common/xf_common.hpp"
#include "../common/xf_utility.hpp"
namespace xf {
namespace cv {
template <int SRC_T, int ROWS, int COLS, int DEPTH, int NPC, int COLS_TRIP>
void read_roi_row(xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _src_mat,
int offset,
int col_loop_cnt,
int& cnt,
int end_loc,
int start_loc,
int& pix_pos,
int left_over_pix,
XF_TNAME(SRC_T, NPC) & final_pix,
XF_TNAME(SRC_T, NPC) temp[COLS >> XF_BITSHIFT(NPC)]) {
// Local Variables
XF_TNAME(SRC_T, NPC) pix = 0;
// Local Constants
const int pix_width = XF_PIXELWIDTH(SRC_T, NPC);
const int _npc_ = XF_NPIXPERCYCLE(NPC);
// Initialization
cnt = 0;
for (ap_uint<13> j = 0; j < col_loop_cnt; j++) {
// clang-format off
#pragma HLS LOOP_TRIPCOUNT min=COLS_TRIP max=COLS_TRIP
#pragma HLS PIPELINE II=1
// clang-format on
pix = _src_mat.read(offset + j);
int num_valid = end_loc - start_loc;
int num_rem = _npc_ - pix_pos;
if (num_rem > num_valid) {
final_pix.range(pix_pos * pix_width + (num_valid * pix_width) - 1, pix_pos * pix_width) =
pix.range(end_loc * pix_width - 1, start_loc * pix_width);
pix_pos += num_valid;
} else {
final_pix.range(pix_pos * pix_width + (num_rem * pix_width) - 1, pix_pos * pix_width) =
pix.range((start_loc + num_rem) * pix_width - 1, start_loc * pix_width);
temp[cnt] = final_pix;
cnt++;
pix_pos = num_valid - num_rem;
if (pix_pos != 0)
final_pix.range(pix_pos * pix_width - 1, 0) =
pix.range(end_loc * pix_width - 1, (start_loc + num_rem) * pix_width);
}
// Some reseting stuff...
start_loc = 0;
if (j == (col_loop_cnt - 2)) // For last column (column here refers to a unit of N-Pix per clock)
{
end_loc = left_over_pix;
}
}
}
template <int SRC_T, int ROWS, int COLS, int DEPTH, int NPC, int COLS_TRIP>
void write_roi_row(int cnt,
XF_TNAME(SRC_T, NPC) temp[COLS >> XF_BITSHIFT(NPC)],
int write_offset,
xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _dst_mat) {
for (int k = 0; k < cnt; k++) {
// clang-format off
#pragma HLS LOOP_TRIPCOUNT min=COLS_TRIP max=COLS_TRIP
#pragma HLS PIPELINE II=1
// clang-format on
_dst_mat.write(write_offset + k, temp[k]);
}
}
template <int SRC_T, int ROWS, int COLS, int DEPTH, int NPC, int WORDWIDTH_SRC, int WORDWIDTH_DST, int COLS_TRIP>
void xFcropkernel_memorymapped(xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _src_mat,
xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _dst_mat,
xf::cv::Rect_<unsigned int>& roi,
unsigned short height,
unsigned short width) {
// clang-format off
#pragma HLS INLINE
// clang-format on
// Ping-Pong buffer declaration:
XF_TNAME(SRC_T, NPC) buf0[COLS >> XF_BITSHIFT(NPC)];
// clang-format off
#pragma HLS RESOURCE variable=buf0 core=RAM_S2P_BRAM
// clang-format on
XF_TNAME(SRC_T, NPC) buf1[COLS >> XF_BITSHIFT(NPC)];
// clang-format off
#pragma HLS RESOURCE variable=buf1 core=RAM_S2P_BRAM
// clang-format on
// Local constants
const int _npc_ = XF_NPIXPERCYCLE(NPC);
// For ROI bottom-right co-ordinates
ap_uint<32> r = roi.y;
ap_uint<32> r_new = roi.y + roi.height - 1;
ap_uint<32> c = roi.x;
ap_uint<32> c_new = roi.x + roi.width - 1;
// Temporary register for holding output column
XF_TNAME(SRC_T, NPC) final_pix = 0;
// Local variables and their initial values
int col_offset = 0, write_offset = 0, pix_pos = 0, toggle_flag = 1;
int col_loop_cnt = 0, cnt = 0, start_loc = 0, end_loc = 0, offset = 0;
ap_uint<32> start_pix_loc = 0; // Location of first pix in every row
ap_uint<32> left_over_pix = 0; // Left over pixels in each row after reading col_loop_cnt-1 columns
// NPC will always in powers of 2
// So c%NPC or c_new%NPC is just lest XF_BITSHIFT(NPC) bits
if (XF_BITSHIFT(NPC) != 0) {
start_pix_loc.range(XF_BITSHIFT(NPC) - 1, 0) = c.range(XF_BITSHIFT(NPC) - 1, 0);
left_over_pix.range(XF_BITSHIFT(NPC) - 1, 0) = c_new.range(XF_BITSHIFT(NPC) - 1, 0);
}
start_loc = start_pix_loc; // Ranges from 0->NPC-1
end_loc = _npc_; // Ranges from 1->NPC, this is done for easy loop-count/range calculations.
col_offset = (roi.x >> XF_BITSHIFT(NPC));
col_loop_cnt = (c_new >> XF_BITSHIFT(NPC)) - col_offset + 1;
if (left_over_pix == 0) {
left_over_pix = _npc_;
} else {
left_over_pix++;
}
offset = (r * width) + col_offset;
read_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(_src_mat, offset, col_loop_cnt, cnt, end_loc, start_loc,
pix_pos, left_over_pix, final_pix, buf0);
rowLoop:
for (ap_uint<32> i = 1; i < roi.height; i++) {
// clang-format off
#pragma HLS LOOP_TRIPCOUNT min=ROWS max=ROWS
// clang-format on
start_loc = start_pix_loc;
end_loc = _npc_;
if (i == 24) {
int val = 130;
}
offset += width;
if (toggle_flag) {
write_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(cnt, buf0, write_offset, _dst_mat);
write_offset += cnt;
read_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(_src_mat, offset, col_loop_cnt, cnt, end_loc,
start_loc, pix_pos, left_over_pix, final_pix, buf1);
} else {
write_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(cnt, buf1, write_offset, _dst_mat);
write_offset += cnt;
read_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(_src_mat, offset, col_loop_cnt, cnt, end_loc,
start_loc, pix_pos, left_over_pix, final_pix, buf0);
}
// toogle_flag = ~toggle_flag;
toggle_flag = ((toggle_flag == 0) ? 1 : 0);
}
// For last row
if (roi.height == 1) {
write_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(cnt, buf0, write_offset, _dst_mat);
} else if (toggle_flag == 1) {
write_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(cnt, buf0, write_offset, _dst_mat);
} else {
write_roi_row<SRC_T, ROWS, COLS, DEPTH, NPC, COLS_TRIP>(cnt, buf1, write_offset, _dst_mat);
}
if (pix_pos != 0) {
_dst_mat.write(write_offset + cnt, final_pix);
}
}
template <int SRC_T, int ROWS, int COLS, int DEPTH, int NPC, int WORDWIDTH_SRC, int WORDWIDTH_DST, int COLS_TRIP>
void xFcropkernel_stream(xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _src_mat,
xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _dst_mat,
xf::cv::Rect_<unsigned int>& roi,
unsigned short height,
unsigned short width) {
XF_SNAME(WORDWIDTH_SRC) val_src = 0;
XF_SNAME(WORDWIDTH_DST) val_dst = 0;
XF_PTNAME(DEPTH) pix_pos = 0;
// computing bottom right loaction of ROI using roi structure
ap_uint<13> r = roi.y;
ap_uint<13> r_new = roi.y + roi.height;
ap_uint<13> c = roi.x;
ap_uint<13> c_new = (roi.x + roi.width);
ap_uint<13> i, j, k;
// intializing the local variables
unsigned long long int idx = 0;
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
val_src =
(XF_SNAME(WORDWIDTH_SRC))(_src_mat.read(i * width + j)); // reading the source stream _src into val_src
for (k = 0; k < NPC; k++) {
// clang-format off
#pragma HLS unroll
// clang-format on
int col = (j * NPC) + k;
if (((i >= r) && (i < r_new)) && ((col >= c) && (col < c_new))) {
val_dst.range((pix_pos * XF_PIXELWIDTH(SRC_T, NPC) + (XF_PIXELWIDTH(SRC_T, NPC) - 1)),
pix_pos * XF_PIXELWIDTH(SRC_T, NPC)) =
val_src.range((k * XF_PIXELWIDTH(SRC_T, NPC)) + XF_PIXELWIDTH(SRC_T, NPC) - 1,
k * XF_PIXELWIDTH(SRC_T, NPC));
pix_pos++;
if (pix_pos == NPC) {
_dst_mat.write(idx++, val_dst);
pix_pos = 0;
}
}
}
}
}
if (pix_pos != 0) {
_dst_mat.write(idx++, val_dst);
}
}
template <int SRC_T, int ROWS, int COLS, int ARCH_TYPE = 0, int NPC = 1>
void crop(xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _src_mat,
xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& _dst_mat,
xf::cv::Rect_<unsigned int>& roi) {
unsigned short width = _src_mat.cols;
unsigned short height = _src_mat.rows;
#ifndef __SYNTHESIS__
// assert((SRC_T == XF_8UC1) ||(SRC_T == XF_8UC3) && "Type must be XF_8UC1 or XF_8UC3");
assert(((height <= ROWS) && (width <= COLS)) && "ROWS and COLS should be greater than input image");
assert(((roi.height <= height) && (roi.width <= width)) &&
"ROI dimensions should be smaller or equal to the input image");
assert(((roi.height > 0) && (roi.width > 0)) && "ROI dimensions should be greater than 0");
assert(((roi.height + roi.y <= height) && (roi.width + roi.x <= width)) && "ROI area exceeds the input image area");
#endif
// Width in terms of NPPC
width = _src_mat.cols >> XF_BITSHIFT(NPC);
// clang-format off
#pragma HLS INLINE OFF
// clang-format on
if (ARCH_TYPE == XF_MEMORYMAPPED) {
xFcropkernel_memorymapped<SRC_T, ROWS, COLS, XF_DEPTH(SRC_T, NPC), NPC, XF_WORDWIDTH(SRC_T, NPC),
XF_WORDWIDTH(SRC_T, NPC), (COLS >> XF_BITSHIFT(NPC))>(_src_mat, _dst_mat, roi, height,
width);
} else {
xFcropkernel_stream<SRC_T, ROWS, COLS, XF_DEPTH(SRC_T, NPC), NPC, XF_WORDWIDTH(SRC_T, NPC),
XF_WORDWIDTH(SRC_T, NPC), (COLS >> XF_BITSHIFT(NPC))>(_src_mat, _dst_mat, roi, height,
width);
}
} // crop
} // namespace cv
} // namespace xf
#endif