root/modules/imgproc/test/test_cvtyuv.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. countOfDifferencies
  2. requiresEvenHeight
  3. requiresEvenWidth
  4. write
  5. channels
  6. requiresEvenHeight
  7. requiresEvenWidth
  8. write
  9. channels
  10. write
  11. channels
  12. write
  13. channels
  14. write
  15. channels
  16. channels
  17. size
  18. write
  19. write
  20. channels
  21. size
  22. channels
  23. size
  24. requiresEvenHeight
  25. read
  26. read
  27. read
  28. read
  29. read
  30. read
  31. read
  32. read
  33. channels
  34. size
  35. requiresEvenHeight
  36. requiresEvenWidth
  37. read
  38. channels
  39. read
  40. channels
  41. read
  42. channels
  43. read
  44. channels
  45. convert
  46. convert
  47. convert
  48. getReader
  49. getReader
  50. getWriter
  51. getWriter
  52. getWriter
  53. referenceYUV2RGB
  54. referenceYUV2GRAY
  55. referenceRGB2YUV
  56. getDcn
  57. getScn
  58. getSrcSize
  59. getDstSize
  60. requiresEvenHeight
  61. requiresEvenWidth
  62. TEST_P
  63. TEST_P

#include "test_precomp.hpp"

using namespace cv;
using namespace std;

#undef RGB
#undef YUV

typedef Vec3b YUV;
typedef Vec3b RGB;

int countOfDifferencies(const Mat& gold, const Mat& result, int maxAllowedDifference = 1)
{
    Mat diff;
    absdiff(gold, result, diff);
    return countNonZero(diff.reshape(1) > maxAllowedDifference);
}

class YUVreader
{
public:
    virtual ~YUVreader() {}
    virtual YUV read(const Mat& yuv, int row, int col) = 0;
    virtual int channels() = 0;
    virtual Size size(Size imgSize) = 0;

    virtual bool requiresEvenHeight() { return true; }
    virtual bool requiresEvenWidth() { return true; }

    static YUVreader* getReader(int code);
};

class RGBreader
{
public:
    virtual ~RGBreader() {}
    virtual RGB read(const Mat& rgb, int row, int col) = 0;
    virtual int channels() = 0;

    static RGBreader* getReader(int code);
};

class RGBwriter
{
public:
    virtual ~RGBwriter() {}

    virtual void write(Mat& rgb, int row, int col, const RGB& val) = 0;
    virtual int channels() = 0;

    static RGBwriter* getWriter(int code);
};

class GRAYwriter
{
public:
    virtual ~GRAYwriter() {}

    virtual void write(Mat& gray, int row, int col, const uchar& val)
    {
        gray.at<uchar>(row, col) = val;
    }

    virtual int channels() { return 1; }

    static GRAYwriter* getWriter(int code);
};

class YUVwriter
{
public:
    virtual ~YUVwriter() {}

    virtual void write(Mat& yuv, int row, int col, const YUV& val) = 0;
    virtual int channels() = 0;
    virtual Size size(Size imgSize) = 0;

    virtual bool requiresEvenHeight() { return true; }
    virtual bool requiresEvenWidth() { return true; }

    static YUVwriter* getWriter(int code);
};

class RGB888Writer : public RGBwriter
{
    void write(Mat& rgb, int row, int col, const RGB& val)
    {
        rgb.at<Vec3b>(row, col) = val;
    }

    int channels() { return 3; }
};

class BGR888Writer : public RGBwriter
{
    void write(Mat& rgb, int row, int col, const RGB& val)
    {
        Vec3b tmp(val[2], val[1], val[0]);
        rgb.at<Vec3b>(row, col) = tmp;
    }

    int channels() { return 3; }
};

class RGBA8888Writer : public RGBwriter
{
    void write(Mat& rgb, int row, int col, const RGB& val)
    {
        Vec4b tmp(val[0], val[1], val[2], 255);
        rgb.at<Vec4b>(row, col) = tmp;
    }

    int channels() { return 4; }
};

class BGRA8888Writer : public RGBwriter
{
    void write(Mat& rgb, int row, int col, const RGB& val)
    {
        Vec4b tmp(val[2], val[1], val[0], 255);
        rgb.at<Vec4b>(row, col) = tmp;
    }

    int channels() { return 4; }
};

class YUV420pWriter: public YUVwriter
{
    int channels() { return 1; }
    Size size(Size imgSize) { return Size(imgSize.width, imgSize.height + imgSize.height/2); }
};

