diff --git a/ChangeLog b/ChangeLog index 3f36306..1ab0397 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-12-04: +- RAW8 format support for SVB camera, also fixed RGB24 format +- many bug fixes for RGB conversions +- DNG and SER file format fixes + 2022-11-29: - Crash on invalid dumpfile solved. - closing and reopening of windows is working now. diff --git a/convert.cc b/convert.cc index 8b961a3..fdd3e7c 100644 --- a/convert.cc +++ b/convert.cc @@ -21,6 +21,7 @@ uint32_t convert_pixelformats [] = { V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_SGRBG16, + V4L2_PIX_FMT_SGRBG8, 0 }; @@ -246,17 +247,17 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { /* read the pixel */ - ptrsrc++; r = *(ptrsrc++); g = *(ptrsrc++); b = *(ptrsrc++); + ptrsrc++; /* only paint the image if the source is within the destination */ if (xd < dest->w) { /* set the pixel */ - *(ptrdst++) = b; - *(ptrdst++) = g; *(ptrdst++) = r; + *(ptrdst++) = g; + *(ptrdst++) = b; xd++; } } @@ -273,17 +274,17 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr for (xs = 0, xd = 0; xs < (signed int)srcw; xs++) { /* read the pixel */ + ptrsrc++; b = *(ptrsrc++); g = *(ptrsrc++); r = *(ptrsrc++); - ptrsrc++; /* only paint the image if the source is within the destination */ if (xd < dest->w) { /* set the pixel */ - *(ptrdst++) = b; - *(ptrdst++) = g; *(ptrdst++) = r; + *(ptrdst++) = g; + *(ptrdst++) = b; xd++; } } @@ -306,9 +307,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr /* only paint the image if the source is within the destination */ if (xd < dest->w) { /* set the pixel */ - *(ptrdst++) = b; - *(ptrdst++) = g; *(ptrdst++) = r; + *(ptrdst++) = g; + *(ptrdst++) = b; xd++; } } @@ -332,9 +333,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr /* only paint the image if the source is within the destination */ if (xd < dest->w) { /* set the pixel */ - *(ptrdst++) = b; - *(ptrdst++) = g; *(ptrdst++) = r; + *(ptrdst++) = g; + *(ptrdst++) = b; xd++; } } @@ -347,9 +348,18 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr break; case (V4L2_PIX_FMT_SGRBG16): - printf ("%s:%d %s debayer:%d\n", __FILE__, __LINE__, __FUNCTION__, config.debayer_mode); - if (config.debayer_mode == 0) debayer_grbg16_simple ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); - else debayer_grbg16_bilinear ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); + printf ("%s:%d %s debayer:%d\n", __FILE__, __LINE__, __FUNCTION__, config.debayer_mode); + if (config.debayer_mode == 0) + debayer_grbg16_simple ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); + else + debayer_grbg16_bilinear ((uint16_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); + break; + + case (V4L2_PIX_FMT_SGRBG8): + if (config.debayer_mode == 0) + debayer_grbg8_simple ((uint8_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); + else + debayer_grbg8_bilinear ((uint8_t *)ptrsrc, srcw, srch, ptrdst, dest->w, dest->h); break; case (V4L2_PIX_FMT_UYVY): @@ -373,9 +383,9 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr /* only paint the image if the source is within the destination */ if (xd < dest->w) { /* set the pixel */ - *(ptrdst++) = b; - *(ptrdst++) = g; *(ptrdst++) = r; + *(ptrdst++) = g; + *(ptrdst++) = b; xd++; } } diff --git a/debayer.cc b/debayer.cc index 87f8550..fdcc03c 100644 --- a/debayer.cc +++ b/debayer.cc @@ -66,7 +66,8 @@ void debayer_grbg16_simple (uint16_t * src, int src_w, int src_h, #define DNRI (*(src+src_w+1)) #define BITCONV(d) ((d>>8) & 0xff) -#define STORE *(dst++) = BITCONV(r); *(dst++) = BITCONV(g); *(dst++) = BITCONV(b); src++; +#define STORE *(dst++) = BITCONV(r); *(dst++) = BITCONV(g); *(dst++) = BITCONV(b); src++; +#define STORE8 *(dst++) = (r & 0xff); *(dst++) = (g & 0xff); *(dst++) = (b & 0xff); src++; /* @@ -189,3 +190,177 @@ void debayer_grbg16_bilinear (uint16_t * src, int src_w, int src_h, b = LE; STORE; } + +/* + The function converts a 8bit GRBG 2x2 CFA coded image into an 8bit + RGB image by setting the missing RGB values to zero. + */ +void debayer_grbg8_simple (uint8_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h) { + + // GG RR + // BB GG + uint8_t t; + uint8_t r, g, b; + int ys, yd, xs, xd; + + for (ys = 0, yd = 0; ys < src_h && yd < dst_h; ys++, yd++) { + for (xs = 0, xd = 0; xs < src_w; xs++) { + + /* read the pixel but only the higher 8bit, assuming data is little endian */ + t = *(src++); + + if (xs & 1) { + if (ys & 1) { + // lower right green pixel + b = 0; g = t; r = 0; + } else { + // upper right red pixel + b = 0; g = 0; r = t; + } + } else { + if (ys & 1) { + // lower left blue pixel + b = t; g = 0; r = 0; + } else { + // upper left green pixel + b = 0; g = t; r = 0; + } + } + + /* only paint the image if the source is within the destination */ + if (xd < dst_w) { + /* set the pixel */ + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + xd++; + } + } + + /* if the source image is too small ignore the other places */ + if (xd < dst_w) + dst += 3 * (dst_w - xd); + } +} + +/* + The function converts a 8bit GRBG 2x2 CFA coded image into an 8bit + RGB image by bilinear interpolation. + */ +void debayer_grbg8_bilinear (uint8_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h) { + + // GG RR GG RR + // BB GG BB GG + // GG RR GG RR + // BB GG BB GG + uint16_t r, g, b; + int xs, ys; + + // start with upper left pixel (green) + r = RI; + g = CE; + b = DN; + STORE8; + + // upper first line, starts with RR GG RR ... + for (xs = 1; xs < src_w - 1; xs+=2) { + // red pixel + r = CE; + g = (LE + RI + DN) / 3; + b = (DNLE + DNRI) / 2; + STORE8; + // green pixel + r = (LE + RI) / 2; + g = CE; + b = DN; + STORE8; + } + + // upper right pixel (red) + r = CE; + g = (DN + LE) / 2; + b = DNLE; + STORE8; + + // go through the "body" of the image + for (ys = 1; ys < src_h - 1; ys+=2) { + + // every second line with BB GG BB GG (start at 2nd line) + + // left hand pixel (blue) + r = (UPRI + DNRI) / 2; + g = (UP + DN + RI) / 3; + b = CE; + STORE8; + for (xs = 1; xs < src_w - 1; xs+=2) { + // green pixel + r = (UP + DN) / 2; + g = CE; + b = (LE + RI) / 2; + STORE8; + // blue pixel + r = (UPLE + UPRI + DNLE + DNRI) / 4; + g = (LE + RI + UP + DN) / 4; + b = CE; + STORE8; + } + // last pixel in line (green) + r = (UP + DN) / 2; + g = CE; + b = LE; + STORE8; + + // every second line with GG RR GG RR ... (start at 3rd line) + + // left hand pixel (green) + r = RI; + g = CE; + b = (UP + DN) / 2; + STORE8; + for (xs = 1; xs < src_w - 1; xs+=2) { + // red pixel + r = CE; + g = (LE + RI + UP + DN) / 4; + b = (UPLE + UPRI + DNLE + DNRI) / 4; + STORE8; + // green pixel + r = (LE + RI) / 2; + g = CE; + b = (UP + DN) / 2; + STORE8; + } + // last pixel in line (red) + r = CE; + g = (UP + DN + LE) / 3; + b = (UPLE + DNLE) / 2; + STORE8; + } + + // bottom left pixel + r = UPRI; + g = (UP + RI) / 2; + b = CE; + STORE8; + + // last line starting with GG BB GG ... + for (xs = 1; xs < src_w - 1; xs+=2) { + // green pixel + r = UP; + g = CE; + b = (LE + RI) / 2; + STORE8; + // blue pixel + r = (UPLE + UPRI) / 2; + g = (LE + UP + RI) / 2; + b = CE; + STORE8; + } + + // bottom right pixel (green) + r = UP; + g = CE; + b = LE; + STORE8; +} diff --git a/debayer.h b/debayer.h index 461465d..37816ea 100644 --- a/debayer.h +++ b/debayer.h @@ -3,9 +3,12 @@ void debayer_grbg16_simple (uint16_t * src, int src_w, int src_h, uint8_t * dst, int dst_w, int dst_h); +void debayer_grbg8_simple (uint8_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h); void debayer_grbg16_bilinear (uint16_t * src, int src_w, int src_h, uint8_t * dst, int dst_w, int dst_h); - +void debayer_grbg8_bilinear (uint8_t * src, int src_w, int src_h, + uint8_t * dst, int dst_w, int dst_h); #endif diff --git a/videodev-svbcam.cc b/videodev-svbcam.cc index 24d3086..59a84a4 100644 --- a/videodev-svbcam.cc +++ b/videodev-svbcam.cc @@ -117,7 +117,7 @@ int VideoDev_SVBCam::Open() { Close(); return VDEV_STATUS_ERROR; } - printf ("%s:%d %s height: %ld width: %ld\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, camprop.MaxWidth); + printf ("%s:%d %s MaxHeight: %ld MaxWidth: %ld\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, camprop.MaxWidth); for(int i=0; i < 8 && camprop.SupportedVideoFormat[i] != SVB_IMG_END; i++) { printf ("%s:%d %s VideoFormat Index:%d ", __FILE__, __LINE__, __FUNCTION__, i); @@ -162,7 +162,7 @@ int VideoDev_SVBCam::Open() { printf("\t\tSVB_IMG_END\n"); break; default: - printf ("\t\tunbekannt\n"); + printf ("\t\tunknown\n"); break; } } @@ -178,7 +178,7 @@ int VideoDev_SVBCam::Open() { print_error(err); return VDEV_STATUS_ERROR; } - printf ("%s:%d %s Got Control idx: %d name:%s desc:%s [%ld - %ld]\n", __FILE__, __LINE__, __FUNCTION__, + printf ("%s:%d %s Got Control idx:%d name:%s desc:%s [%ld - %ld]\n", __FILE__, __LINE__, __FUNCTION__, i, camcontrols[i].Name, camcontrols[i].Description, (long)camcontrols[i].MinValue, (long)camcontrols[i].MaxValue); vctl.name = (char*)camcontrols[i].Name; vctl.id = i; @@ -209,26 +209,26 @@ int VideoDev_SVBCam::Open() { return VDEV_STATUS_ERROR; } break; - case (V4L2_PIX_FMT_RGB32): + case (V4L2_PIX_FMT_BGR32): if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB32)) != SVB_SUCCESS) { print_error(err); return VDEV_STATUS_ERROR; } break; - case (V4L2_PIX_FMT_RGB24): - if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) { - print_error(err); - return VDEV_STATUS_ERROR; - } - break; + case (V4L2_PIX_FMT_BGR24): + if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + break; default: - conf_format = convert_from_pixelformat(V4L2_PIX_FMT_RGB24); - inframe_pixfmt = V4L2_PIX_FMT_RGB24; - if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) { - print_error(err); - return VDEV_STATUS_ERROR; - } - break; + conf_format = convert_from_pixelformat(V4L2_PIX_FMT_BGR24); + inframe_pixfmt = V4L2_PIX_FMT_BGR24; + if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + break; } @@ -264,8 +264,8 @@ int VideoDev_SVBCam::Close() { /* - * prepare inframe for raw picture data, will hold a video frame with 16bit per channel - * inframe size = 2*3*W*H + * prepare inframe for raw picture data, will hold a video frame with 16bit per channel or BGR32/BGR24 + * inframe size = 4*W*H * send the start capture signal to the cam */ int VideoDev_SVBCam::CaptureStart() { @@ -281,7 +281,7 @@ int VideoDev_SVBCam::CaptureStart() { // // allocate memory for frame data if (inframe != NULL) free (inframe); - inframe_size = 6 * inframe_w * inframe_h; + inframe_size = 4 * inframe_w * inframe_h; inframe = (unsigned char*) malloc(inframe_size); ConvertStart(&cdata, inframe_pixfmt); @@ -368,14 +368,53 @@ int VideoDev_SVBCam::GetDeviceFormats(string device, std::list *formats) Close(); return VDEV_STATUS_ERROR; } - printf ("%s:%d %s height: %ld width: %ld maxdepth:%d BayerPattern:%d\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, - camprop.MaxWidth, camprop.MaxBitDepth, camprop.BayerPattern); + printf ("%s:%d %s MaxHeight:%ld MaxWidth:%ld MaxDepth:%d\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, + camprop.MaxWidth, camprop.MaxBitDepth); + char pattern[5]; + switch(camprop.BayerPattern) { + case SVB_BAYER_RG: + strcpy(pattern, "RGGB"); + break; + case SVB_BAYER_BG: + strcpy(pattern, "BGGR"); + break; + case SVB_BAYER_GR: + strcpy(pattern, "GRBG"); + break; + case SVB_BAYER_GB: + strcpy(pattern, "GBRG"); + break; + default: + strcpy(pattern, "NONE"); + break; + } + printf ("%s:%d %s BayerPattern:%s Color:%d Binning: \n", __FILE__, __LINE__, __FUNCTION__, pattern, camprop.IsColorCam); + for(int i=0; i < 16 && camprop.SupportedBins[i] != 0; i++) { + printf ("%s:%d %s Binning Index:%d ", __FILE__, __LINE__, __FUNCTION__, i); + printf ("\t\%dx%d\n", camprop.SupportedBins[i], camprop.SupportedBins[i]); + } for(int i=0; i < 8 && camprop.SupportedVideoFormat[i] != SVB_IMG_END; i++) { printf ("%s:%d %s VideoFormat Index:%d ", __FILE__, __LINE__, __FUNCTION__, i); switch (camprop.SupportedVideoFormat[i]) { case SVB_IMG_RAW8: printf("\t\tSVB_IMG_RAW8\n"); + switch(camprop.BayerPattern) { + case SVB_BAYER_RG: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SRGGB8)); + break; + case SVB_BAYER_BG: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SBGGR8)); + break; + case SVB_BAYER_GR: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGRBG8)); + break; + case SVB_BAYER_GB: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGBRG8)); + break; + default: + break; + } break; case SVB_IMG_RAW10: printf("\t\tSVB_IMG_RAW10\n"); @@ -388,7 +427,22 @@ int VideoDev_SVBCam::GetDeviceFormats(string device, std::list *formats) break; case SVB_IMG_RAW16: printf("\t\tSVB_IMG_RAW16\n"); - formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGRBG16)); + switch(camprop.BayerPattern) { + case SVB_BAYER_RG: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SRGGB16)); + break; + case SVB_BAYER_BG: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SBGGR16)); + break; + case SVB_BAYER_GR: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGRBG16)); + break; + case SVB_BAYER_GB: + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_SGBRG16)); + break; + default: + break; + } break; case SVB_IMG_Y8: printf("\t\tSVB_IMG_Y8\n"); @@ -407,17 +461,17 @@ int VideoDev_SVBCam::GetDeviceFormats(string device, std::list *formats) break; case SVB_IMG_RGB24: printf("\t\tSVB_IMG_RGB24\n"); - formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_RGB24)); + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_BGR24)); break; case SVB_IMG_RGB32: printf("\t\tSVB_IMG_RGB32\n"); - formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_RGB32)); + formats->push_back(convert_from_pixelformat(V4L2_PIX_FMT_BGR32)); break; case SVB_IMG_END: printf("\t\tSVB_IMG_END\n"); break; default: - printf ("\t\tunbekannt\n"); + printf ("\t\tunknown\n"); break; } }