0
votes

The following code runs without exception on iOS (Xcode-v6.2 and openCV-v3.0beta). But for some reason the image the function returns is "black" !

The code is adapted from this link ! I tried to replace the oldish "IplImage*" by more modern "cv::Mat" matrices. Does anybody know if my function still has a mistake or why it would return a completely "black" image instead of a colored image in HSV-format.

By the way, the reason I would want to use this function [instead of cvtColor(cv_src, imgHSV, cv::COLOR_BGR2HSV)] is that I would like to get 0-255 range of Hue-values's (...since OpenCV only allows Hues up to 180 instead of 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

1 Answers

1
votes

The cv::Mat M.depth() of a CV_8UC3-type matrix does unfortunately not return 8 - but instead it returns 0

Please have a look at the file "type_c.h"

#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() doesn't return the actual bit depth but the number symbol that represents the depth !!

After replacing to the following line - it all works !! (i.e. replacing .depth() by .type() in the if-statement...)

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