class YV12Writer: public YUV420pWriter
{
    void write(Mat& yuv, int row, int col, const YUV& val)
    {
        int h = yuv.rows * 2 / 3;

        yuv.ptr<uchar>(row)[col] = val[0];
        if( row % 2 == 0 && col % 2 == 0 )
        {
            yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[2];
            yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[1];
        }
    }
};

class I420Writer: public YUV420pWriter
{
    void write(Mat& yuv, int row, int col, const YUV& val)
    {
        int h = yuv.rows * 2 / 3;

        yuv.ptr<uchar>(row)[col] = val[0];
        if( row % 2 == 0 && col % 2 == 0 )
        {
            yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)] = val[1];
            yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)] = val[2];
        }
    }
};

class YUV420Reader: public YUVreader
{
    int channels() { return 1; }
    Size size(Size imgSize) { return Size(imgSize.width, imgSize.height * 3 / 2); }
};

class YUV422Reader: public YUVreader
{
    int channels() { return 2; }
    Size size(Size imgSize) { return imgSize; }
    bool requiresEvenHeight() { return false; }
};

class NV21Reader: public YUV420Reader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        uchar y = yuv.ptr<uchar>(row)[col];
        uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];
        uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];

        return YUV(y, u, v);
    }
};


struct NV12Reader: public YUV420Reader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        uchar y = yuv.ptr<uchar>(row)[col];
        uchar u = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2];
        uchar v = yuv.ptr<uchar>(yuv.rows * 2 / 3 + row/2)[(col/2)*2 + 1];

        return YUV(y, u, v);
    }
};

class YV12Reader: public YUV420Reader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        int h = yuv.rows * 2 / 3;
        uchar y = yuv.ptr<uchar>(row)[col];
        uchar u = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];
        uchar v = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];

        return YUV(y, u, v);
    }
};

class IYUVReader: public YUV420Reader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        int h = yuv.rows * 2 / 3;
        uchar y = yuv.ptr<uchar>(row)[col];
        uchar u = yuv.ptr<uchar>(h + row/4)[col/2 + ((row/2) % 2) * (yuv.cols/2)];
        uchar v = yuv.ptr<uchar>(h + (row/2 + h/2)/2)[col/2 + ((row/2 + h/2) % 2) * (yuv.cols/2)];

        return YUV(y, u, v);
    }
};

class UYVYReader: public YUV422Reader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        uchar y = yuv.ptr<Vec2b>(row)[col][1];
        uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][0];
        uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][0];

        return YUV(y, u, v);
    }
};

class YUY2Reader: public YUV422Reader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        uchar y = yuv.ptr<Vec2b>(row)[col][0];
        uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2][1];
        uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];

        return YUV(y, u, v);
    }
};

class YVYUReader: public YUV422Reader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        uchar y = yuv.ptr<Vec2b>(row)[col][0];
        uchar u = yuv.ptr<Vec2b>(row)[(col/2)*2 + 1][1];
        uchar v = yuv.ptr<Vec2b>(row)[(col/2)*2][1];

        return YUV(y, u, v);
    }
};

class YUV888Reader : public YUVreader
{
    YUV read(const Mat& yuv, int row, int col)
    {
        return yuv.at<YUV>(row, col);
    }

    int channels() { return 3; }
    Size size(Size imgSize) { return imgSize; }
    bool requiresEvenHeight() { return false; }
    bool requiresEvenWidth() { return false; }
};

class RGB888Reader : public RGBreader
{
    RGB read(const Mat& rgb, int row, int col)
    {
        return rgb.at<RGB>(row, col);
    }

    int channels() { return 3; }
};

class BGR888Reader : public RGBreader
{
    RGB read(const Mat& rgb, int row, int col)
    {
        RGB tmp = rgb.at<RGB>(row, col);
        return RGB(tmp[2], tmp[1], tmp[0]);
    }

    int channels() { return 3; }
};

class RGBA8888Reader : public RGBreader
{
    RGB read(const Mat& rgb, int row, int col)
    {
        Vec4b rgba = rgb.at<Vec4b>(row, col);
        return RGB(rgba[0], rgba[1], rgba[2]);
    }

    int channels() { return 4; }
};

class BGRA8888Reader : public RGBreader
{
    RGB read(const Mat& rgb, int row, int col)
    {
        Vec4b rgba = rgb.at<Vec4b>(row, col);
        return RGB(rgba[2], rgba[1], rgba[0]);
    }

