# Best approach for Grass Detection ?

I want to develop a program for detecting grass. It should be able to identify the input image as 'grass' or as 'obstacle'.

It should output as 'grass' if there is only grass in the input image, and if there is any object placed on grass, then it should output as 'obstacle'. Similarly, if there is no grass at all (i.e. concrete etc) or there is boundary between grass and concrete, it should output as 'obstacle'

Please guide me what approach to use for such kind of grass detection. Do I need a learning algorithm for this purpose or a non-learning algorithm (like features detection etc.) would serve the purpose. In both the cases, what would be the appropriate opencv functions to implement them.

Thanks.

Update: I have attached a sample image which contains grass as well as the concrete surface (obstacle)

edit retag close merge delete

( 2016-10-03 04:59:55 -0500 )edit

Basically this set of steps can get you there

• Empower Green color regions by for example using the Exessive Green formula.
• Then segment green regions and create a binary mask.
• If the mask has blobs that are larger then x pixels in the movement direction, then classify as object, else it is classified as grass!

But again, without samples a specific solutions is a randomn guess.

( 2016-10-03 08:37:55 -0500 )edit

@Balaji R I have attached a sample image via update in my original post

( 2016-10-17 03:31:25 -0500 )edit

@StevenPuttemans Actually I do not want to detect grass based on its green color since I could also encounter an obstacle of green color placed on the grass and i want it to be classified as an obstacle.

( 2016-10-17 03:32:32 -0500 )edit

Sort by » oldest newest most voted

You can use machine learning to do a lot of stuff but often there is a simpler way... for example you could start trying color filter... remove all green and look if anything survives in the image. Following StevePuttemans suggestions

Get colors in the image

Mat src, hsv,hue;
cv::cvtColor(src, hsv, CV_BGR2HSV_FULL);
vector<cv::Mat> hsvPlanes;
cv::split(hsv, hsvPlanes);
hue = hsvPlanes[0];


Green has Hue values at 120°+/-45° in the standard 0..360° RGB color wheel (https://en.wikipedia.org/wiki/Hue).

            COLOR       | HUE |
--------------+-----+
Red          |  0°
Orange       | 30°
Yellow       | 60° ------+ 42#
+--------> 75°             |
| Green-Yellow | 90°       | Grass
Greens --| Green        |120°       |
| Cyan-green   |150° ------+ 106#
+-------> 165°
Cyan         |180°
+-------> 195°
| Blue-Cyan    |210°
Blue-----| Blue         |240°
| Magenta-Blue |270°
+-------> 285°
Magenta      |300°
Red-Magenta  |330°
Red          |360°


Is common that grass has a bit of yellow. Because CV_BGR2HSV_FULL returns Hue between 0..255# you can get grass filtering the range 42#..106# A large smooth would help to remove discontinuities in grass

Mat greenMask;
GaussianBlur(hsv, hsv, Size(7, 7), 0);
//Because you are expecting only green objects...
Mat obstacle;
// do a morphology to reduce blobs complexity
morphologyEx(obstacle, obstacle, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(5, 5)));
imshow("obstacle", obstacle);


Finally use contours to detect blobs removing very small one

vector<vector<Point>> contours;
findContours(obstacle, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
int minArea = cvRound(0.002*src.cols*src.rows);
for (size_t i = 0; i < contours.size(); i++)
{
Rect rr = boundingRect(contours[i]);
if (rr.area() < minArea) continue;  //ignore small
rectangle(src, rr, Scalar(0, 0, 255), 2);
}
imshow("Findings", src);
waitKey(0);

more

Thanks for the detailed response. Actually i do not want to detect grass based on its green color since there maybe a case where a green colored object is placed on grass and I would want it to detect as an obstacle. The machine learning method you have mentioned earlier, can you explain it in detail as to what approach would be better to implement this. Thanks

( 2016-10-17 03:38:53 -0500 )edit

Another idea would be to analyse the gradients. On the grass, the gradients should be a directional; on a rough concrete surface they are chaotic, on a smooth surface they are weak.

So compute the gradients Gx and Gy of the image, and in a given region compute the PCA on the gradients. Let L1 and L2 be the first two principal components

If L1/L2 is high, than the image has directional gradients, so it's probably grass. If L2 is high, then you have a rough surface; if L1 has a low value, the region is smooth.

more

This approach looks good. I will give it a try. Thanks

( 2016-10-17 03:33:06 -0500 )edit

On the image you posted, the grass texture has mostly a chaotic nature, so you won't have much directional component. It will be probably the case where L2 is high.

You can also try a classical texture segmentation method by applying the Gabor filters or computing the Haralick descriptors and categorize each neighborhood using an SVM.

( 2016-10-17 03:40:00 -0500 )edit

yeah that seems a good option. But do you think SVM is better to use in this case or using ANN would be better ?

( 2016-10-17 15:16:35 -0500 )edit

Official site

GitHub

Wiki

Documentation