My current project is to use OpenCV and a webcam to follow a line with the Lego Mindstorm EV3. That would be black tape on a light background. I have a test image (white left, black right) that I can process. The idea is to use moments to find the x location of the vertical line. I can process my test image with cvtColor, GaussianBlur, threshold, erode, dilate, findContours and drawContour. The white region is seen as a block bounded by the edges of the frame. I can create a black border on the contour image to remove the frame edges. Then I am left with a vertical line. FindContours should find the line. But, findContours is area based and I am trying something that is line based. If I findContours of the vertical line, I go back to the edges. What is the contour of a line? I get three contours. 1 left edge and line. 2 line. 3 right edge and line. I could just use the second contour, but that will not expand to a real image with an unknown number of contours. My idea is to find the x location of the vertical line with moments. I can get the average x location of all the moments, but that is misleading and inaccurate. Or, will I have to use BondingRect.
My problem is with OpenCV. Does anyone know OpenCV well enough to suggest a valid approach to solve this problem?
2/20/2018
My commenter wants a real image. A real image makes this more difficult. But, I have provided. The Lego EV3 runs at 300 Hz. So, my simulations are on my desktop (3Gz). The original project is at LeJosNews in java. But, most of the OpenCV documentation I am finding is in C++. I am trying an easy slow start with this project, so I am using C++ at 3Gz. The original core java code is as follows …
private float getMidPoint(int bias)
{
vid.read(camImage);
Mat roi = new Mat(camImage, new Rect(10, 2*camImage.rows()/3, camImage.cols()-20,
camImage.rows()/12));
Imgproc.cvtColor(roi, mono, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(mono, blur, new Size(9, 9), 2, 2);
Imgproc.threshold(blur, thresh, 0, 255, Imgproc.THRESH_BINARY_INV|Imgproc.THRESH_OTSU);
Imgproc.erode(thresh, erodeImg, erode);
Imgproc.dilate(erodeImg, dilateImg, dilate);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(dilateImg, contours, notused, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
double minMaxCx = (bias > 0 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
for(MatOfPoint cont : contours)
{
Moments mu = Imgproc.moments(cont, false);
if (mu.get_m00() > 100.0)
{
Rect r = Imgproc.boundingRect(cont);
double cx;
if (bias > 0)
{
cx = r.x + r.width - 12;
if (cx > minMaxCx)
{
minMaxCx = cx;
}
}
else
{
cx = r.x + 12;
if (minMaxCx > cx)
{
minMaxCx = cx;
}
}
}
}
if (Double.isInfinite(minMaxCx))
minMaxCx = roi.cols()/2;
return 1.0f - 2.0f*(float)minMaxCx/roi.cols();
}
And in C++ that is …
#include "stdafx.h"
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
Mat src;
Mat frame;
int bias = 0;
int Countt = 0;
const Scalar white = Scalar(255, 255, 255);
const Scalar black = Scalar(0);
Scalar color = Scalar(128, 255, 255);
/// Function headers
int display_caption(const char* caption);
int display_dst(int delay);
vector<vector<Point> > contours; // From Contours.cpp2
vector<Vec4i> hierarchy; // From Contours.cpp3
vector<Point> cont;
/**
* function main
*/
int main(int argc, char ** argv)
{
Mat frame;
src = imread("166.jpg.");
resize(src, src, Size(), 0.5, 0.5);
printf("Before 166.jpg.\n");
imshow("166.jpg. Press any key ...", src);
waitKey();
Mat Canvas = Mat::zeros(src.size(), CV_8UC3);
Mat mono;
printf("Before cvtColor.\n");
cvtColor(src, mono, COLOR_BGR2GRAY);
imshow("After cvtColor. Press any key ...", mono);
waitKey();
Mat Iblur;
printf("Before GaussianBlur.\n");
GaussianBlur(mono, Iblur, Size(9, 9), 2, 2);
imshow("After GaussionBlur. Press any key ...", Iblur);
waitKey();
Mat thresh;
printf("Before threshold.\n");
threshold(Iblur, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
imshow("After threshold. Press any key ...", thresh);
waitKey();
Mat erodeImg;
printf("Before erode.\n");
erode(thresh, erodeImg, 1);
imshow("After erode. Press any key ...", erodeImg);
waitKey();
Mat dilateImg;
printf("Before dilate.\n");
dilate(erodeImg, dilateImg, 1);
imshow("After dilate. Press any key ...", dilateImg);
waitKey();
printf("Before findcontours.\n");
//
findContours( //
dilateImg, // Image //
contours, // Contours //
hierarchy, // Hierarchy //
RETR_TREE, // int - Contour retrieval mode: RETR_LIST, RETR_CCOMP //
CHAIN_APPROX_NONE); // int - Contour approximantion Method: CHAIN_APPROX_SIMPLE, CHAIN_APPROX_NONE //
//
imshow("After findContours. Press any key ...", dilateImg); //
waitKey();
Scalar color = Scalar(128, 255, 255);
//Mat dstt;
//dstt = Mat::zeros(dilateImg.cols, dilateImg.rows, CV_8UC3);
Mat dstt = Mat::zeros(src.size(), CV_8UC3);
printf("Before drawContours.\n");
for (int i = 0; i < contours.size(); i++) //
{ //
//
drawContours( //
dstt, // Image //
contours, // Contours //
i, // int: Contouridx //
color, // Color //
1, // Thickness, Defalt = 1 //
LINE_8, // LineType, Defalt = LINE_8, //
hierarchy, //
100); // Hierarchy = //
// //
} //
//
imshow("After drawContours. Press any key ...", dstt); //
waitKey();
vector<Moments> mu(contours.size());
bias = 1; // Left edge
bias = -1; // Right edge
// TRUE FALSE
double minMaxCx = (bias > 0 ? -5280 : 5280);
double cx;
for (int i = 0; i < contours.size(); i++) //Or: "for (vector<Point>cont : contours);"
{
mu[i] = moments(contours[i], false); // Get the moments
Rect r = boundingRect(contours[i]);
printf(" %d: \tx %d, \ty %d, \tw %d, \th %d \tA %.2f\n",i+1, r.x, r.y, r.width, r.height, mu[i].m00);
if (mu[i].m00 > 100.0) //
{
if (bias > 0) // bias is +1, Find left edge
{
cx = r.x + r.width - 40;
if (cx > minMaxCx)
{
minMaxCx = cx;
}
}
else // bias is -1, Find right edge
{
cx = r.x + 12;
if (minMaxCx > cx)
{
minMaxCx = cx;
}
}
}
waitKey();
}
if (!isfinite(minMaxCx))
{
cout << minMaxCx;
minMaxCx = dstt.cols / 2;
cout << minMaxCx;
}
float Ans;
Ans = 1.0f - 2.0f*(float)minMaxCx / dstt.cols;
printf("And the answer is ");
cout << Ans;
waitKey();
mmmmmmmmmmmmmmmmmmm
mmmmmmmmmmm
}](/upfiles/15191311699815329.jpg)(/upfiles/15191307643293393.png)[C:\fakepath\166.jpg](/upfiles/15191321077402117.jpg)