    int channels() { return 4; }
};

class YUV2RGB_Converter
{
public:
    RGB convert(YUV yuv)
    {
        int y = std::max(0, yuv[0] - 16);
        int u = yuv[1] - 128;
        int v = yuv[2] - 128;
        uchar r = saturate_cast<uchar>(1.164f * y + 1.596f * v);
        uchar g = saturate_cast<uchar>(1.164f * y - 0.813f * v - 0.391f * u);
        uchar b = saturate_cast<uchar>(1.164f * y + 2.018f * u);

        return RGB(r, g, b);
    }
};

class YUV2GRAY_Converter
{
public:
    uchar convert(YUV yuv)
    {
        return yuv[0];
    }
};

class RGB2YUV_Converter
{
public:
    YUV convert(RGB rgb)
    {
        int r = rgb[0];
        int g = rgb[1];
        int b = rgb[2];

        uchar y = saturate_cast<uchar>((int)( 0.257f*r + 0.504f*g + 0.098f*b + 0.5f) + 16);
        uchar u = saturate_cast<uchar>((int)(-0.148f*r - 0.291f*g + 0.439f*b + 0.5f) + 128);
        uchar v = saturate_cast<uchar>((int)( 0.439f*r - 0.368f*g - 0.071f*b + 0.5f) + 128);

        return YUV(y, u, v);
    }
};

YUVreader* YUVreader::getReader(int code)
{
    switch(code)
    {
    case CV_YUV2RGB_NV12:
    case CV_YUV2BGR_NV12:
    case CV_YUV2RGBA_NV12:
    case CV_YUV2BGRA_NV12:
        return new NV12Reader();
    case CV_YUV2RGB_NV21:
    case CV_YUV2BGR_NV21:
    case CV_YUV2RGBA_NV21:
    case CV_YUV2BGRA_NV21:
        return new NV21Reader();
    case CV_YUV2RGB_YV12:
    case CV_YUV2BGR_YV12:
    case CV_YUV2RGBA_YV12:
    case CV_YUV2BGRA_YV12:
        return new YV12Reader();
    case CV_YUV2RGB_IYUV:
    case CV_YUV2BGR_IYUV:
    case CV_YUV2RGBA_IYUV:
    case CV_YUV2BGRA_IYUV:
        return new IYUVReader();
    case CV_YUV2RGB_UYVY:
    case CV_YUV2BGR_UYVY:
    case CV_YUV2RGBA_UYVY:
    case CV_YUV2BGRA_UYVY:
        return new UYVYReader();
    //case CV_YUV2RGB_VYUY = 109,
    //case CV_YUV2BGR_VYUY = 110,
    //case CV_YUV2RGBA_VYUY = 113,
    //case CV_YUV2BGRA_VYUY = 114,
    //    return ??
    case CV_YUV2RGB_YUY2:
    case CV_YUV2BGR_YUY2:
    case CV_YUV2RGBA_YUY2:
    case CV_YUV2BGRA_YUY2:
        return new YUY2Reader();
    case CV_YUV2RGB_YVYU:
    case CV_YUV2BGR_YVYU:
    case CV_YUV2RGBA_YVYU:
    case CV_YUV2BGRA_YVYU:
        return new YVYUReader();
    case CV_YUV2GRAY_420:
        return new NV21Reader();
    case CV_YUV2GRAY_UYVY:
        return new UYVYReader();
    case CV_YUV2GRAY_YUY2:
        return new YUY2Reader();
    case CV_YUV2BGR:
    case CV_YUV2RGB:
        return new YUV888Reader();
    default:
        return 0;
    }
}

RGBreader* RGBreader::getReader(int code)
{
    switch(code)
    {
    case CV_RGB2YUV_YV12:
    case CV_RGB2YUV_I420:
        return new RGB888Reader();
    case CV_BGR2YUV_YV12:
    case CV_BGR2YUV_I420:
        return new BGR888Reader();
    case CV_RGBA2YUV_I420:
    case CV_RGBA2YUV_YV12:
        return new RGBA8888Reader();
    case CV_BGRA2YUV_YV12:
    case CV_BGRA2YUV_I420:
        return new BGRA8888Reader();
    default:
        return 0;
    };
}

