Program Listing for File xf_demosaicing.hpp
↰ Return to documentation for file (/tmp/ws/src/vitis_common/include/imgproc/xf_demosaicing.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_DEMOSAICING_HPP__
#define __XF_DEMOSAICING_HPP__
#include "ap_int.h"
#include "../common/xf_common.hpp"
#include "hls_stream.h"
#define MAXVAL(pixeldepth) ((1 << pixeldepth) - 1)
#define XF_UCHAR_MAX 255
#define XF_UTENBIT_MAX 1023
#define XF_UTWELVEBIT_MAX 4095
#define XF_USHORT_MAX 65535
template <typename T>
T xf_satcast(int in_val){};
template <>
inline ap_uint<8> xf_satcast<ap_uint<8> >(int v) {
return (v > MAXVAL(8) ? XF_UCHAR_MAX : v);
};
template <>
inline ap_uint<10> xf_satcast<ap_uint<10> >(int v) {
return (v > MAXVAL(10) ? XF_UTENBIT_MAX : v);
};
template <>
inline ap_uint<12> xf_satcast<ap_uint<12> >(int v) {
return (v > MAXVAL(12) ? XF_UTWELVEBIT_MAX : v);
};
template <>
inline ap_uint<16> xf_satcast<ap_uint<16> >(int v) {
return (v > MAXVAL(16) ? XF_USHORT_MAX : v);
};
/* */
namespace xf {
namespace cv {
template <typename T, int buf_size>
int g_kernel(T imgblock[5][buf_size], int loop) {
// clang-format off
#pragma HLS inline off
// clang-format on
int res = -(imgblock[0][2 + loop] + imgblock[2][0 + loop] + imgblock[2][4 + loop] + imgblock[4][2 + loop]) +
(imgblock[1][2 + loop] + imgblock[2][1 + loop] + imgblock[2][3 + loop] + imgblock[3][2 + loop]) * 2 +
(imgblock[2][2 + loop]) * 4;
res /= 8;
if (res < 0) return 0;
return res;
}
// R at a B location and B at a R location
template <typename T, int buf_size>
int rb_kernel(T imgblock[5][buf_size], int loop) {
// clang-format off
#pragma HLS inline off
// clang-format on
int t1 = (imgblock[0][2 + loop] + imgblock[2][0 + loop] + imgblock[2][4 + loop] + imgblock[4][2 + loop]);
t1 = (t1 * 3) / 2;
int t2 = (imgblock[1][1 + loop] + imgblock[1][3 + loop] + imgblock[3][1 + loop] + imgblock[3][3 + loop]);
t2 = t2 * 2;
int t3 = (imgblock[2][2 + loop]) * 6;
int res = (-t1) + (t2) + (t3);
res /= 8;
if (res < 0) return 0;
return res;
}
//**** R at a G location in R row ****** B at a Green location in a B row
//*******
template <typename T, int buf_size>
int rgr_bgb_kernel(T imgblock[5][buf_size], int loop) {
// clang-format off
#pragma HLS inline off
// clang-format on
int t1 = imgblock[0][2 + loop] + imgblock[4][2 + loop];
int t2 = imgblock[1][1 + loop] + imgblock[1][3 + loop] + imgblock[2][0 + loop] + imgblock[2][4 + loop] +
imgblock[3][1 + loop] + imgblock[3][3 + loop];
int t3 = imgblock[2][1 + loop] + imgblock[2][3 + loop];
t3 *= 4;
int t4 = (imgblock[2][2 + loop]) * 5;
int res = ((t1) >> 1) - (t2) + (t3) + (t4);
res /= 8;
if (res < 0) return 0;
return res;
}
// R at a G location in a B row and B at a G location in R row
template <typename T, int buf_size>
int rgb_bgr_kernel(T imgblock[5][buf_size], int loop) {
// clang-format off
#pragma HLS inline off
// clang-format on
int t1 = (imgblock[2][0 + loop] + imgblock[2][4 + loop]);
t1 /= 2;
int t2 = imgblock[0][2 + loop] + imgblock[1][1 + loop] + imgblock[1][3 + loop] + imgblock[3][1 + loop] +
imgblock[3][3 + loop] + imgblock[4][2 + loop];
int t3 = imgblock[1][2 + loop] + imgblock[3][2 + loop];
t3 *= 4;
int t4 = (imgblock[2][2 + loop]) * 5;
int res = (t1) - (t2) + (t3) + (t4);
res /= 8;
if (res < 0) return 0;
return res;
}
template <int BFORMAT, int SRC_T, int NPC, int DEPTH, int buf_size>
void Core_Process(XF_DTUNAME(SRC_T, NPC) imgblock[5][buf_size], int& b, int& g, int& r, int row, int col, int loop) {
if (BFORMAT == XF_BAYER_RG) {
if ((row & 0x00000001) == 0) { // if R row
if ((col & 0x00000001) == 0) { // We already have R value at this location
b = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
r = imgblock[2][2 + loop];
} else { // We already have G value at this location
b = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
} else { // B row
if ((col & 0x00000001) == 0) { // We have already G value at this location
b = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
} else { // We already have B value at this location
b = imgblock[2][2 + loop];
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
r = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
}
} else if (BFORMAT == XF_BAYER_BG) {
if ((row & 0x00000001) == 0) { // if B row
if ((col & 0x00000001) == 0) { // Even row, even column - We already have
// B value at this location
r = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
b = imgblock[2][2 + loop];
} else { // Even row, odd column - We already have G value at this
// location
b = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
} else { // if R row
if ((col & 0x00000001) == 0) { // Odd row, even column - We have G value at this location
b = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
} else { // Odd row, odd column - We already have R value at this location
r = imgblock[2][2 + loop];
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
b = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
}
} else if (BFORMAT == XF_BAYER_GB) {
if ((row & 0x00000001) == 0) { // if B row
if ((col & 0x00000001) == 0) { // Even row, even column - We already have
// G value at this location
b = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
} else { // Even row, odd column - We already have B value at this
// location
b = imgblock[2][2 + loop];
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
r = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
} else { // if R row
if ((col & 0x00000001) == 0) { // Odd row, even column - We have R value at this location
r = imgblock[2][2 + loop];
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
b = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
} else { // Odd row, odd column - We already have G value at this location
b = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
}
} else if (BFORMAT == XF_BAYER_GR) {
if ((row & 0x00000001) == 0) { // if R row
if ((col & 0x00000001) == 0) { // Even row, even column - We already have
// G value at this location
b = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
} else { // Even row, odd column - We already have R value at this
// location
r = imgblock[2][2 + loop];
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
b = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
} else { // if B row
if ((col & 0x00000001) == 0) { // Odd row, even column - We have B value at this location
b = imgblock[2][2 + loop];
g = g_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
r = rb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
} else { // Odd row, odd column - We already have G value at this location
b = rgr_bgb_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
g = imgblock[2][2 + loop];
r = rgb_bgr_kernel<XF_DTUNAME(SRC_T, NPC), buf_size>(imgblock, loop);
}
}
}
}
template <int BFORMAT, int SRC_T, int DST_T, int ROWS, int COLS, int NPC, bool USE_URAM>
void demosaicing(xf::cv::Mat<SRC_T, ROWS, COLS, NPC>& src_mat, xf::cv::Mat<DST_T, ROWS, COLS, NPC>& dst_mat) {
#ifndef __SYNTHESIS__
assert(((BFORMAT == XF_BAYER_BG) || (BFORMAT == XF_BAYER_GB) || (BFORMAT == XF_BAYER_GR) ||
(BFORMAT == XF_BAYER_RG)) &&
("Unsupported Bayer pattern. Use anyone among: "
"XF_BAYER_BG;XF_BAYER_GB;XF_BAYER_GR;XF_BAYER_RG"));
assert(((src_mat.rows <= ROWS) && (src_mat.cols <= COLS)) && "ROWS and COLS should be greater than input image");
assert(((NPC == 1) || (NPC == 2) || (NPC == 4)) && "Only 1, 2 and 4 pixel-parallelism are supported");
assert(((SRC_T == XF_8UC1) || (SRC_T == XF_10UC1) || (SRC_T == XF_12UC1) || (SRC_T == XF_16UC1)) &&
"Only 8, 10, 12 and 16 bit, single channel images are supported");
assert(((DST_T == XF_8UC3) || (DST_T == XF_10UC3) || (DST_T == XF_12UC3) || (DST_T == XF_16UC3) ||
(DST_T == XF_8UC4) || (DST_T == XF_10UC4) || (DST_T == XF_12UC4) || (DST_T == XF_16UC4)) &&
"Only 8, 10, 12 and 16 bit, 3 and 4 channel images are supported");
#endif
const int __BHEIGHT = 5;
const int __BHEIGHTMINUSONE = __BHEIGHT - 1;
const int __BWIDTH = NPC + __BHEIGHTMINUSONE + (((NPC - 1) >> 1) << 1);
// clang-format off
#pragma HLS INLINE OFF
// clang-format on
XF_TNAME(SRC_T, NPC) linebuffer[__BHEIGHTMINUSONE][COLS >> XF_BITSHIFT(NPC)];
if (USE_URAM) {
// clang-format off
#pragma HLS RESOURCE variable=linebuffer core=RAM_T2P_URAM
#pragma HLS array_reshape variable=linebuffer dim=1 factor=4 cyclic
// clang-format on
} else {
// clang-format off
#pragma HLS RESOURCE variable=linebuffer core=RAM_T2P_BRAM
#pragma HLS array_partition variable=linebuffer complete dim=1
// clang-format on
}
XF_CTUNAME(SRC_T, NPC) imgblock[__BHEIGHT][__BWIDTH];
const int pre_read_count = (2 / NPC) + ((NPC * NPC) >> 2); // 2-2-4
const int post_read_count = pre_read_count + 2; // 4-4-6
const int end_read_count = ((NPC << 1) >> (NPC * NPC)) + 1; // 2-1-1
// clang-format off
#pragma HLS array_partition variable=imgblock complete dim=0
// clang-format on
int lineStore = 3, read_index = 0, write_index = 0;
LineBuffer:
for (int i = 0; i < 2; i++) {
// clang-format off
#pragma HLS LOOP_TRIPCOUNT min=2 max=2
// clang-format on
for (int j = 0; j<src_mat.cols>> XF_BITSHIFT(NPC); j++) {
// clang-format off
#pragma HLS LOOP_TRIPCOUNT min=COLS/NPC max=COLS/NPC
#pragma HLS pipeline ii=1
// clang-format on
XF_TNAME(SRC_T, NPC) tmp = src_mat.read(read_index++);
linebuffer[i][j] = 0;
linebuffer[i + 2][j] = tmp;
}
}
ap_uint<3> line0 = 3, line1 = 0, line2 = 1, line3 = 2;
int step = XF_DTPIXELDEPTH(SRC_T, NPC);
int out_step = XF_DTPIXELDEPTH(DST_T, NPC);
XF_TNAME(SRC_T, NPC) tmp;
Row_Loop:
for (int i = 0; i < src_mat.rows; i++) {
// clang-format off
#pragma HLS LOOP_TRIPCOUNT min=ROWS max=ROWS
// clang-format on
int bram_read_count = 0;
lineStore++;
if (lineStore > 3) {
lineStore = 0;
}
if (line0 == 0) {
line0 = 1;
line1 = 2;
line2 = 3;
line3 = 0;
} else if (line0 == 1) {
line0 = 2;
line1 = 3;
line2 = 0;
line3 = 1;
} else if (line0 == 2) {
line0 = 3;
line1 = 0;
line2 = 1;
line3 = 2;
} else {
line0 = 0;
line1 = 1;
line2 = 2;
line3 = 3;
}
/*Image left corner case */
Zero:
for (int p = 0; p < 4; ++p) {
// clang-format off
#pragma HLS PIPELINE ii=1
// clang-format on
for (int k = 0; k < NPC + 2; k++) {
imgblock[p][k] = 0;
}
}
/*Filling the data in the first four rows of 5x5/5x6/5x10 window from
* linebuffer */
Datafill:
for (int n = 0, w = 0, v = 0; n < pre_read_count; ++n, ++v) {
// clang-format off
#pragma HLS UNROLL
// clang-format on
imgblock[0][2 + NPC + n] = linebuffer[line0][w].range((step + step * v) - 1, step * v);
imgblock[1][2 + NPC + n] = linebuffer[line1][w].range((step + step * v) - 1, step * v);
imgblock[2][2 + NPC + n] = linebuffer[line2][w].range((step + step * v) - 1, step * v);
imgblock[3][2 + NPC + n] = linebuffer[line3][w].range((step + step * v) - 1, step * v);
(NPC == 1) ? (bram_read_count++, w++, v = -1) : bram_read_count; // Read twice (for 3rd and 4th locations of
// imgblock) for NPPC1
}
(NPC == 2 || NPC == 4) ? (bram_read_count++) : bram_read_count;
Col_Loop:
for (int j = 0; j < ((src_mat.cols) >> XF_BITSHIFT(NPC)); j++) {
// clang-format off
#pragma HLS PIPELINE ii=1
#pragma HLS dependence variable=linebuffer inter false
#pragma HLS LOOP_TRIPCOUNT min=COLS/NPC max=COLS/NPC
#pragma HLS LOOP_FLATTEN OFF
// clang-format on
if (i < src_mat.rows - 2) {
tmp = src_mat.read(read_index++); // Reading 5th row element
} else {
tmp = 0;
}
for (int z = 0; z < NPC; ++z) {
imgblock[4][2 + NPC + z] = tmp.range((step + step * z) - 1, step * z);
}
// Shift the elements in imgblock by NPC
for (int k = 0; k < 5; k++) {
for (int m = 0; m < NPC; ++m) {
for (int l = 0; l < (__BWIDTH - 1); l++) {
imgblock[k][l] = imgblock[k][l + 1];
}
}
}
XF_TNAME(SRC_T, NPC)
packed_read1, packed_read2, packed_read3, packed_read4, packed_store;
if (j < (src_mat.cols >> XF_BITSHIFT(NPC)) - end_read_count) { // for each element being processed that is
// not at borders
packed_read1 = linebuffer[line0][bram_read_count];
packed_read2 = linebuffer[line1][bram_read_count];
packed_read3 = linebuffer[line2][bram_read_count];
packed_read4 = linebuffer[line3][bram_read_count];
for (int q = 0; q < NPC; ++q) {
imgblock[0][post_read_count + q] = packed_read1.range((step + step * q) - 1, step * q);
imgblock[1][post_read_count + q] = packed_read2.range((step + step * q) - 1, step * q);
imgblock[2][post_read_count + q] = packed_read3.range((step + step * q) - 1, step * q);
imgblock[3][post_read_count + q] = packed_read4.range((step + step * q) - 1, step * q);
imgblock[4][NPC + 2 + q] = tmp.range((step + step * q) - 1, step * q);
packed_store.range((step + step * q) - 1, step * q) = imgblock[4][2 + q];
}
linebuffer[lineStore][j] = packed_store;
} else { // For processing elements at the end of the line.
for (int r = 0; r < NPC; ++r) {
if (NPC == 1) {
imgblock[4][post_read_count + r - 1] = tmp.range((step + step * r) - 1, step * r);
}
linebuffer[lineStore][j].range((step + step * r) - 1, step * r) = imgblock[4][2 + r];
imgblock[0][post_read_count + r] = 0;
imgblock[1][post_read_count + r] = 0;
imgblock[2][post_read_count + r] = 0;
imgblock[3][post_read_count + r] = 0;
imgblock[4][post_read_count + r] = 0;
}
}
bram_read_count++;
// Calculate the resultant intensities at each pixel
int r, g, b;
XF_TNAME(DST_T, NPC) res_pixel[NPC];
for (int loop = 0; loop < NPC; loop++) {
Core_Process<BFORMAT, SRC_T, NPC, XF_DEPTH(SRC_T, NPC), __BWIDTH>(imgblock, b, g, r, i, j * NPC + loop,
loop);
b = xf_satcast<XF_CTUNAME(DST_T, NPC)>(b);
g = xf_satcast<XF_CTUNAME(DST_T, NPC)>(g);
r = xf_satcast<XF_CTUNAME(DST_T, NPC)>(r);
if (XF_CHANNELS(DST_T, NPC) == 4) {
res_pixel[loop].range(4 * out_step - 1, 3 * out_step) = MAXVAL(out_step);
}
res_pixel[loop].range(3 * out_step - 1, 2 * out_step) = r; // xf_satcast<XF_CTUNAME(SRC_T, NPC)>(r);
res_pixel[loop].range(2 * out_step - 1, out_step) = g; // xf_satcast<XF_CTUNAME(SRC_T, NPC)>(g);
res_pixel[loop].range(out_step - 1, 0) = b; // xf_satcast<XF_CTUNAME(SRC_T, NPC)>(b);
}
XF_TNAME(DST_T, NPC) packed_res_pixel;
int pstep = XF_PIXELWIDTH(DST_T, NPC);
for (int ploop = 0; ploop < NPC; ploop++) {
packed_res_pixel.range(pstep + pstep * ploop - 1, pstep * ploop) = res_pixel[ploop];
}
dst_mat.write(write_index++, packed_res_pixel);
} // end COL loop
} // end ROW loop
}
} // namespace cv
}; // namespace xf
#endif