Question

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
Was it helpful?

Solution 2

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.

OTHER TIPS

Here's how you can do it pretty simply, works for me!

Also posted here on PasteBin: https://pastebin.com/tA1R8Qtm

// -----------------------------------------------------
// ---------- FIND AVG LUMINENCE OF FRAME --------------
// -----------------------------------------------------

// Assuming you have a cv::Mat to start with called "input_mat"
cv::Mat grayMat; 
cv::cvtColor(input_mat, grayMat, CV_BGR2GRAY);

int Totalintensity = 0;
for (int i=0; i < grayMat.rows; ++i){
    for (int j=0; j < grayMat.cols; ++j){
        Totalintensity += (int)grayMat.at<uchar>(i, j);
    }
}

// Find avg lum of frame
float avgLum = 0;
avgLum = Totalintensity/(grayMat.rows * grayMat.cols);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top