The robot has a new feature, it can follow a black line painted on the floor.
I've created a new sign with a line, when the robot reads this sign it will begin the line following process.
How it works
In fact the line following feature is implemented in a very simple way. Because the line is black is easy to isolate from the ground and this is performed using a simple binarization. Here are the steps of the implemented feature.
1. ROI
First thing to do is to chose a ROI (region of interest) like showed in the next picture.
In this case the middle region of the image will look like this:
Changing the ROI image (up an down) will change the robot behavior in the corners. If a top region is chosen the robot will turn sooner, otherwise it will turn later. This requires some tuning, it will depend on the robot speed and camera tilt angle.
Code looks like this:
Rect roi(0, 190, 640, 100);
greyImg(roi).copyTo(roiImg);
2. Threshold
Next thing to do is to threshold ROI image, the threshold level has to be tuned, the ideia is to get something like this:
I'm using morphological operations to reduce noise. Code looks like this:
threshold(roiImg, roiImg, thVal , 255, 0);
bitwise_not(roiImg, roiImg); // negative image
Mat erodeElmt = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat dilateElmt = getStructuringElement(MORPH_RECT, Size(5, 5));
erode(roiImg, roiImg, erodeElmt);
dilate(roiImg, roiImg, dilateElmt);
3. Find contours and center
Next step is to find image contours, in this case it will have just one contour (white quadrilateral). After finding image contour is easy to find its center that will be used to turn the robot. If the contour center moves to one side, the robot must turn to follow it.
Code to find center:
findContours(roiImg, contours, hierarchy, CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE, Point(0,0));
for (size_t i = 0; i < contours.size(); i++) {
float area = contourArea(contours[i]);
if (area > 2000) {
Moments mu;
mu = moments(contours[i], false);
Point2f center(mu.m10 / mu.m00, 240); // point in center (x only)
circle(camera, center, 5, Scalar(0, 255, 0), -1, 8, 0);
}
}