Description
The goal of this project is to implement algorithm that finds dots on dices. Motivation was idea / question how to create home-made random number generator? We can throw dices and our application will be able to recognize summary value on dices.
This program uses fitEllipse() function to find dots on dices. The basics steps are as follows:
Process
- Open video stream
CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
- For the whole stream we create single frame
IplImage* frame = cvQueryFrame( capture );
- Invert color
- Use adaptive threshold
adaptiveThreshold(image, bimage, 255, ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 15, -10);
- We can use morphological operations (dilatation, erosion) to expand/minimize contours
- To find circles we use following:
Mat pointsf; Mat(contours[i]).convertTo(pointsf, CV_32F); RotatedRect box = fitEllipse(pointsf);
- If difference between box.size.width and box.size.height is lower than treshold, we consider ellipse as circle.
- At this point we have a lot of “circlesâ€. An experimenting helped us to determine, which circle in the picture is real point on dice. Based on size of real dices points we can isolate only real dices points.
Example of process
Using custom settings we are able to improve results in specific situations.
findContours(bimage, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE); Vector<pair<RotatedRect*, int>> vec, finalVec; Mat cimage = Mat::zeros(bimage.size(), CV_8UC3); int i; int w, h, wAhThr, angleThr, centerThr; int hwDifferenceThreshold, histThreshold; centerThr = settCenterThr; wAhThr = settwAhThr; hwDifferenceThreshold = settHWdifferenceThr; histThreshold = settHistogramThr; for(i = 0; i < contours.size(); i++) { size_t count = contours[i].size(); if( count > 50 || count < 6) continue; Mat pointsf; Mat(contours[i]).convertTo(pointsf, CV_32F); RotatedRect box = fitEllipse(pointsf); w = box.size.width; h = box.size.height; int hwDifference = abs(h - w); if (hwDifference > hwDifferenceThreshold) continue; if (w < wAhThr || h < wAhThr) continue; vec.push_back(pair<RotatedRect*, int>(new RotatedRect(box), i)); } int asdf = vec.size(); Vector<pair<RotatedRect* ,int>>::iterator it ,iend, it2; int MAXHIST = 200; int* histVals = new int[MAXHIST]; for (int i = 0; i < MAXHIST; i++) histVals[i] = 0; int histIter = 0; RotatedRect * box; RotatedRect * box2; int maxWidth = 0; int distanceOfCenters; for (it = vec.begin(), iend = vec.end(); it != iend; it++) { box = (it->first); for (it2 = it + 1; it2 != iend; it2++) { box2 = (it2->first); distanceOfCenters = (int)std::sqrt((box->center.x - box2->center.x) * (box->center.x - box2->center.x) + (box->center.y - box2->center.y) * (box->center.y - box2->center.y)); if (distanceOfCenters < centerThr) { if (box->size.width > box2->size.width) it2->second = -1; else it->second = -1; break; } } }