全系列色调:OpenCV的HSV到RGB颜色转换

时间:2015-03-26 15:38:02

标签: ios opencv hsv

以下代码在iOS(Xcode-v6.2和openCV-v3.0beta)上运行无例外。但由于某种原因,函数返回的图像是“黑色”!

代码改编自this link!我试图用更现代的“cv :: Mat”矩阵替换旧的“IplImage *”。有没有人知道我的功能是否仍有错误,或者为什么它会返回一个完全“黑色”的图像而不是HSV格式的彩色图像。

顺便说一句,我想要使用这个函数[而不是cvtColor(cv_src,imgHSV,cv :: COLOR_BGR2HSV)]的原因是我希望得到0-255范围的Hue-values(...因为OpenCV只允许Hues高达180而不是255。

// Create a HSV image from the RGB image using the full 8-bits, since OpenCV only allows Hues up to 180 instead of 255.
cv::Mat convertImageRGBtoHSV(cv::Mat imageRGB) {

    float fR, fG, fB;
    float fH, fS, fV;
    const float FLOAT_TO_BYTE = 255.0f;
    const float BYTE_TO_FLOAT = 1.0f / FLOAT_TO_BYTE;

    // Create a blank HSV image
    cv::Mat imageHSV(imageRGB.rows, imageRGB.cols, CV_8UC3);

    int rowSizeHSV = (int)imageHSV.step;    // Size of row in bytes, including extra padding.
    char *imHSV = (char*)imageHSV.data;     // Pointer to the start of the image pixels.

    if (imageRGB.depth() == 8 && imageRGB.channels() == 3) {

        std::vector<cv::Mat> planes(3);
        cv::split(imageRGB, planes);
        cv::Mat R = planes[2];
        cv::Mat G = planes[1];
        cv::Mat B = planes[0];

        for(int y = 0; y < imageRGB.rows; ++y)
        {
            // get pointers to each row
            cv::Vec3b* row = imageRGB.ptr<cv::Vec3b>(y);

            // now scan the row
            for(int x = 0; x < imageRGB.cols; ++x)
            {
                // Get the RGB pixel components. NOTE that OpenCV stores RGB pixels in B,G,R order.
                cv::Vec3b pixel = row[x];
                int bR = pixel[2];
                int bG = pixel[1];
                int bB = pixel[0];

                // Convert from 8-bit integers to floats.
                fR = bR * BYTE_TO_FLOAT;
                fG = bG * BYTE_TO_FLOAT;
                fB = bB * BYTE_TO_FLOAT;

                // Convert from RGB to HSV, using float ranges 0.0 to 1.0.
                float fDelta;
                float fMin, fMax;
                int iMax;
                // Get the min and max, but use integer comparisons for slight speedup.
                if (bB < bG) {
                    if (bB < bR) {
                        fMin = fB;
                        if (bR > bG) {
                            iMax = bR;
                            fMax = fR;
                        }
                        else {
                            iMax = bG;
                            fMax = fG;
                        }
                    }
                    else {
                        fMin = fR;
                        fMax = fG;
                        iMax = bG;
                    }
                }
                else {
                    if (bG < bR) {
                        fMin = fG;
                        if (bB > bR) {
                            fMax = fB;
                            iMax = bB;
                        }
                        else {
                            fMax = fR;
                            iMax = bR;
                        }
                    }
                    else {
                        fMin = fR;
                        fMax = fB;
                        iMax = bB;
                    }
                }
                fDelta = fMax - fMin;
                fV = fMax;              // Value (Brightness).
                if (iMax != 0) {            // Make sure it's not pure black.
                    fS = fDelta / fMax;     // Saturation.
                    float ANGLE_TO_UNIT = 1.0f / (6.0f * fDelta);   // Make the Hues between 0.0 to 1.0 instead of 6.0
                    if (iMax == bR) {       // between yellow and magenta.
                        fH = (fG - fB) * ANGLE_TO_UNIT;
                    }
                    else if (iMax == bG) {      // between cyan and yellow.
                        fH = (2.0f/6.0f) + ( fB - fR ) * ANGLE_TO_UNIT;
                    }
                    else {              // between magenta and cyan.
                        fH = (4.0f/6.0f) + ( fR - fG ) * ANGLE_TO_UNIT;
                    }
                    // Wrap outlier Hues around the circle.
                    if (fH < 0.0f)
                        fH += 1.0f;
                    if (fH >= 1.0f)
                        fH -= 1.0f;
                }
                else {
                    // color is pure Black.
                    fS = 0;
                    fH = 0; // undefined hue
                }

                // Convert from floats to 8-bit integers.
                int bH = (int)(0.5f + fH * 255.0f);
                int bS = (int)(0.5f + fS * 255.0f);
                int bV = (int)(0.5f + fV * 255.0f);

                // Clip the values to make sure it fits within the 8bits.
                if (bH > 255)
                    bH = 255;
                if (bH < 0)
                    bH = 0;
                if (bS > 255)
                    bS = 255;
                if (bS < 0)
                    bS = 0;
                if (bV > 255)
                    bV = 255;
                if (bV < 0)
                    bV = 0;

                // Set the HSV pixel components.
                uchar *pHSV = (uchar*)(imHSV + y*rowSizeHSV + x*3);
                *(pHSV+0) = bH;     // H component
                *(pHSV+1) = bS;     // S component
                *(pHSV+2) = bV;     // V component
            }
        }
    }
    return imageHSV;
}

1 个答案:

答案 0 :(得分:0)

CV_8UC3类型矩阵的cv :: Mat M.depth()遗憾地不会返回8 - 而是返回0

请查看文件&#34; type_c.h&#34;

#define CV_8U   0 
#define CV_CN_SHIFT   3
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)

depth()不会返回实际的位深度,而是表示深度的数字符号!!

更换到以下系列后 - 一切正常!! (即在if语句中用.type()替换.depth()......)

if (imageHSV.type() == CV_8UC3 && imageHSV.channels() == 3) {...}