for (int i = 0; i < all_contours.size(); ++i) { if (all_contours[i].size() > min_size) { contours.push_back(all_contours[i]); } }
vector approx_poly; for (int i = 0; i < contours.size(); ++i) { double eps = contours[i].size()*APPROX_POLY_EPS; approxPolyDP(contours[i], approx_poly, eps, true);
if (approx_poly.size() != 4) continue;
if (!isContourConvex(approx_poly)) continue;
//Ensure that the distance between consecutive points is large enough float min_side = FLT_MAX; for (int j = 0; j < 4; ++j) { Point side = approx_poly[j] - approx_poly[(j+1)%4]; min_side = min(min_size, side.dot(side)); } if (min_side < min_side_length*min_side_length) continue;
Mat marker_image; Mat bit_matrix(5, 5, CV_8UC1); for (int i = 0; i < possible_markers.size(); ++i) { Mat M = getPerspectiveTransform(possible_markers[i].m_corners, m_marker_coords); warpPerspective(img_gray, marker_image, M, Size(MARKER_SIZE, MARKER_SIZE)); threshold(marker_image, marker_image, 125, 255, THRESH_BINARY|THRESH_OTSU); //OTSU determins threshold automatically.
//A marker must has a whole black border. for (int y = 0; y < 7; ++y) { int inc = (y == 0 || y == 6) ? 1 : 6; int cell_y = y*MARKER_CELL_SIZE;
for (int x = 0; x < 7; x += inc) { int cell_x = x*MARKER_CELL_SIZE; int none_zero_count = countNonZero(marker_image(Rect(cell_x, cell_y, MARKER_CELL_SIZE, MARKER_CELL_SIZE))); if (none_zero_count > MARKER_CELL_SIZE*MARKER_CELL_SIZE/4) goto __wrongMarker; } }
//Decode the marker for (int y = 0; y < 5; ++y) { int cell_y = (y+1)*MARKER_CELL_SIZE;
for (int x = 0; x < 5; ++x) { int cell_x = (x+1)*MARKER_CELL_SIZE; int none_zero_count = countNonZero(marker_image(Rect(cell_x, cell_y, MARKER_CELL_SIZE, MARKER_CELL_SIZE))); if (none_zero_count > MARKER_CELL_SIZE*MARKER_CELL_SIZE/2) bit_matrix.at(y, x) = 1; else bit_matrix.at(y, x) = 0; } }
//Find the right marker orientation bool good_marker = false; int rotation_idx; //逆时针旋转的次数 for (rotation_idx = 0; rotation_idx < 4; ++rotation_idx) { if (hammingDistance(bit_matrix) == 0) { good_marker = true; break; } bit_matrix = bitMatrixRotate(bit_matrix); } if (!good_marker) goto __wrongMarker;
//Store the final marker Marker& final_marker = possible_markers[i]; final_marker.m_id = bitMatrixToId(bit_matrix); std::rotate(final_marker.m_corners.begin(), final_marker.m_corners.begin() + rotation_idx, final_marker.m_corners.end()); final_markers.push_back(final_marker);