RGBwriter* RGBwriter::getWriter(int code)
{
    switch(code)
    {
    case CV_YUV2RGB_NV12:
    case CV_YUV2RGB_NV21:
    case CV_YUV2RGB_YV12:
    case CV_YUV2RGB_IYUV:
    case CV_YUV2RGB_UYVY:
    //case CV_YUV2RGB_VYUY:
    case CV_YUV2RGB_YUY2:
    case CV_YUV2RGB_YVYU:
    case CV_YUV2RGB:
        return new RGB888Writer();
    case CV_YUV2BGR_NV12:
    case CV_YUV2BGR_NV21:
    case CV_YUV2BGR_YV12:
    case CV_YUV2BGR_IYUV:
    case CV_YUV2BGR_UYVY:
    //case CV_YUV2BGR_VYUY:
    case CV_YUV2BGR_YUY2:
    case CV_YUV2BGR_YVYU:
    case CV_YUV2BGR:
        return new BGR888Writer();
    case CV_YUV2RGBA_NV12:
    case CV_YUV2RGBA_NV21:
    case CV_YUV2RGBA_YV12:
    case CV_YUV2RGBA_IYUV:
    case CV_YUV2RGBA_UYVY:
    //case CV_YUV2RGBA_VYUY:
    case CV_YUV2RGBA_YUY2:
    case CV_YUV2RGBA_YVYU:
        return new RGBA8888Writer();
    case CV_YUV2BGRA_NV12:
    case CV_YUV2BGRA_NV21:
    case CV_YUV2BGRA_YV12:
    case CV_YUV2BGRA_IYUV:
    case CV_YUV2BGRA_UYVY:
    //case CV_YUV2BGRA_VYUY:
    case CV_YUV2BGRA_YUY2:
    case CV_YUV2BGRA_YVYU:
        return new BGRA8888Writer();
    default:
        return 0;
    };
}

GRAYwriter* GRAYwriter::getWriter(int code)
{
    switch(code)
    {
    case CV_YUV2GRAY_420:
    case CV_YUV2GRAY_UYVY:
    case CV_YUV2GRAY_YUY2:
        return new GRAYwriter();
    default:
        return 0;
    }
}

YUVwriter* YUVwriter::getWriter(int code)
{
    switch(code)
    {
    case CV_RGB2YUV_YV12:
    case CV_BGR2YUV_YV12:
    case CV_RGBA2YUV_YV12:
    case CV_BGRA2YUV_YV12:
        return new YV12Writer();
    case CV_RGB2YUV_I420:
    case CV_BGR2YUV_I420:
    case CV_RGBA2YUV_I420:
    case CV_BGRA2YUV_I420:
        return new I420Writer();
    default:
        return 0;
    };
}

template<class convertor>
void referenceYUV2RGB(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, RGBwriter* rgbWriter)
{
    convertor cvt;

    for(int row = 0; row < rgb.rows; ++row)
        for(int col = 0; col < rgb.cols; ++col)
            rgbWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));
}

template<class convertor>
void referenceYUV2GRAY(const Mat& yuv, Mat& rgb, YUVreader* yuvReader, GRAYwriter* grayWriter)
{
    convertor cvt;

    for(int row = 0; row < rgb.rows; ++row)
        for(int col = 0; col < rgb.cols; ++col)
            grayWriter->write(rgb, row, col, cvt.convert(yuvReader->read(yuv, row, col)));
}

template<class convertor>
void referenceRGB2YUV(const Mat& rgb, Mat& yuv, RGBreader* rgbReader, YUVwriter* yuvWriter)
{
    convertor cvt;

    for(int row = 0; row < rgb.rows; ++row)
        for(int col = 0; col < rgb.cols; ++col)
            yuvWriter->write(yuv, row, col, cvt.convert(rgbReader->read(rgb, row, col)));
}

struct ConversionYUV
{
    ConversionYUV( const int code )
    {
        yuvReader_  = YUVreader :: getReader(code);
        yuvWriter_  = YUVwriter :: getWriter(code);
        rgbReader_  = RGBreader :: getReader(code);
        rgbWriter_  = RGBwriter :: getWriter(code);
        grayWriter_ = GRAYwriter:: getWriter(code);
    }

    int getDcn()
    {
        return (rgbWriter_ != 0) ? rgbWriter_->channels() : ((grayWriter_ != 0) ? grayWriter_->channels() : yuvWriter_->channels());
    }

    int getScn()
    {
        return (yuvReader_ != 0) ? yuvReader_->channels() : rgbReader_->channels();
    }

