.. _program_listing_file__tmp_ws_src_vitis_common_include_imgproc_xf_demosaicing.hpp: Program Listing for File xf_demosaicing.hpp =========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``/tmp/ws/src/vitis_common/include/imgproc/xf_demosaicing.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* * 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 T xf_satcast(int in_val){}; template <> inline ap_uint<8> xf_satcast >(int v) { return (v > MAXVAL(8) ? XF_UCHAR_MAX : v); }; template <> inline ap_uint<10> xf_satcast >(int v) { return (v > MAXVAL(10) ? XF_UTENBIT_MAX : v); }; template <> inline ap_uint<12> xf_satcast >(int v) { return (v > MAXVAL(12) ? XF_UTWELVEBIT_MAX : v); }; template <> inline ap_uint<16> xf_satcast >(int v) { return (v > MAXVAL(16) ? XF_USHORT_MAX : v); }; /* */ namespace xf { namespace cv { template 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 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 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 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 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(imgblock, loop); g = g_kernel(imgblock, loop); r = imgblock[2][2 + loop]; } else { // We already have G value at this location b = rgb_bgr_kernel(imgblock, loop); g = imgblock[2][2 + loop]; r = rgr_bgb_kernel(imgblock, loop); } } else { // B row if ((col & 0x00000001) == 0) { // We have already G value at this location b = rgr_bgb_kernel(imgblock, loop); g = imgblock[2][2 + loop]; r = rgb_bgr_kernel(imgblock, loop); } else { // We already have B value at this location b = imgblock[2][2 + loop]; g = g_kernel(imgblock, loop); r = rb_kernel(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(imgblock, loop); g = g_kernel(imgblock, loop); b = imgblock[2][2 + loop]; } else { // Even row, odd column - We already have G value at this // location b = rgr_bgb_kernel(imgblock, loop); g = imgblock[2][2 + loop]; r = rgb_bgr_kernel(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(imgblock, loop); g = imgblock[2][2 + loop]; r = rgr_bgb_kernel(imgblock, loop); } else { // Odd row, odd column - We already have R value at this location r = imgblock[2][2 + loop]; g = g_kernel(imgblock, loop); b = rb_kernel(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(imgblock, loop); g = imgblock[2][2 + loop]; r = rgb_bgr_kernel(imgblock, loop); } else { // Even row, odd column - We already have B value at this // location b = imgblock[2][2 + loop]; g = g_kernel(imgblock, loop); r = rb_kernel(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(imgblock, loop); b = rb_kernel(imgblock, loop); } else { // Odd row, odd column - We already have G value at this location b = rgb_bgr_kernel(imgblock, loop); g = imgblock[2][2 + loop]; r = rgr_bgb_kernel(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(imgblock, loop); g = imgblock[2][2 + loop]; r = rgr_bgb_kernel(imgblock, loop); } else { // Even row, odd column - We already have R value at this // location r = imgblock[2][2 + loop]; g = g_kernel(imgblock, loop); b = rb_kernel(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(imgblock, loop); r = rb_kernel(imgblock, loop); } else { // Odd row, odd column - We already have G value at this location b = rgr_bgb_kernel(imgblock, loop); g = imgblock[2][2 + loop]; r = rgb_bgr_kernel(imgblock, loop); } } } } template void demosaicing(xf::cv::Mat& src_mat, xf::cv::Mat& 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> 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(imgblock, b, g, r, i, j * NPC + loop, loop); b = xf_satcast(b); g = xf_satcast(g); r = xf_satcast(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(r); res_pixel[loop].range(2 * out_step - 1, out_step) = g; // xf_satcast(g); res_pixel[loop].range(out_step - 1, 0) = b; // xf_satcast(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