From 7982e9e30608a3be701008cee03211aa455bbb7d Mon Sep 17 00:00:00 2001 From: Gursimar Date: Fri, 11 Jul 2025 16:33:01 +0530 Subject: [PATCH 1/7] Added fastcv color conversions --- modules/fastcv/include/opencv2/fastcv.hpp | 1 + .../fastcv/include/opencv2/fastcv/color.hpp | 37 ++ modules/fastcv/src/color.cpp | 343 ++++++++++++++++++ 3 files changed, 381 insertions(+) create mode 100644 modules/fastcv/include/opencv2/fastcv/color.hpp create mode 100644 modules/fastcv/src/color.cpp diff --git a/modules/fastcv/include/opencv2/fastcv.hpp b/modules/fastcv/include/opencv2/fastcv.hpp index 6626c4c9b5..b6b2843932 100644 --- a/modules/fastcv/include/opencv2/fastcv.hpp +++ b/modules/fastcv/include/opencv2/fastcv.hpp @@ -37,6 +37,7 @@ #include "opencv2/fastcv/fft_dsp.hpp" #include "opencv2/fastcv/edges_dsp.hpp" #include "opencv2/fastcv/blur_dsp.hpp" +#include "opencv2/fastcv/color.hpp" /** * @defgroup fastcv Module-wrapper for FastCV hardware accelerated functions diff --git a/modules/fastcv/include/opencv2/fastcv/color.hpp b/modules/fastcv/include/opencv2/fastcv/color.hpp new file mode 100644 index 0000000000..79107701d4 --- /dev/null +++ b/modules/fastcv/include/opencv2/fastcv/color.hpp @@ -0,0 +1,37 @@ +#include + +namespace cv +{ +namespace fastcv +{ + +/** the color conversion codes +@see @ref imgproc_color_conversions +@ingroup imgproc_color_conversions + */ +enum ColorConversionCodes { + // FastCV-specific color conversion codes (avoid collision with OpenCV core) + COLOR_YUV2YUV444sp_NV12 = 1, //!< FastCV: YCbCr420PseudoPlanar to YCbCr444PseudoPlanar + COLOR_YUV2YUV422sp_NV12 = 2, //!< FastCV: YCbCr420PseudoPlanar to YCbCr422PseudoPlanar + COLOR_YUV422sp2YUV444sp = 3, //!< FastCV: YCbCr422PseudoPlanar to YCbCr444PseudoPlanar + COLOR_YUV422sp2YUV_NV12 = 4, //!< FastCV: YCbCr422PseudoPlanar to YCbCr420PseudoPlanar + COLOR_YUV444sp2YUV422sp = 5, //!< FastCV: YCbCr444PseudoPlanar to YCbCr422PseudoPlanar + COLOR_YUV444sp2YUV_NV12 = 6, //!< FastCV: YCbCr444PseudoPlanar to YCbCr420PseudoPlanar + COLOR_YUV2RGB565_NV12 = 7, //!< FastCV: YCbCr420PseudoPlanar to RGB565 + COLOR_YUV422sp2RGB565 = 8, //!< FastCV: YCbCr422PseudoPlanar to RGB565 + COLOR_YUV422sp2RGB = 9, //!< FastCV: YCbCr422PseudoPlanar to RGB888 + COLOR_YUV422sp2RGBA = 10, //!< FastCV: YCbCr422PseudoPlanar to RGBA8888 + COLOR_YUV444sp2RGB565 = 11, //!< FastCV: YCbCr444PseudoPlanar to RGB565 + COLOR_YUV444sp2RGB = 12, //!< FastCV: YCbCr444PseudoPlanar to RGB888 + COLOR_YUV444sp2RGBA = 13, //!< FastCV: YCbCr444PseudoPlanar to RGBA8888 + COLOR_RGB2YUV_NV12 = 14, //!< FastCV: RGB888 to YCbCr420PseudoPlanar + COLOR_RGB5652YUV444sp = 15, //!< FastCV: RGB565 to YCbCr444PseudoPlanar + COLOR_RGB5652YUV422sp = 16, //!< FastCV: RGB565 to YCbCr422PseudoPlanar + COLOR_RGB5652YUV_NV12 = 17, //!< FastCV: RGB565 to YCbCr420PseudoPlanar + COLOR_RGB2YUV444sp = 18, //!< FastCV: RGB888 to YCbCr444PseudoPlanar + COLOR_RGB2YUV422sp = 19, //!< FastCV: RGB888 to YCbCr422PseudoPlanar +}; + +CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code); + +}}; //cv::fastcv namespace end \ No newline at end of file diff --git a/modules/fastcv/src/color.cpp b/modules/fastcv/src/color.cpp new file mode 100644 index 0000000000..e06050697d --- /dev/null +++ b/modules/fastcv/src/color.cpp @@ -0,0 +1,343 @@ +#include "precomp.hpp" + +namespace cv { namespace fastcv { + +static void fastcvColorWrapper(const Mat& src, Mat& dst, int code); + +inline double heightFactor(int fmt /*420 / 422 / 444*/) +{ + switch (fmt) + { + case 420: return 1.5; // YUV420 has 1.5× rows + case 422: case 444: return 2.0; // YUV422/444 have 2× rows + default: return 1.0; // packed RGB565/RGB888 → no extra plane + } +} + +inline void getFormats(int code, int& srcFmt, int& dstFmt) +{ + switch (code) + { + case COLOR_YUV2YUV444sp_NV12: srcFmt=420; dstFmt=444; break; + case COLOR_YUV2YUV422sp_NV12: srcFmt=420; dstFmt=422; break; + case COLOR_YUV422sp2YUV444sp: srcFmt=422; dstFmt=444; break; + case COLOR_YUV422sp2YUV_NV12: srcFmt=422; dstFmt=420; break; + case COLOR_YUV444sp2YUV422sp: srcFmt=444; dstFmt=422; break; + case COLOR_YUV444sp2YUV_NV12: srcFmt=444; dstFmt=420; break; + case COLOR_YUV2RGB565_NV12: srcFmt=420; dstFmt=565; break; + case COLOR_YUV422sp2RGB565: srcFmt=422; dstFmt=565; break; + case COLOR_YUV422sp2RGB: srcFmt=422; dstFmt=888; break; + case COLOR_YUV422sp2RGBA:srcFmt=422; dstFmt=8888; break; + case COLOR_YUV444sp2RGB565: srcFmt=444; dstFmt=565; break; + case COLOR_YUV444sp2RGB: srcFmt=444; dstFmt=888; break; + case COLOR_YUV444sp2RGBA:srcFmt=444; dstFmt=8888; break; + case COLOR_RGB5652YUV444sp: srcFmt=565; dstFmt=444; break; + case COLOR_RGB5652YUV422sp: srcFmt=565; dstFmt=422; break; + case COLOR_RGB5652YUV_NV12: srcFmt=565; dstFmt=420; break; + case COLOR_RGB2YUV444sp: srcFmt=888; dstFmt=444; break; + case COLOR_RGB2YUV422sp: srcFmt=888; dstFmt=422; break; + case COLOR_RGB2YUV_NV12: srcFmt=888; dstFmt=420; break; + + default: + CV_Error(Error::StsBadArg, "Unknown FastCV color-code"); + } +} + +void cvtColor( InputArray _src, OutputArray _dst, int code) +{ + switch( code ) + { + case COLOR_YUV2YUV444sp_NV12: + case COLOR_YUV2YUV422sp_NV12: + case COLOR_YUV422sp2YUV444sp: + case COLOR_YUV422sp2YUV_NV12: + case COLOR_YUV444sp2YUV422sp: + case COLOR_YUV444sp2YUV_NV12: + case COLOR_YUV2RGB565_NV12: + case COLOR_YUV422sp2RGB565: + case COLOR_YUV422sp2RGB: + case COLOR_YUV422sp2RGBA: + case COLOR_YUV444sp2RGB565: + case COLOR_YUV444sp2RGB: + case COLOR_YUV444sp2RGBA: + case COLOR_RGB5652YUV444sp: + case COLOR_RGB5652YUV422sp: + case COLOR_RGB5652YUV_NV12: + case COLOR_RGB2YUV444sp: + case COLOR_RGB2YUV422sp: + case COLOR_RGB2YUV_NV12: + fastcvColorWrapper(_src.getMat(), _dst.getMatRef(), code); + break; + + default: + CV_Error( cv::Error::StsBadFlag, "Unknown/unsupported color conversion code" ); + } +} + +void fastcvColorWrapper(const Mat& src, Mat& dst, int code) +{ + CV_Assert(src.isContinuous()); + CV_Assert(reinterpret_cast(src.data) % 16 == 0); + + const uint32_t width = static_cast(src.cols); + int srcFmt, dstFmt; + getFormats(code, srcFmt, dstFmt); + + const double hFactorSrc = heightFactor(srcFmt); + CV_Assert(std::fmod(src.rows, hFactorSrc) == 0.0); + + const uint32_t height = static_cast(src.rows / hFactorSrc); // Y-plane height we pass to FastCV + + const uint8_t* srcY = src.data; + const size_t srcYBytes = static_cast(src.step) * height; + const uint8_t* srcC = srcY + srcYBytes; + const uint32_t srcStride = static_cast(src.step); + + const int dstRows = static_cast(height * heightFactor(dstFmt)); // 1.5·H or 2·H + + dst.create(dstRows, width, CV_8UC1); + + CV_Assert(dst.isContinuous()); + CV_Assert(reinterpret_cast(dst.data) % 16 == 0); + + uint8_t* dstY = dst.data; + uint8_t* dstC = dstY + static_cast(dst.step) * height; // offset by Y-plane bytes + const uint32_t dstStride = static_cast(dst.step); + + switch(code) + { + case COLOR_YUV2YUV444sp_NV12: + { + fcvColorYCbCr420PseudoPlanarToYCbCr444PseudoPlanaru8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_YUV2YUV422sp_NV12: + { + fcvColorYCbCr420PseudoPlanarToYCbCr422PseudoPlanaru8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, dstC, + dstStride, dstStride + ); + + } + break; + + case COLOR_YUV422sp2YUV444sp: + { + fcvColorYCbCr422PseudoPlanarToYCbCr444PseudoPlanaru8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_YUV422sp2YUV_NV12: + { + fcvColorYCbCr422PseudoPlanarToYCbCr420PseudoPlanaru8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_YUV444sp2YUV422sp: + { + fcvColorYCbCr444PseudoPlanarToYCbCr422PseudoPlanaru8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_YUV444sp2YUV_NV12: + { + fcvColorYCbCr444PseudoPlanarToYCbCr420PseudoPlanaru8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_RGB5652YUV444sp: + { + fcvColorRGB565ToYCbCr444PseudoPlanaru8( + srcY, + width, height, + srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_RGB5652YUV422sp: + { + fcvColorRGB565ToYCbCr422PseudoPlanaru8( + srcY, + width, height, + srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_RGB5652YUV_NV12: + { + fcvColorRGB565ToYCbCr420PseudoPlanaru8( + srcY, + width, height, + srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_RGB2YUV444sp: + { + fcvColorRGB888ToYCbCr444PseudoPlanaru8( + srcY, + width, height, + srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_RGB2YUV422sp: + { + fcvColorRGB888ToYCbCr422PseudoPlanaru8( + srcY, + width, height, + srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_RGB2YUV_NV12: + { + fcvColorRGB888ToYCbCr420PseudoPlanaru8( + srcY, + width, height, + srcStride, + dstY, dstC, + dstStride, dstStride + ); + } + break; + + case COLOR_YUV2RGB565_NV12: + { + fcvColorYCbCr420PseudoPlanarToRGB565u8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, + dstStride + ); + } + break; + + case COLOR_YUV422sp2RGB565: + { + fcvColorYCbCr422PseudoPlanarToRGB565u8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, + dstStride + ); + } + break; + + case COLOR_YUV422sp2RGB: + { + fcvColorYCbCr422PseudoPlanarToRGB888u8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, + dstStride + ); + } + break; + + case COLOR_YUV422sp2RGBA: + { + fcvColorYCbCr422PseudoPlanarToRGBA8888u8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, + dstStride + ); + } + break; + + case COLOR_YUV444sp2RGB565: + { + fcvColorYCbCr444PseudoPlanarToRGB565u8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, + dstStride + ); + } + break; + + case COLOR_YUV444sp2RGB: + { + fcvColorYCbCr444PseudoPlanarToRGB888u8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, + dstStride + ); + } + break; + + case COLOR_YUV444sp2RGBA: + { + fcvColorYCbCr444PseudoPlanarToRGBA8888u8( + srcY, srcC, + width, height, + srcStride, srcStride, + dstY, + dstStride + ); + } + break; + + default: + CV_Error(cv::Error::StsBadArg, "Unsupported FastCV color code"); + } +} + +}} // namespace cv::fastcv From 3c50f4b0cafe6fca55c7553aa86062c6ecd8e55e Mon Sep 17 00:00:00 2001 From: Gursimar Date: Fri, 11 Jul 2025 18:46:02 +0530 Subject: [PATCH 2/7] Added OpenCV license --- modules/fastcv/include/opencv2/fastcv/color.hpp | 8 ++++---- modules/fastcv/src/color.cpp | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/fastcv/include/opencv2/fastcv/color.hpp b/modules/fastcv/include/opencv2/fastcv/color.hpp index 79107701d4..da96a790bd 100644 --- a/modules/fastcv/include/opencv2/fastcv/color.hpp +++ b/modules/fastcv/include/opencv2/fastcv/color.hpp @@ -1,3 +1,7 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + #include namespace cv @@ -5,10 +9,6 @@ namespace cv namespace fastcv { -/** the color conversion codes -@see @ref imgproc_color_conversions -@ingroup imgproc_color_conversions - */ enum ColorConversionCodes { // FastCV-specific color conversion codes (avoid collision with OpenCV core) COLOR_YUV2YUV444sp_NV12 = 1, //!< FastCV: YCbCr420PseudoPlanar to YCbCr444PseudoPlanar diff --git a/modules/fastcv/src/color.cpp b/modules/fastcv/src/color.cpp index e06050697d..ef6207ac94 100644 --- a/modules/fastcv/src/color.cpp +++ b/modules/fastcv/src/color.cpp @@ -1,3 +1,7 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + #include "precomp.hpp" namespace cv { namespace fastcv { From eecbfd34ca7700e723669b8eae15d131b52fbb95 Mon Sep 17 00:00:00 2001 From: Gursimar Date: Fri, 11 Jul 2025 19:30:51 +0530 Subject: [PATCH 3/7] Fixed multiple ColorConversionCodes declaration --- modules/fastcv/include/opencv2/fastcv/color.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/fastcv/include/opencv2/fastcv/color.hpp b/modules/fastcv/include/opencv2/fastcv/color.hpp index da96a790bd..34c082b985 100644 --- a/modules/fastcv/include/opencv2/fastcv/color.hpp +++ b/modules/fastcv/include/opencv2/fastcv/color.hpp @@ -2,6 +2,10 @@ // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. + +#ifndef OPENCV_FASTCV_COLOR_HPP +#define OPENCV_FASTCV_COLOR_HPP + #include namespace cv @@ -34,4 +38,6 @@ enum ColorConversionCodes { CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code); -}}; //cv::fastcv namespace end \ No newline at end of file +}}; //cv::fastcv namespace end + +#endif // OPENCV_FASTCV_COLOR_HPP From 2fd896aacc531623870e18eff35282f9b82b6093 Mon Sep 17 00:00:00 2001 From: Gursimar Date: Mon, 14 Jul 2025 14:56:56 +0530 Subject: [PATCH 4/7] updated intersecting color conversion codes --- .../fastcv/include/opencv2/fastcv/color.hpp | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/modules/fastcv/include/opencv2/fastcv/color.hpp b/modules/fastcv/include/opencv2/fastcv/color.hpp index 34c082b985..cd2889ea7a 100644 --- a/modules/fastcv/include/opencv2/fastcv/color.hpp +++ b/modules/fastcv/include/opencv2/fastcv/color.hpp @@ -15,25 +15,25 @@ namespace fastcv enum ColorConversionCodes { // FastCV-specific color conversion codes (avoid collision with OpenCV core) - COLOR_YUV2YUV444sp_NV12 = 1, //!< FastCV: YCbCr420PseudoPlanar to YCbCr444PseudoPlanar - COLOR_YUV2YUV422sp_NV12 = 2, //!< FastCV: YCbCr420PseudoPlanar to YCbCr422PseudoPlanar - COLOR_YUV422sp2YUV444sp = 3, //!< FastCV: YCbCr422PseudoPlanar to YCbCr444PseudoPlanar - COLOR_YUV422sp2YUV_NV12 = 4, //!< FastCV: YCbCr422PseudoPlanar to YCbCr420PseudoPlanar - COLOR_YUV444sp2YUV422sp = 5, //!< FastCV: YCbCr444PseudoPlanar to YCbCr422PseudoPlanar - COLOR_YUV444sp2YUV_NV12 = 6, //!< FastCV: YCbCr444PseudoPlanar to YCbCr420PseudoPlanar - COLOR_YUV2RGB565_NV12 = 7, //!< FastCV: YCbCr420PseudoPlanar to RGB565 - COLOR_YUV422sp2RGB565 = 8, //!< FastCV: YCbCr422PseudoPlanar to RGB565 - COLOR_YUV422sp2RGB = 9, //!< FastCV: YCbCr422PseudoPlanar to RGB888 - COLOR_YUV422sp2RGBA = 10, //!< FastCV: YCbCr422PseudoPlanar to RGBA8888 - COLOR_YUV444sp2RGB565 = 11, //!< FastCV: YCbCr444PseudoPlanar to RGB565 - COLOR_YUV444sp2RGB = 12, //!< FastCV: YCbCr444PseudoPlanar to RGB888 - COLOR_YUV444sp2RGBA = 13, //!< FastCV: YCbCr444PseudoPlanar to RGBA8888 - COLOR_RGB2YUV_NV12 = 14, //!< FastCV: RGB888 to YCbCr420PseudoPlanar - COLOR_RGB5652YUV444sp = 15, //!< FastCV: RGB565 to YCbCr444PseudoPlanar - COLOR_RGB5652YUV422sp = 16, //!< FastCV: RGB565 to YCbCr422PseudoPlanar - COLOR_RGB5652YUV_NV12 = 17, //!< FastCV: RGB565 to YCbCr420PseudoPlanar - COLOR_RGB2YUV444sp = 18, //!< FastCV: RGB888 to YCbCr444PseudoPlanar - COLOR_RGB2YUV422sp = 19, //!< FastCV: RGB888 to YCbCr422PseudoPlanar + COLOR_YUV2YUV444sp_NV12 = 156, //!< FastCV: YCbCr420PseudoPlanar to YCbCr444PseudoPlanar + COLOR_YUV2YUV422sp_NV12 = 157, //!< FastCV: YCbCr420PseudoPlanar to YCbCr422PseudoPlanar + COLOR_YUV422sp2YUV444sp = 158, //!< FastCV: YCbCr422PseudoPlanar to YCbCr444PseudoPlanar + COLOR_YUV422sp2YUV_NV12 = 159, //!< FastCV: YCbCr422PseudoPlanar to YCbCr420PseudoPlanar + COLOR_YUV444sp2YUV422sp = 160, //!< FastCV: YCbCr444PseudoPlanar to YCbCr422PseudoPlanar + COLOR_YUV444sp2YUV_NV12 = 161, //!< FastCV: YCbCr444PseudoPlanar to YCbCr420PseudoPlanar + COLOR_YUV2RGB565_NV12 = 162, //!< FastCV: YCbCr420PseudoPlanar to RGB565 + COLOR_YUV422sp2RGB565 = 163, //!< FastCV: YCbCr422PseudoPlanar to RGB565 + COLOR_YUV422sp2RGB = 164, //!< FastCV: YCbCr422PseudoPlanar to RGB888 + COLOR_YUV422sp2RGBA = 165, //!< FastCV: YCbCr422PseudoPlanar to RGBA8888 + COLOR_YUV444sp2RGB565 = 166, //!< FastCV: YCbCr444PseudoPlanar to RGB565 + COLOR_YUV444sp2RGB = 167, //!< FastCV: YCbCr444PseudoPlanar to RGB888 + COLOR_YUV444sp2RGBA = 168, //!< FastCV: YCbCr444PseudoPlanar to RGBA8888 + COLOR_RGB2YUV_NV12 = 169, //!< FastCV: RGB888 to YCbCr420PseudoPlanar + COLOR_RGB5652YUV444sp = 170, //!< FastCV: RGB565 to YCbCr444PseudoPlanar + COLOR_RGB5652YUV422sp = 171, //!< FastCV: RGB565 to YCbCr422PseudoPlanar + COLOR_RGB5652YUV_NV12 = 172, //!< FastCV: RGB565 to YCbCr420PseudoPlanar + COLOR_RGB2YUV444sp = 173, //!< FastCV: RGB888 to YCbCr444PseudoPlanar + COLOR_RGB2YUV422sp = 174, //!< FastCV: RGB888 to YCbCr422PseudoPlanar }; CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code); From 6be366ac74ec045ccd87b386b770b1409ac6af9f Mon Sep 17 00:00:00 2001 From: Gursimar Date: Wed, 16 Jul 2025 20:54:05 +0530 Subject: [PATCH 5/7] Updated dst shape --- modules/fastcv/src/color.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/modules/fastcv/src/color.cpp b/modules/fastcv/src/color.cpp index ef6207ac94..1ba9ac3b3e 100644 --- a/modules/fastcv/src/color.cpp +++ b/modules/fastcv/src/color.cpp @@ -99,7 +99,31 @@ void fastcvColorWrapper(const Mat& src, Mat& dst, int code) const int dstRows = static_cast(height * heightFactor(dstFmt)); // 1.5·H or 2·H - dst.create(dstRows, width, CV_8UC1); + int dstType = CV_8UC1; // default for planar/semi-planar YUV formats (1 byte per pixel) + + switch (dstFmt) + { + case 420: case 422: case 444: + dstType = CV_8UC1; + break; + + case 565: // RGB565 – 16-bit packed RGB, 2 bytes per pixel + dstType = CV_8UC2; + break; + + case 888: // RGB888 – 3 bytes per pixel + dstType = CV_8UC3; + break; + + case 8888: // RGBA8888 – 4 bytes per pixel + dstType = CV_8UC4; + break; + + default: + CV_Error(cv::Error::StsBadArg, "Unsupported destination pixel format for FastCV"); + } + + dst.create(dstRows, width, dstType); CV_Assert(dst.isContinuous()); CV_Assert(reinterpret_cast(dst.data) % 16 == 0); From 8d21b1924fbe595b8e682eec564e63c2d0281967 Mon Sep 17 00:00:00 2001 From: Gursimar Date: Wed, 23 Jul 2025 20:24:59 +0530 Subject: [PATCH 6/7] Added tests --- modules/fastcv/src/color.cpp | 3 +- modules/fastcv/test/test_color.cpp | 177 +++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 modules/fastcv/test/test_color.cpp diff --git a/modules/fastcv/src/color.cpp b/modules/fastcv/src/color.cpp index 1ba9ac3b3e..d2dc0729d6 100644 --- a/modules/fastcv/src/color.cpp +++ b/modules/fastcv/src/color.cpp @@ -13,7 +13,8 @@ inline double heightFactor(int fmt /*420 / 422 / 444*/) switch (fmt) { case 420: return 1.5; // YUV420 has 1.5× rows - case 422: case 444: return 2.0; // YUV422/444 have 2× rows + case 422: return 2.0; // YUV422 have 2× rows + case 444: return 2.0; // YUV444 have 3× rows default: return 1.0; // packed RGB565/RGB888 → no extra plane } } diff --git a/modules/fastcv/test/test_color.cpp b/modules/fastcv/test/test_color.cpp new file mode 100644 index 0000000000..b82b130110 --- /dev/null +++ b/modules/fastcv/test/test_color.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_precomp.hpp" + +namespace opencv_test { namespace { + +static inline void fillRandom8U(cv::Mat& m) +{ + cv::RNG& rng = cv::theRNG(); + rng.fill(m, cv::RNG::UNIFORM, 0, 256); +} + +TEST(Fastcv_cvtColor, YUV420_to_YUV422_and_back_roundtrip) +{ + const cv::Size sz(640, 480); + + cv::Mat bgr(sz, CV_8UC3); + fillRandom8U(bgr); + + cv::Mat rgb; + cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB); + + cv::Mat yuv420_before; + yuv420_before.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(rgb, yuv420_before, cv::fastcv::COLOR_RGB2YUV_NV12); + + cv::Mat yuv422; + yuv422.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv420_before, yuv422, cv::fastcv::COLOR_YUV2YUV422sp_NV12); + + cv::Mat yuv422_to_bgr; + + cv::Mat yuv420_after; + yuv420_after.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv422, yuv420_after, cv::fastcv::COLOR_YUV422sp2YUV_NV12); + + ASSERT_EQ(yuv420_before.size(), yuv420_after.size()); + ASSERT_EQ(yuv420_before.type(), yuv420_after.type()); + + double maxDiff = cv::norm(yuv420_before, yuv420_after, cv::NORM_INF); + std::cout << "Max difference YUV420 before vs after = " << maxDiff << std::endl; + EXPECT_LE(maxDiff, 1.0); +} + +TEST(Fastcv_cvtColor, YUV422_to_YUV420_roundtrip_custom_input) +{ + const int width = 640; + const int height = 480; + const cv::Size sz(width, height); + const int yuv422_rows = height * 2; + cv::Mat yuv422_initial(yuv422_rows, width, CV_8UC1); + yuv422_initial.allocator = cv::fastcv::getQcAllocator(); + + uint8_t* y_plane = yuv422_initial.data; + uint8_t* uv_plane = y_plane + yuv422_initial.step * height; + + for (int y = 0; y < height; ++y) + { + uint8_t* y_row = y_plane + y * yuv422_initial.step; + uint8_t* uv_row = uv_plane + y * yuv422_initial.step; + for (int x = 0; x < width; x += 2) + { + y_row[x] = 100; + y_row[x+1] = 100; + + uv_row[x] = 50; + uv_row[x+1] = 200; + } + } + + cv::Mat yuv420; + yuv420.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv422_initial, yuv420, cv::fastcv::COLOR_YUV422sp2YUV_NV12); + + cv::Mat yuv422_roundtrip; + yuv422_roundtrip.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv420, yuv422_roundtrip, cv::fastcv::COLOR_YUV2YUV422sp_NV12); + + ASSERT_EQ(yuv422_initial.size(), yuv422_roundtrip.size()); + ASSERT_EQ(yuv422_initial.type(), yuv422_roundtrip.type()); + + double diff = cv::norm(yuv422_initial, yuv422_roundtrip, cv::NORM_INF); + EXPECT_LE(diff, 2.0); +} + +TEST(Fastcv_cvtColor, YUV444_to_YUV420_and_back_roundtrip) +{ + const cv::Size sz(640, 480); + + cv::Mat bgr(sz, CV_8UC3); + fillRandom8U(bgr); + cv::Mat rgb; + cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB); + + cv::Mat yuv444_initial; + yuv444_initial.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(rgb, yuv444_initial, cv::fastcv::COLOR_RGB2YUV444sp); + + cv::Mat yuv420; + yuv420.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv444_initial, yuv420, cv::fastcv::COLOR_YUV444sp2YUV_NV12); + + cv::Mat yuv444_final; + yuv444_final.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv420, yuv444_final, cv::fastcv::COLOR_YUV2YUV444sp_NV12); + + ASSERT_EQ(yuv444_initial.size(), yuv444_final.size()); + ASSERT_EQ(yuv444_initial.type(), yuv444_final.type()); + + double maxDiff = cv::norm(yuv444_initial, yuv444_final, cv::NORM_INF); + std::cout << "Max difference YUV444 before vs after roundtrip = " << maxDiff << std::endl; + EXPECT_LE(maxDiff, 2.0); +} + +TEST(Fastcv_cvtColor, YUV444_to_YUV422_and_back_roundtrip) +{ + const cv::Size sz(640, 480); + + cv::Mat bgr(sz, CV_8UC3); + fillRandom8U(bgr); + cv::Mat rgb; + cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB); + + cv::Mat yuv444_initial; + yuv444_initial.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(rgb, yuv444_initial, cv::fastcv::COLOR_RGB2YUV444sp); + + cv::Mat yuv422; + yuv422.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv444_initial, yuv422, cv::fastcv::COLOR_YUV444sp2YUV422sp); + + cv::Mat yuv444_final; + yuv444_final.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv422, yuv444_final, cv::fastcv::COLOR_YUV422sp2YUV444sp); + + ASSERT_EQ(yuv444_initial.size(), yuv444_final.size()); + ASSERT_EQ(yuv444_initial.type(), yuv444_final.type()); + + double maxDiff = cv::norm(yuv444_initial, yuv444_final, cv::NORM_INF); + std::cout << "Max difference YUV444 before vs after roundtrip = " << maxDiff << std::endl; + EXPECT_LE(maxDiff, 2.0); +} + +TEST(Fastcv_cvtColor, YUV444_to_RGB565_and_back_roundtrip) +{ + const cv::Size sz(640, 480); + cv::Mat bgr(sz, CV_8UC3); + fillRandom8U(bgr); + + cv::Mat rgb; + cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB); + + cv::Mat yuv444_initial; + yuv444_initial.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(rgb, yuv444_initial, cv::fastcv::COLOR_RGB2YUV444sp); + + cv::Mat rgb565(sz, CV_8UC2); + rgb565.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(yuv444_initial, rgb565, cv::fastcv::COLOR_YUV444sp2RGB565); + + cv::Mat yuv444_roundtrip; + yuv444_roundtrip.allocator = cv::fastcv::getQcAllocator(); + cv::fastcv::cvtColor(rgb565, yuv444_roundtrip, cv::fastcv::COLOR_RGB5652YUV444sp); + + ASSERT_EQ(yuv444_initial.size(), yuv444_roundtrip.size()); + ASSERT_EQ(yuv444_initial.type(), yuv444_roundtrip.type()); + + double maxDiff = cv::norm(yuv444_initial, yuv444_roundtrip, cv::NORM_INF); + std::cout << "Max difference YUV444 after RGB565 roundtrip = " << maxDiff << std::endl; + + EXPECT_LE(maxDiff, 2.0); +} + +}} // namespace opencv_test From 7d2167da07ea04867a5138a0f7fe5908b39b8f17 Mon Sep 17 00:00:00 2001 From: Gursimar Date: Thu, 24 Jul 2025 01:40:51 +0530 Subject: [PATCH 7/7] updated tests --- modules/fastcv/test/test_color.cpp | 41 ------------------------------ 1 file changed, 41 deletions(-) diff --git a/modules/fastcv/test/test_color.cpp b/modules/fastcv/test/test_color.cpp index b82b130110..bd317fff98 100644 --- a/modules/fastcv/test/test_color.cpp +++ b/modules/fastcv/test/test_color.cpp @@ -45,47 +45,6 @@ TEST(Fastcv_cvtColor, YUV420_to_YUV422_and_back_roundtrip) EXPECT_LE(maxDiff, 1.0); } -TEST(Fastcv_cvtColor, YUV422_to_YUV420_roundtrip_custom_input) -{ - const int width = 640; - const int height = 480; - const cv::Size sz(width, height); - const int yuv422_rows = height * 2; - cv::Mat yuv422_initial(yuv422_rows, width, CV_8UC1); - yuv422_initial.allocator = cv::fastcv::getQcAllocator(); - - uint8_t* y_plane = yuv422_initial.data; - uint8_t* uv_plane = y_plane + yuv422_initial.step * height; - - for (int y = 0; y < height; ++y) - { - uint8_t* y_row = y_plane + y * yuv422_initial.step; - uint8_t* uv_row = uv_plane + y * yuv422_initial.step; - for (int x = 0; x < width; x += 2) - { - y_row[x] = 100; - y_row[x+1] = 100; - - uv_row[x] = 50; - uv_row[x+1] = 200; - } - } - - cv::Mat yuv420; - yuv420.allocator = cv::fastcv::getQcAllocator(); - cv::fastcv::cvtColor(yuv422_initial, yuv420, cv::fastcv::COLOR_YUV422sp2YUV_NV12); - - cv::Mat yuv422_roundtrip; - yuv422_roundtrip.allocator = cv::fastcv::getQcAllocator(); - cv::fastcv::cvtColor(yuv420, yuv422_roundtrip, cv::fastcv::COLOR_YUV2YUV422sp_NV12); - - ASSERT_EQ(yuv422_initial.size(), yuv422_roundtrip.size()); - ASSERT_EQ(yuv422_initial.type(), yuv422_roundtrip.type()); - - double diff = cv::norm(yuv422_initial, yuv422_roundtrip, cv::NORM_INF); - EXPECT_LE(diff, 2.0); -} - TEST(Fastcv_cvtColor, YUV444_to_YUV420_and_back_roundtrip) { const cv::Size sz(640, 480);