Search code examples
c++iosopencvimage-processingluminance

How to get luminosity of Mat image from opencv?


I'm doing an image processing on iOS using OpenCV in c++. Sometime the ambient light is not enough and the image cannot be processed properly. I did not found any suitable way to detect the ambient light so trying to detect the luminosity of the image instead.

This answer suggests to use the luma value or Y in YUV format. So I follow this answer to access the pixel in formation from Mat image after convert the image to YUV format.

- (void)processImage:(Mat&)image
{    
    Mat frame_yuv;
    cvtColor( image, frame_yuv, CV_BGR2YUV );

    uint8_t* pixelPtr = (uint8_t*)frame_yuv.data;
    int cn = frame_yuv.channels();
    for(int i = 0; i < frame_yuv.rows; i+=50)
    {
        for(int j = 0; j < frame_yuv.cols; j += 50)
        {
            Scalar_<uint8_t> yuvPixel;
            yuvPixel.val[0] = pixelPtr[i*frame_yuv.cols*cn + j*cn + 0]; // Y
            yuvPixel.val[1] = pixelPtr[i*frame_yuv.cols*cn + j*cn + 1]; // U
            yuvPixel.val[2] = pixelPtr[i*frame_yuv.cols*cn + j*cn + 2]; // V

            // do something with YUV values...
            std::cout << "Y: " << yuvPixel.val[0] << endl;
            std::cout << "U: " << yuvPixel.val[1] << endl;
            std::cout << "V: " << yuvPixel.val[2] << endl;
        }
    }
}

Here are some lines of log which contains some weird results to me and the values of "Y", "U", or "V" should not be this much in my understanding. Please suggest me what I missed or what did wrong? Thank you very much.

Y: P
U: \204
V: \206
Y: Q
U: \201
V: \207
Y: K
U: \205
V: \211
Y: H
U: \203
V: \210
Y: G
U: \202
V: \210
Y: H
U: \201
V: \210
Y: H
U: \202
V: \211
Y: \326
U: \200
V: \204
Y: \377
U: \200
V: \200
Y: \377
U: \200
V: \200
Y: \377
U: \200
V: \200
Y: \376
U: |
V: \201
Y: \313
U: x
V: \210
Y: \231
U: ~
V: \204
Y: \214
U: ~
V: \204
Y: \205
U: |
V: \204
Y: \221
U: 
V: \202

Solution

  • The reason for your log output is that your pixel values are of type uint8_t, which will be interpreted as unsigned char (on iOS, at least) when you try to output it to the console. So the log output is the character represented by that pixel value. To output the corresponding numerical value, cast the value to an int, like so:

    std::cout << "Y: " << (int)yuvPixel.val[0] << std::endl;
    std::cout << "U: " << (int)yuvPixel.val[1] << std::endl;
    std::cout << "V: " << (int)yuvPixel.val[2] << std::endl;
    

    Also, your posted code was outputting the same element three times, and bgrPixel was undefined. I have corrected those errors in this snippet as well.

    If you are only interested in the luminance information, you could instead call

    cv::cvtColor(image, frame_yuv, CV_BGR2GRAY);
    

    Which does the same color conversion as the Y channel of YUV, but will be more efficient.