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.

This commit is contained in:
catree 2024-03-28 16:26:43 +01:00
parent f87e1efd2a
commit d81cd13bb3
2 changed files with 47 additions and 282 deletions

View File

@ -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 <taka-qce@ls-a.jp>
*
*/
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 &currentBuffer)
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 &currentBuffer)
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;

View File

@ -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<Format_Channels_Depth> 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 },