Ask Your Question

# Math on every pixel to Calculate NDVI?

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 close merge delete

1

## 3 answers

Sort by » oldest newest most voted

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

    vector<Mat> channels;
split(imageBGR, channels);
Mat numeratorMat = channels - channels; // red - blue
Mat denominatorMat = channels + channels; // 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);

more

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..

more 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.

more

Official site

GitHub

Wiki

Documentation

## Stats

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

Seen: 2,324 times

Last updated: Apr 05 '16