It's better to start right away from the second paragraph, because I can assume it's a priority.Bionarization (steering) is essentially a process whereby the amount of information available on the image is minimized. This fact is both a plus and a minus, since, together with uninterestested information, information is erased and that could have greatly contributed to the task.It is not difficult to see the presence of white ozone on the right side. These "zones" are of the same size and, in general, they are not separated from the exact same white "zone" but are already in the field of interest (parks).White " zones " within the area of interest may also have an arbitrary size and often cannot be considered as a whole with others in the vicinity, as they have separate boundaries and relatively close size with those that are not in the area of interest.By all means, the "zones" between the two areas of interest can be closer to each other (by the distance between the moments of contour) than the "zones" of the same parking spot.All of the above-mentioned exceptions are fully presented in the picture of the photoshop, which actually makes it impossible to correctly cluster the ozone contour into the automobile.By binarization, an acceptable result is extremely rare if the original image contains a natural environment.However, if a person is allowed to interfere with the algorithm, namely, to indicate to the last real boundaries of the facility by hand-delivering parking rectangles, the whole task will be a fairly simple operation. Example of binarization of the C++ and C# (EmguCV).Suppose there is a reference: We'll load it, translate it into shades of grey and binarize:C+++:cv::Mat src_mat = cv::imread("img.jpg");
if(src_mat.empty()) return;
cv::Mat gry_mat;
cv::cvtColor(src_mat, gry_mat, cv::COLOR_BGR2GRAY);
cv::Mat bin1_mat, bin2_mat;
cv::threshold(gry_mat, bin1_mat, 230, 255, cv::THRESH_BINARY);
cv::threshold(gry_mat, bin2_mat, 25, 255, cv::THRESH_BINARY_INV);
cv::Mat bin_mat = bin1_mat + bin2_mat;
C#:Mat srcMat = new Mat("img.jpg", LoadImageType.AnyColor);
if(srcMat.IsEmpty) return;
Mat grayMat = new Mat();
Mat bin1Mat = new Mat();
Mat bin2Mat = new Mat();
Mat binMat = new Mat();
CvInvoke.CvtColor(srcMat, grayMat, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(grayMat, bin1Mat, 230, 255, ThresholdType.Binary);
CvInvoke.Threshold(grayMat, bin2Mat, 25, 255, ThresholdType.BinaryInv);
CvInvoke.Add(bin1Mat, bin2Mat, binMat);
Here, an attempt has been made to binarize the upper and lower borders. The coefficients are selected manually and may differ as best for other images. Thus, more useful details are retained: Next, if we start looking for contours and paint them:C+++:std::vector<std::vector<cv::Point> > contours;
cv::findContours(bin_mat.clone(), contours
, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
cv::Mat ctr_mat = cv::Mat::zeros(bin_mat.size(), CV_8U);
cv::drawContours(ctr_mat, contours, -1, cv::Scalar::all(255), 1);
C#:VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat hierarchy;
CvInvoke.FindContours(binMat, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxSimple);
Mat ctrMat = new Mat(binMat.Size, DepthType.Cv8U, 3);
CvInvoke.DrawContours(ctrMat, contours, -1, new MCvScalar(255));
...we'll get a picture like this: Contours have proved to be quite large, and there is already doubt that the contours of individual parts can be assembled in a single contour of the vehicle. Let's try to filter some of them, for example, in the square, while drawing them on the specimen of quadratics in the original image:C+++:std::vector<std::vector<cv::Point> > contours;
cv::findContours(bin_mat.clone(), contours
, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
std::vector<std::vector<cv::Point> > contours2;
for(auto itr = contours.begin(); itr != contours.end(); ++itr) {
if(cv::contourArea(*itr) > 8) {
contours2.push_back(*itr);
cv::Rect rc = cv::boundingRect(*itr);
cv::rectangle(src_mat, rc, cv::Scalar(0,0,255));
}
}
cv::Mat ctr_mat = cv::Mat::zeros(bin_mat.size(), CV_8U);
cv::drawContours(ctr_mat, contours2, -1, cv::Scalar::all(255), 1);
C#:VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
VectorOfVectorOfPoint contours2 = new VectorOfVectorOfPoint();
Mat hierarchy;
CvInvoke.FindContours(binMat, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxSimple);
for (int i = 0; i < contours.Size; ++i)
{
if (CvInvoke.ContourArea(contours[i]) > 8)
{
contours2.Push(contours[i]);
Rectangle rc = CvInvoke.BoundingRectangle(contours[i]);
CvInvoke.Rectangle(srcMat, rc, new MCvScalar(0, 0, 255));
}
}
Mat ctrMat = new Mat(binMat.Size, DepthType.Cv8U, 3);
CvInvoke.DrawContours(ctrMat, contours2, -1, new MCvScalar(255));
The contours have become much smaller, the noise has become worse, but we continue to lose the information and the objects of interest (the automobiles), making them eventually more unlike the original. Those that are close to the camera, nowhere else went, but the more so, the more the situation is getting worse: At the end of the day, it may be necessary to draw the lumbaric contours of rectangles, and then it will be seen what it might be possible to draw together the dispersed parts of each car in a single whole: But the film does not question: parts of different objects are located at relatively same distances as parts of the same object, leading to the impossibility of correct clustering. And since we have other factors that might lead to the binarization, there is simply no problem with the automatic definition of the frontiers of motor vehicles under existing conditions. Well, maybe one or two cars close to the camera, but not anymore.In that case, there is nothing more than manually defining the limits of parking spaces. This task is usually not postponed because it has an arsenic function (with the user pointing out the location of the parking multi-angles) as a whole limited and implemented by means of general-purpose framings.A simple design can be used to obtain a map of the parking space from predetermined coordinates in the frame:cv::Mat parking_lot_mat = src_mat(cv::Rect(0,0,100,100)).clone();
Now. parking_lot_mat will contain part of the reference image at coordinates x equal to 0 and y equal to 0, and will be 100x100 peaks.Then you're doing all the same work on binarization as you did on the big picture. At the end, the contour and its area will be found by means of a method: cv::contourArea()♪ If the amount of the contour area exceeds a threshold shown empirically, then the vehicle in this parking area can be considered detected.