    Size getSrcSize( const Size& imgSize )
    {
        return (yuvReader_ != 0) ? yuvReader_->size(imgSize) : imgSize;
    }

    Size getDstSize( const Size& imgSize )
    {
        return (yuvWriter_ != 0) ? yuvWriter_->size(imgSize) : imgSize;
    }

    bool requiresEvenHeight()
    {
        return (yuvReader_ != 0) ? yuvReader_->requiresEvenHeight() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenHeight() : false);
    }

    bool requiresEvenWidth()
    {
        return (yuvReader_ != 0) ? yuvReader_->requiresEvenWidth() : ((yuvWriter_ != 0) ? yuvWriter_->requiresEvenWidth() : false);
    }

    YUVreader*  yuvReader_;
    YUVwriter*  yuvWriter_;
    RGBreader*  rgbReader_;
    RGBwriter*  rgbWriter_;
    GRAYwriter* grayWriter_;
};

CV_ENUM(YUVCVTS, CV_YUV2RGB_NV12, CV_YUV2BGR_NV12, CV_YUV2RGB_NV21, CV_YUV2BGR_NV21,
                 CV_YUV2RGBA_NV12, CV_YUV2BGRA_NV12, CV_YUV2RGBA_NV21, CV_YUV2BGRA_NV21,
                 CV_YUV2RGB_YV12, CV_YUV2BGR_YV12, CV_YUV2RGB_IYUV, CV_YUV2BGR_IYUV,
                 CV_YUV2RGBA_YV12, CV_YUV2BGRA_YV12, CV_YUV2RGBA_IYUV, CV_YUV2BGRA_IYUV,
                 CV_YUV2RGB_UYVY, CV_YUV2BGR_UYVY, CV_YUV2RGBA_UYVY, CV_YUV2BGRA_UYVY,
                 CV_YUV2RGB_YUY2, CV_YUV2BGR_YUY2, CV_YUV2RGB_YVYU, CV_YUV2BGR_YVYU,
                 CV_YUV2RGBA_YUY2, CV_YUV2BGRA_YUY2, CV_YUV2RGBA_YVYU, CV_YUV2BGRA_YVYU,
                 CV_YUV2GRAY_420, CV_YUV2GRAY_UYVY, CV_YUV2GRAY_YUY2,
                 CV_YUV2BGR, CV_YUV2RGB, CV_RGB2YUV_YV12, CV_BGR2YUV_YV12, CV_RGBA2YUV_YV12,
                 CV_BGRA2YUV_YV12, CV_RGB2YUV_I420, CV_BGR2YUV_I420, CV_RGBA2YUV_I420, CV_BGRA2YUV_I420)

typedef ::testing::TestWithParam<YUVCVTS> Imgproc_ColorYUV;

