From f48bd3d28165562b76d3e5e013b560ce849e8282 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Tue, 20 Jul 2010 15:51:32 +0000 Subject: [PATCH] added VNG demosaicing algorithm (ticket #466) --- .../imgproc/include/opencv2/imgproc/types_c.h | 20 ++ modules/imgproc/src/color.cpp | 266 +++++++++++++++++- 2 files changed, 285 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/include/opencv2/imgproc/types_c.h b/modules/imgproc/include/opencv2/imgproc/types_c.h index 97503c076d..182c22b4a4 100644 --- a/modules/imgproc/include/opencv2/imgproc/types_c.h +++ b/modules/imgproc/include/opencv2/imgproc/types_c.h @@ -186,6 +186,26 @@ enum CV_HLS2BGR =60, CV_HLS2RGB =61, + CV_BayerBG2BGR_VNG =62, + CV_BayerGB2BGR_VNG =63, + CV_BayerRG2BGR_VNG =64, + CV_BayerGR2BGR_VNG =65, + + CV_BayerBG2RGB_VNG =CV_BayerRG2BGR_VNG, + CV_BayerGB2RGB_VNG =CV_BayerGR2BGR_VNG, + CV_BayerRG2RGB_VNG =CV_BayerBG2BGR_VNG, + CV_BayerGR2RGB_VNG =CV_BayerGB2BGR_VNG, + + CV_BGR2HSV_FULL = 66, + CV_RGB2HSV_FULL = 67, + CV_BGR2HLS_FULL = 68, + CV_RGB2HLS_FULL = 69, + + CV_HSV2BGR_FULL = 70, + CV_HSV2RGB_FULL = 71, + CV_HLS2BGR_FULL = 72, + CV_HLS2RGB_FULL = 73, + CV_COLORCVT_MAX =100 }; diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp index cc748b0e91..7b56439117 100644 --- a/modules/imgproc/src/color.cpp +++ b/modules/imgproc/src/color.cpp @@ -2183,6 +2183,247 @@ icvBayer2BGR_8u_C1C3R( const uchar* bayer0, int bayer_step, } + +static CvStatus CV_STDCALL +icvBayer2BGR_VNG_8u_C1C3R( const uchar* bayer, int bstep, + uchar *dst, int dststep, + CvSize size, int code ) +{ + int blueIdx = code == CV_BayerBG2BGR_VNG || code == CV_BayerGB2BGR_VNG ? 0 : 2; + bool greenCell0 = code != CV_BayerBG2BGR_VNG && code != CV_BayerRG2BGR_VNG; + bool greenCell0_buf = !greenCell0; + + // for too small images use the simple interpolation algorithm + if( MIN(size.width, size.height) < 5 ) + return icvBayer2BGR_8u_C1C3R( bayer, bstep, dst, dststep, size, code ); + + const int brows = 3, bcn = 7; + int i, bufstep = size.width*bcn; + cv::AutoBuffer _buf(bufstep*brows); + ushort* buf = (ushort*)_buf; + + bayer += bstep*2; + + for( i = 0; i < size.width*3; i++ ) + { + dst[i] = dst[i + dststep] = + dst[i + dststep*(size.height-2)] = + dst[i + dststep*(size.height-1)] = 0; + } + + for( int y = 2; y < size.height - 2; y++ ) + { + uchar* dstrow = dst + dststep*y; + const uchar* srow; + + for( int dy = (y == 2 ? -1 : 1); dy <= 1; dy++ ) + { + ushort* brow = buf + ((y + dy - 1)%brows)*bufstep; + srow = bayer + dy*bstep; + + for( i = 0; i < bcn; i++ ) + brow[i] = brow[i + (size.width-1)*bcn] = 0; + + bool greenCell = greenCell0_buf; + for( i = 1; i < size.width-1; i++ ) + { + brow += bcn; + brow[0] = (ushort)( abs(srow[i-1-bstep] - srow[i-1+bstep]) + + abs(srow[i-bstep] - srow[i+bstep])*2 + + abs(srow[i+1-bstep] - srow[i+1+bstep])); + brow[1] = (ushort)( abs(srow[i-1-bstep] - srow[i+1-bstep]) + + abs(srow[i-1] - srow[i+1])*2 + + abs(srow[i-1+bstep] - srow[i+1+bstep])); + brow[2] = (ushort)(abs(srow[i+1-bstep] - srow[i-1+bstep])*2); + brow[3] = (ushort)(abs(srow[i-1-bstep] - srow[i+1+bstep])*2); + if(!greenCell) + { + brow[4] = (ushort)(brow[2] + abs(srow[i-bstep] - srow[i-1]) + abs(srow[i+bstep] - srow[i+1])); + brow[5] = (ushort)(brow[3] + abs(srow[i-bstep] - srow[i+1]) + abs(srow[i+bstep] - srow[i-1])); + brow[6] = (ushort)((srow[i-bstep] + srow[i-1] + srow[i+1] + srow[i+bstep] + 2)>>2); + } + greenCell = !greenCell; + } + greenCell0_buf = !greenCell0_buf; + } + + const ushort* brow0 = buf + ((y - 2) % brows)*bufstep + bcn; + const ushort* brow1 = buf + ((y - 1) % brows)*bufstep + bcn; + const ushort* brow2 = buf + (y % brows)*bufstep + bcn; + static const float scale[] = { 0.f, 1.f, 0.5f, 0.3333333333f, 0.25f, 0.2f, 0.1666666667f, 0.1428571f, 0.125f }; + srow = bayer + y*bstep; + bool greenCell = greenCell0; + + for( i = 0; i < 6; i++ ) + dstrow[i] = dstrow[i + (size.width-2)*3] = 0; + dstrow += 6; + + for( i = 2; i < size.width-2; i++, brow0 += bcn, brow1 += bcn, brow2 += bcn, dstrow += 3 ) + { + int gradN = (brow0[0] + brow1[0])>>1; + int gradS = (brow1[0] + brow2[0])>>1; + int gradW = (brow1[-bcn+1] + brow1[1])>>1; + int gradE = (brow1[1] + brow1[bcn+1])>>1; + int minGrad = std::min(std::min(std::min(gradN, gradS), gradW), gradE); + int maxGrad = std::max(std::max(std::max(gradN, gradS), gradW), gradE); + int R, G, B; + + if( !greenCell ) + { + int gradNE = (brow0[bcn+4] + brow1[4])>>1; + int gradSW = (brow1[4] + brow2[-bcn+4])>>1; + int gradNW = (brow0[-bcn+5] + brow1[5])>>1; + int gradSE = (brow1[5] + brow2[bcn+5])>>1; + + minGrad = std::min(std::min(std::min(std::min(minGrad, gradNE), gradSW), gradNW), gradSE); + maxGrad = std::max(std::max(std::max(std::max(maxGrad, gradNE), gradSW), gradNW), gradSE); + int T = minGrad + maxGrad/2; + + int Rs = 0, Gs = 0, Bs = 0, ng = 0; + if( gradN < T ) + { + Rs += (srow[i-bstep*2] + srow[i])>>1; + Gs += srow[i-bstep]; + Bs += (srow[i-bstep-1] + srow[i-bstep+1])>>1; + ng++; + } + if( gradS < T ) + { + Rs += (srow[i+bstep*2] + srow[i])>>1; + Gs += srow[i+bstep]; + Bs += (srow[i+bstep-1] + srow[i+bstep+1])>>1; + ng++; + } + if( gradW < T ) + { + Rs += (srow[i-2] + srow[i])>>1; + Gs += srow[i-1]; + Bs += (srow[i-bstep-1] + srow[i+bstep-1])>>1; + ng++; + } + if( gradE < T ) + { + Rs += (srow[i+2] + srow[i])>>1; + Gs += srow[i+1]; + Bs += (srow[i-bstep+1] + srow[i+bstep+1])>>1; + ng++; + } + if( gradNE < T ) + { + Rs += (srow[i-bstep*2+2] + srow[i])>>1; + Gs += brow0[bcn+6]; + Bs += srow[i-bstep+1]; + ng++; + } + if( gradSW < T ) + { + Rs += (srow[i+bstep*2-2] + srow[i])>>1; + Gs += brow2[-bcn+6]; + Bs += srow[i+bstep-1]; + ng++; + } + if( gradNW < T ) + { + Rs += (srow[i-bstep*2+2] + srow[i])>>1; + Gs += brow0[bcn+6]; + Bs += srow[i-bstep+1]; + ng++; + } + if( gradSE < T ) + { + Rs += (srow[i-bstep*2+2] + srow[i])>>1; + Gs += brow0[bcn+6]; + Bs += srow[i-bstep+1]; + ng++; + } + R = srow[i]; + G = R + cvRound((Gs - Rs)*scale[ng]); + B = R + cvRound((Bs - Rs)*scale[ng]); + } + else + { + int gradNE = (brow0[2] + brow0[bcn+2] + brow1[2] + brow1[bcn+2])>>1; + int gradSW = (brow1[2] + brow1[-bcn+2] + brow2[2] + brow2[-bcn+2])>>1; + int gradNW = (brow0[3] + brow0[-bcn+3] + brow1[3] + brow1[-bcn+3])>>1; + int gradSE = (brow1[3] + brow1[bcn+3] + brow2[3] + brow2[bcn+3])>>1; + + minGrad = std::min(std::min(std::min(std::min(minGrad, gradNE), gradSW), gradNW), gradSE); + maxGrad = std::max(std::max(std::max(std::max(maxGrad, gradNE), gradSW), gradNW), gradSE); + int T = minGrad + maxGrad/2; + + int Rs = 0, Gs = 0, Bs = 0, ng = 0; + if( gradN < T ) + { + Rs += (srow[i-bstep*2-1] + srow[i-bstep*2+1])>>1; + Gs += (srow[i-bstep*2] + srow[i])>>1; + Bs += srow[i-bstep]; + ng++; + } + if( gradS < T ) + { + Rs += (srow[i+bstep*2-1] + srow[i+bstep*2+1])>>1; + Gs += (srow[i+bstep*2] + srow[i])>>1; + Bs += srow[i+bstep]; + ng++; + } + if( gradW < T ) + { + Rs += srow[i-1]; + Gs += (srow[i-2] + srow[i])>>1; + Bs += (srow[i-bstep-2]+srow[i+bstep-2])>>1; + ng++; + } + if( gradE < T ) + { + Rs += srow[i+1]; + Gs += (srow[i+2] + srow[i])>>1; + Bs += (srow[i-bstep+2]+srow[i+bstep+2])>>1; + ng++; + } + if( gradNE < T ) + { + Rs += (srow[i-bstep*2+1] + srow[i+1])>>1; + Gs += srow[i-bstep+1]; + Bs += (srow[i-bstep] + srow[i-bstep+2])>>1; + ng++; + } + if( gradSW < T ) + { + Rs += (srow[i+bstep*2-1] + srow[i-1])>>1; + Gs += srow[i+bstep-1]; + Bs += (srow[i+bstep] + srow[i+bstep-2])>>1; + ng++; + } + if( gradNW < T ) + { + Rs += (srow[i-bstep*2-1] + srow[i-1])>>1; + Gs += srow[i-bstep-1]; + Bs += (srow[i-bstep-2]+srow[i-bstep])>>1; + ng++; + } + if( gradSE < T ) + { + Rs += (srow[i+bstep*2+1] + srow[i+1])>>1; + Gs += srow[i+bstep+1]; + Bs += (srow[i+bstep+2]+srow[i+bstep])>>1; + ng++; + } + G = srow[i]; + R = G + cvRound((Rs - Gs)*scale[ng]); + B = G + cvRound((Bs - Gs)*scale[ng]); + } + dstrow[blueIdx] = CV_CAST_8U(B); + dstrow[1] = CV_CAST_8U(G); + dstrow[blueIdx^2] = CV_CAST_8U(R); + greenCell = !greenCell; + } + greenCell0 = !greenCell0; + blueIdx ^= 2; + } + + return CV_OK; +} + /****************************************************************************************\ * The main function * \****************************************************************************************/ @@ -2222,7 +2463,9 @@ cvCvtColor( const CvArr* srcarr, CvArr* dstarr, int code ) if( CV_IS_MAT_CONT(src->type & dst->type) && code != CV_BayerBG2BGR && code != CV_BayerGB2BGR && - code != CV_BayerRG2BGR && code != CV_BayerGR2BGR ) + code != CV_BayerRG2BGR && code != CV_BayerGR2BGR && + code != CV_BayerBG2BGR_VNG && code != CV_BayerGB2BGR_VNG && + code != CV_BayerRG2BGR_VNG && code != CV_BayerGR2BGR_VNG ) { size.width *= size.height; size.height = 1; @@ -2470,6 +2713,22 @@ cvCvtColor( const CvArr* srcarr, CvArr* dstarr, int code ) func1 = (CvColorCvtFunc1)icvBayer2BGR_8u_C1C3R; param[0] = code; // conversion code break; + + case CV_BayerBG2BGR_VNG: + case CV_BayerGB2BGR_VNG: + case CV_BayerRG2BGR_VNG: + case CV_BayerGR2BGR_VNG: + if( src_cn != 1 || dst_cn != 3 ) + CV_Error( CV_BadNumChannels, + "Incorrect number of channels for this conversion code" ); + + if( depth != CV_8U ) + CV_Error( CV_BadDepth, + "Bayer pattern can be converted only to 8-bit 3-channel BGR/RGB image" ); + + func1 = (CvColorCvtFunc1)icvBayer2BGR_VNG_8u_C1C3R; + param[0] = code; // conversion code + break; default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); } @@ -2532,6 +2791,11 @@ void cv::cvtColor( const Mat& src, Mat& dst, int code, int dst_cn ) case CV_BayerGB2BGR: case CV_BayerRG2BGR: case CV_BayerGR2BGR: + + case CV_BayerBG2BGR_VNG: + case CV_BayerGB2BGR_VNG: + case CV_BayerRG2BGR_VNG: + case CV_BayerGR2BGR_VNG: case CV_BGRA2BGR: case CV_RGBA2BGR: -- GitLab