Skip to content

Added fastcv color conversions #3967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: 4.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions modules/fastcv/include/opencv2/fastcv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 43 additions & 0 deletions modules/fastcv/include/opencv2/fastcv/color.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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.


#ifndef OPENCV_FASTCV_COLOR_HPP
#define OPENCV_FASTCV_COLOR_HPP

#include <opencv2/core.hpp>

namespace cv
{
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
};

CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code);

}}; //cv::fastcv namespace end

#endif // OPENCV_FASTCV_COLOR_HPP
347 changes: 347 additions & 0 deletions modules/fastcv/src/color.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,347 @@
// 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 {

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<uintptr_t>(src.data) % 16 == 0);

const uint32_t width = static_cast<uint32_t>(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<uint32_t>(src.rows / hFactorSrc); // Y-plane height we pass to FastCV

const uint8_t* srcY = src.data;
const size_t srcYBytes = static_cast<size_t>(src.step) * height;
const uint8_t* srcC = srcY + srcYBytes;
const uint32_t srcStride = static_cast<uint32_t>(src.step);

const int dstRows = static_cast<int>(height * heightFactor(dstFmt)); // 1.5·H or 2·H

dst.create(dstRows, width, CV_8UC1);

CV_Assert(dst.isContinuous());
CV_Assert(reinterpret_cast<uintptr_t>(dst.data) % 16 == 0);

uint8_t* dstY = dst.data;
uint8_t* dstC = dstY + static_cast<size_t>(dst.step) * height; // offset by Y-plane bytes
const uint32_t dstStride = static_cast<uint32_t>(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
Loading