TEST_P(Imgproc_ColorYUV, accuracy)
{
    int code = GetParam();
    RNG& random = theRNG();

    ConversionYUV cvt(code);

    const int scn = cvt.getScn();
    const int dcn = cvt.getDcn();
    for(int iter = 0; iter < 30; ++iter)
    {
        Size sz(random.uniform(1, 641), random.uniform(1, 481));

        if(cvt.requiresEvenWidth())  sz.width  += sz.width % 2;
        if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;

        Size srcSize = cvt.getSrcSize(sz);
        Mat src = Mat(srcSize.height, srcSize.width * scn, CV_8UC1).reshape(scn);

        Size dstSize = cvt.getDstSize(sz);
        Mat dst = Mat(dstSize.height, dstSize.width * dcn, CV_8UC1).reshape(dcn);
        Mat gold(dstSize, CV_8UC(dcn));

        random.fill(src, RNG::UNIFORM, 0, 256);

        if(cvt.rgbWriter_)
            referenceYUV2RGB<YUV2RGB_Converter>  (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
        else if(cvt.grayWriter_)
            referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
        else if(cvt.yuvWriter_)
            referenceRGB2YUV<RGB2YUV_Converter>  (src, gold, cvt.rgbReader_, cvt.yuvWriter_);

        cv::cvtColor(src, dst, code, -1);

        EXPECT_EQ(0, countOfDifferencies(gold, dst));
    }
}

TEST_P(Imgproc_ColorYUV, roi_accuracy)
{
    int code = GetParam();
    RNG& random = theRNG();

    ConversionYUV cvt(code);

    const int scn = cvt.getScn();
    const int dcn = cvt.getDcn();
    for(int iter = 0; iter < 30; ++iter)
    {
        Size sz(random.uniform(1, 641), random.uniform(1, 481));

        if(cvt.requiresEvenWidth())  sz.width  += sz.width % 2;
        if(cvt.requiresEvenHeight()) sz.height += sz.height % 2;

        int roi_offset_top = random.uniform(0, 6);
        int roi_offset_bottom = random.uniform(0, 6);
        int roi_offset_left = random.uniform(0, 6);
        int roi_offset_right = random.uniform(0, 6);

        Size srcSize = cvt.getSrcSize(sz);
        Mat src_full(srcSize.height + roi_offset_top + roi_offset_bottom, srcSize.width + roi_offset_left + roi_offset_right, CV_8UC(scn));

        Size dstSize = cvt.getDstSize(sz);
        Mat dst_full(dstSize.height  + roi_offset_left + roi_offset_right, dstSize.width + roi_offset_top + roi_offset_bottom, CV_8UC(dcn), Scalar::all(0));
        Mat gold_full(dst_full.size(), CV_8UC(dcn), Scalar::all(0));

        random.fill(src_full, RNG::UNIFORM, 0, 256);

        Mat src = src_full(Range(roi_offset_top, roi_offset_top + srcSize.height), Range(roi_offset_left, roi_offset_left + srcSize.width));
        Mat dst = dst_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));
        Mat gold = gold_full(Range(roi_offset_left, roi_offset_left + dstSize.height), Range(roi_offset_top, roi_offset_top + dstSize.width));

        if(cvt.rgbWriter_)
            referenceYUV2RGB<YUV2RGB_Converter>  (src, gold, cvt.yuvReader_, cvt.rgbWriter_);
        else if(cvt.grayWriter_)
            referenceYUV2GRAY<YUV2GRAY_Converter>(src, gold, cvt.yuvReader_, cvt.grayWriter_);
        else if(cvt.yuvWriter_)
            referenceRGB2YUV<RGB2YUV_Converter>  (src, gold, cvt.rgbReader_, cvt.yuvWriter_);

        cv::cvtColor(src, dst, code, -1);

        EXPECT_EQ(0, countOfDifferencies(gold_full, dst_full));
    }
}

INSTANTIATE_TEST_CASE_P(cvt420, Imgproc_ColorYUV,
    ::testing::Values((int)CV_YUV2RGB_NV12, (int)CV_YUV2BGR_NV12, (int)CV_YUV2RGB_NV21, (int)CV_YUV2BGR_NV21,
                      (int)CV_YUV2RGBA_NV12, (int)CV_YUV2BGRA_NV12, (int)CV_YUV2RGBA_NV21, (int)CV_YUV2BGRA_NV21,
                      (int)CV_YUV2RGB_YV12, (int)CV_YUV2BGR_YV12, (int)CV_YUV2RGB_IYUV, (int)CV_YUV2BGR_IYUV,
                      (int)CV_YUV2RGBA_YV12, (int)CV_YUV2BGRA_YV12, (int)CV_YUV2RGBA_IYUV, (int)CV_YUV2BGRA_IYUV,
                      (int)CV_YUV2GRAY_420, (int)CV_RGB2YUV_YV12, (int)CV_BGR2YUV_YV12, (int)CV_RGBA2YUV_YV12,
                      (int)CV_BGRA2YUV_YV12, (int)CV_RGB2YUV_I420, (int)CV_BGR2YUV_I420, (int)CV_RGBA2YUV_I420,
                      (int)CV_BGRA2YUV_I420));

INSTANTIATE_TEST_CASE_P(cvt422, Imgproc_ColorYUV,
    ::testing::Values((int)CV_YUV2RGB_UYVY, (int)CV_YUV2BGR_UYVY, (int)CV_YUV2RGBA_UYVY, (int)CV_YUV2BGRA_UYVY,
                      (int)CV_YUV2RGB_YUY2, (int)CV_YUV2BGR_YUY2, (int)CV_YUV2RGB_YVYU, (int)CV_YUV2BGR_YVYU,
                      (int)CV_YUV2RGBA_YUY2, (int)CV_YUV2BGRA_YUY2, (int)CV_YUV2RGBA_YVYU, (int)CV_YUV2BGRA_YVYU,
                      (int)CV_YUV2GRAY_UYVY, (int)CV_YUV2GRAY_YUY2));

/* [<][>][^][v][top][bottom][index][help] */