From d81cd13bb37a3827998fb98359827718a8478b13 Mon Sep 17 00:00:00 2001 From: catree Date: Thu, 28 Mar 2024 16:26:43 +0100 Subject: [PATCH] Use cvtColor() for Bayer image color demosaicing and for V4L2_PIX_FMT_SRGGB8, V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SGBRG8, V4L2_PIX_FMT_SGRBG8 options. Update modules/videoio/test/test_v4l2.cpp test file. --- modules/videoio/src/cap_v4l.cpp | 308 +++-------------------------- modules/videoio/test/test_v4l2.cpp | 21 +- 2 files changed, 47 insertions(+), 282 deletions(-) diff --git a/modules/videoio/src/cap_v4l.cpp b/modules/videoio/src/cap_v4l.cpp index 48cc0062da..531af03d1a 100644 --- a/modules/videoio/src/cap_v4l.cpp +++ b/modules/videoio/src/cap_v4l.cpp @@ -1321,262 +1321,6 @@ yuv411p_to_rgb24(int width, int height, } } -/* - * BAYER2RGB24 ROUTINE TAKEN FROM: - * - * Sonix SN9C10x based webcam basic I/F routines - * Takafumi Mizuno - * - */ -static void bayer2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst) -{ - long int i; - unsigned char *rawpt, *scanpt; - long int size; - - rawpt = src; - scanpt = dst; - size = WIDTH*HEIGHT; - - for ( i = 0; i < size; i++ ) { - if ( (i/WIDTH) % 2 == 0 ) { - if ( (i % 2) == 0 ) { - /* B */ - if ( (i > WIDTH) && ((i % WIDTH) > 0) ) { - *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ - *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ - *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ - *(rawpt+WIDTH)+*(rawpt-WIDTH))/4; /* G */ - *scanpt++ = *rawpt; /* B */ - } else { - /* first line or left column */ - *scanpt++ = *(rawpt+WIDTH+1); /* R */ - *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; /* G */ - *scanpt++ = *rawpt; /* B */ - } - } else { - /* (B)G */ - if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) { - *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* R */ - *scanpt++ = *rawpt; /* G */ - *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ - } else { - /* first line or right column */ - *scanpt++ = *(rawpt+WIDTH); /* R */ - *scanpt++ = *rawpt; /* G */ - *scanpt++ = *(rawpt-1); /* B */ - } - } - } else { - if ( (i % 2) == 0 ) { - /* G(R) */ - if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) { - *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ - *scanpt++ = *rawpt; /* G */ - *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* B */ - } else { - /* bottom line or left column */ - *scanpt++ = *(rawpt+1); /* R */ - *scanpt++ = *rawpt; /* G */ - *scanpt++ = *(rawpt-WIDTH); /* B */ - } - } else { - /* R */ - if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) { - *scanpt++ = *rawpt; /* R */ - *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ - *(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ - *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ - *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* B */ - } else { - /* bottom line or right column */ - *scanpt++ = *rawpt; /* R */ - *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */ - *scanpt++ = *(rawpt-WIDTH-1); /* B */ - } - } - } - rawpt++; - } - -} - -// SGBRG to RGB24 -// for some reason, red and blue needs to be swapped -// at least for 046d:092f Logitech, Inc. QuickCam Express Plus to work -//see: http://www.siliconimaging.com/RGB%20Bayer.htm -//and 4.6 at http://tldp.org/HOWTO/html_single/libdc1394-HOWTO/ -static void sgbrg2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst) -{ - long int i; - unsigned char *rawpt, *scanpt; - long int size; - - rawpt = src; - scanpt = dst; - size = WIDTH*HEIGHT; - - for ( i = 0; i < size; i++ ) - { - if ( (i/WIDTH) % 2 == 0 ) //even row - { - if ( (i % 2) == 0 ) //even pixel - { - if ( (i > WIDTH) && ((i % WIDTH) > 0) ) - { - *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = (*(rawpt-WIDTH) + *(rawpt+WIDTH))/2; /* B */ - } else - { - /* first line or left column */ - - *scanpt++ = *(rawpt+1); /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = *(rawpt+WIDTH); /* B */ - } - } else //odd pixel - { - if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) - { - *scanpt++ = *(rawpt); /* R */ - *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ - *scanpt++ = (*(rawpt-WIDTH-1) + *(rawpt-WIDTH+1) + *(rawpt+WIDTH-1) + *(rawpt+WIDTH+1))/4; /* B */ - } else - { - /* first line or right column */ - - *scanpt++ = *(rawpt); /* R */ - *scanpt++ = (*(rawpt-1)+*(rawpt+WIDTH))/2; /* G */ - *scanpt++ = *(rawpt+WIDTH-1); /* B */ - } - } - } else - { //odd row - if ( (i % 2) == 0 ) //even pixel - { - if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) - { - *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+*(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ - *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ - *scanpt++ = *(rawpt); /* B */ - } else - { - /* bottom line or left column */ - - *scanpt++ = *(rawpt-WIDTH+1); /* R */ - *scanpt++ = (*(rawpt+1)+*(rawpt-WIDTH))/2; /* G */ - *scanpt++ = *(rawpt); /* B */ - } - } else - { //odd pixel - if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) - { - *scanpt++ = (*(rawpt-WIDTH)+*(rawpt+WIDTH))/2; /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ - } else - { - /* bottom line or right column */ - - *scanpt++ = (*(rawpt-WIDTH)); /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = (*(rawpt-1)); /* B */ - } - } - } - rawpt++; - } -} - -// SGRBG to RGB24 -static void sgrbg2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst) -{ - long int i; - unsigned char *rawpt, *scanpt; - long int size; - - rawpt = src; - scanpt = dst; - size = WIDTH*HEIGHT; - - for ( i = 0; i < size; i++ ) - { - if ( (i/WIDTH) % 2 == 0 ) //even row - { - if ( (i % 2) == 0 ) //even pixel - { - if ( (i > WIDTH) && ((i % WIDTH) > 0) ) - { - *scanpt++ = (*(rawpt-WIDTH) + *(rawpt+WIDTH))/2; /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ - } else - { - /* first line or left column */ - - *scanpt++ = *(rawpt+WIDTH); /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = *(rawpt+1); /* B */ - } - } else //odd pixel - { - if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) - { - *scanpt++ = (*(rawpt-WIDTH-1) + *(rawpt-WIDTH+1) + - *(rawpt+WIDTH-1) + *(rawpt+WIDTH+1)) / 4; /* R */ - *scanpt++ = (*(rawpt-1) + *(rawpt+1) + - *(rawpt-WIDTH) + *(rawpt+WIDTH)) / 4; /* G */ - *scanpt++ = *(rawpt); /* B */ - } else - { - /* first line or right column */ - - *scanpt++ = *(rawpt+WIDTH-1); /* R */ - *scanpt++ = (*(rawpt-1)+*(rawpt+WIDTH))/2; /* G */ - *scanpt++ = *(rawpt); /* B */ - } - } - } else - { //odd row - if ( (i % 2) == 0 ) //even pixel - { - if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) - { - *scanpt++ = *(rawpt); /* R */ - *scanpt++ = (*(rawpt-1) + *(rawpt+1)+ - *(rawpt-WIDTH) + *(rawpt+WIDTH)) / 4; /* G */ - *scanpt++ = (*(rawpt-WIDTH-1) + *(rawpt-WIDTH+1) + - *(rawpt+WIDTH-1) + *(rawpt+WIDTH+1)) / 4; /* B */ - } else - { - /* bottom line or left column */ - - *scanpt++ = *(rawpt); /* R */ - *scanpt++ = (*(rawpt+1)+*(rawpt-WIDTH))/2; /* G */ - *scanpt++ = *(rawpt-WIDTH+1); /* B */ - } - } else - { //odd pixel - if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) - { - *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = (*(rawpt-WIDTH)+*(rawpt+WIDTH))/2; /* B */ - } else - { - /* bottom line or right column */ - - *scanpt++ = (*(rawpt-1)); /* R */ - *scanpt++ = *(rawpt); /* G */ - *scanpt++ = (*(rawpt-WIDTH)); /* B */ - } - } - } - rawpt++; - } -} - #define CLAMP(x) ((x)<0?0:((x)>255)?255:(x)) typedef struct { @@ -1778,28 +1522,6 @@ void CvCaptureCAM_V4L::convertToRgb(const Buffer ¤tBuffer) yuv411p_to_rgb24(imageSize.width, imageSize.height, start, (unsigned char*)frame.imageData); return; - case V4L2_PIX_FMT_SBGGR8: - bayer2rgb24(imageSize.width, imageSize.height, - start, (unsigned char*)frame.imageData); - return; - - case V4L2_PIX_FMT_SN9C10X: - sonix_decompress_init(); - sonix_decompress(imageSize.width, imageSize.height, - start, (unsigned char*)buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start); - - bayer2rgb24(imageSize.width, imageSize.height, - (unsigned char*)buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start, - (unsigned char*)frame.imageData); - return; - case V4L2_PIX_FMT_SGBRG8: - sgbrg2rgb24(imageSize.width, imageSize.height, - start, (unsigned char*)frame.imageData); - return; - case V4L2_PIX_FMT_SGRBG8: - sgrbg2rgb24(imageSize.width, imageSize.height, - start, (unsigned char*)frame.imageData); - return; default: break; } @@ -1872,6 +1594,36 @@ void CvCaptureCAM_V4L::convertToRgb(const Buffer ¤tBuffer) cv::cvtColor(temp, destination, COLOR_GRAY2BGR); return; } + case V4L2_PIX_FMT_SN9C10X: + { + sonix_decompress_init(); + sonix_decompress(imageSize.width, imageSize.height, + start, (unsigned char*)buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start); + + cv::Mat cv_buf(imageSize, CV_8UC1, buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start); + cv::cvtColor(cv_buf, destination, COLOR_BayerRG2BGR); + return; + } + case V4L2_PIX_FMT_SRGGB8: + { + cv::cvtColor(cv::Mat(imageSize, CV_8UC1, start), destination, COLOR_BayerBG2BGR); + return; + } + case V4L2_PIX_FMT_SBGGR8: + { + cv::cvtColor(cv::Mat(imageSize, CV_8UC1, start), destination, COLOR_BayerRG2BGR); + return; + } + case V4L2_PIX_FMT_SGBRG8: + { + cv::cvtColor(cv::Mat(imageSize, CV_8UC1, start), destination, COLOR_BayerGR2BGR); + return; + } + case V4L2_PIX_FMT_SGRBG8: + { + cv::cvtColor(cv::Mat(imageSize, CV_8UC1, start), destination, COLOR_BayerGB2BGR); + return; + } case V4L2_PIX_FMT_GREY: cv::cvtColor(cv::Mat(imageSize, CV_8UC1, start), destination, COLOR_GRAY2BGR); break; diff --git a/modules/videoio/test/test_v4l2.cpp b/modules/videoio/test/test_v4l2.cpp index 1c4917bfca..5bb1a1f5a3 100644 --- a/modules/videoio/test/test_v4l2.cpp +++ b/modules/videoio/test/test_v4l2.cpp @@ -70,6 +70,7 @@ TEST_P(videoio_v4l2, formats) const string device = devs[0]; const Size sz(640, 480); const Format_Channels_Depth params = GetParam(); + const Size esz(sz.width * params.mul_width, sz.height * params.mul_height); { // Case with RAW output @@ -83,7 +84,17 @@ TEST_P(videoio_v4l2, formats) Mat img; EXPECT_TRUE(cap.grab()); EXPECT_TRUE(cap.retrieve(img)); - EXPECT_EQ(Size(sz.width * params.mul_width, sz.height * params.mul_height), img.size()); + if (params.pixel_format == V4L2_PIX_FMT_SRGGB8 || + params.pixel_format == V4L2_PIX_FMT_SBGGR8 || + params.pixel_format == V4L2_PIX_FMT_SGBRG8 || + params.pixel_format == V4L2_PIX_FMT_SGRBG8) + { + EXPECT_EQ((size_t)esz.area(), img.total()); + } + else + { + EXPECT_EQ(esz, img.size()); + } EXPECT_EQ(params.channels, img.channels()); EXPECT_EQ(params.depth, img.depth()); } @@ -116,9 +127,11 @@ vector all_params = { // { V4L2_PIX_FMT_JPEG, 1, CV_8U, 1.f, 1.f }, { V4L2_PIX_FMT_YUYV, 2, CV_8U, 1.f, 1.f }, { V4L2_PIX_FMT_UYVY, 2, CV_8U, 1.f, 1.f }, -// { V4L2_PIX_FMT_SBGGR8, 1, CV_8U, 1.f, 1.f }, -// { V4L2_PIX_FMT_SN9C10X, 3, CV_8U, 1.f, 1.f }, -// { V4L2_PIX_FMT_SGBRG8, 1, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_SN9C10X, 3, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_SRGGB8, 1, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_SBGGR8, 1, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_SGBRG8, 1, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_SGRBG8, 1, CV_8U, 1.f, 1.f }, { V4L2_PIX_FMT_RGB24, 3, CV_8U, 1.f, 1.f }, { V4L2_PIX_FMT_Y16, 1, CV_16U, 1.f, 1.f }, { V4L2_PIX_FMT_Y16_BE, 1, CV_16U, 1.f, 1.f },