Ask Your Question
0

Math on every pixel to Calculate NDVI?

asked 2016-04-04 14:54:58 -0600

barronlroth gravatar image

I'm very new to OpenCV and attempting to do something which seems simple, but execution for an amateur is difficult.

I have to iterate through every pixel in an image, perform some math on the current pixel's RGB values (Red-Blue/Red+Blue), and output an image (in HSL) with a hue:

newHue = (ndvi-.5)*(-360)

and a saturation & brightness of 1 (constant across the output image).

Any tips on getting started with something like this?

edit retag flag offensive close merge delete

Comments

what have you tried so far?

strann gravatar imagestrann ( 2016-04-05 02:16:28 -0600 )edit
1

It looks like this thread

LBerger gravatar imageLBerger ( 2016-04-05 02:34:13 -0600 )edit

3 answers

Sort by ยป oldest newest most voted
1

answered 2016-04-05 03:22:31 -0600

strann gravatar image

You can perform band math using element-wise operations like this

    vector<Mat> channels;
    split(imageBGR, channels);
    Mat numeratorMat = channels[2] - channels[0]; // red - blue
    Mat denominatorMat = channels[2] + channels[0]; // red + blue
    Mat ratio;
    cv::divide(denominatorMat, numeratorMat, ratio, 1., 5); // here 5 specifies type of ratio (CV_32FC1)

Then you can do something like

   Mat newHue = (ratio.clone() - 0.5 ) * (-360); // float 32
   Mat newLigthness = Mat::ones(imageBGR.rows, imageBGR.cols, CV_32FC1);
   Mat newSaturation = Mat::ones(imageBGR.rows, imageBGR.cols, CV_32FC1);

   vector<Mat> newChannels;
   newChannels.push_back(newHue);
   newChannels.push_back(newSaturation);
   newChannels.push_back(newLigthness);
   Mat newHSL;
   cv::merge(newChannels, newHSL);
edit flag offensive delete link more
1

answered 2016-04-05 02:56:15 -0600

If you want to convert your image in HSL, the proper way to do it in OpenCV is:

cv::cvtColor( src, dst, cv::COLOR_BGR2HLS );

If your intent is to do it manually, then you can iterate through the pixel that way:

for(int r = 0 ; r < src.rows ; ++r) {
    for(int c = 0 ; c < src.cols ; ++c) {
        dst.at<cv::Vec3b>(r,c) = cv::Vec3b(newHue, /*newLigthness*/1, /*newSaturation*/1);
    }
}

This is the most standard (and slow way) to iterate through pixels, but also the most obvious. If you want to have a look at how to speed-up the pixel iteration, I suggest you have a look at this tutorial or even, this tutorial for a very basic (but yet helpful) introduction to OpenCV images..

edit flag offensive delete link more
0

answered 2016-04-05 04:44:00 -0600

kbarni gravatar image

updated 2016-04-05 04:48:03 -0600

There are several problems in your approach that the other answers didn't adress:

  • in OpenCV HSV space the Hue angle is between 0-180! (not 360)
  • to get the HSV color map, the saturation/lightness should be 255, not 1!
  • they all forgot to convert back the hsv image to RGB: cvtColor(hsvimage,color,COLOR_HSV2BGR);
  • probably it's easier to use color mapping than HSV conversion.

So the second part of strann's answer using color mapping would be:

// Normalize NDVI between 0 and 255 and convert to byte type (CV_8UC1)
normalize(ratio, ratio, 0, 255, NORM_MINMAX, CV_8UC1);
//or: normalize(ratio, ratio, 127,127,NORM_L2,CV_8UC1);
// Apply a color map 
applyColorMap(ratio, cm_img0, COLORMAP_HSV);
// Show the result:
imshow("NDVI color map", cm_img0);

Some more information about color maps: http://docs.opencv.org/3.1.0/d3/d50/g...

BTW, it seems that you try to use Public lab's method of calculating NDVI using a camera without IR filter. According to my experiences it's results aren't very accurate, but it's a good start for experimenting.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2016-04-04 14:54:58 -0600

Seen: 3,061 times

Last updated: Apr 05 '16