Exemplo n.º 1
0
void MarkerDetector::recognizeMarkers(const cv::Mat& grayscale, std::vector<Marker>& detectedMarkers)
{
    std::vector<Marker> goodMarkers;

    // Identify the markers
    for (size_t i=0;i<detectedMarkers.size();i++)
    {
        Marker& marker = detectedMarkers[i];

        // Find the perspective transformation that brings current marker to rectangular form
        cv::Mat markerTransform = cv::getPerspectiveTransform(marker.points, m_markerCorners2d);

        // Transform image to get a canonical marker image
        cv::warpPerspective(grayscale, canonicalMarkerImage,  markerTransform, markerSize);

#ifdef SHOW_DEBUG_IMAGES
        {
            cv::Mat markerImage = grayscale.clone();
            marker.drawContour(markerImage);
            cv::Mat markerSubImage = markerImage(cv::boundingRect(marker.points));

            cv::showAndSave("Source marker" + ToString(i),           markerSubImage);
            cv::showAndSave("Marker " + ToString(i) + " after warp", canonicalMarkerImage);
        }
#endif

        int nRotations;
        int id = Marker::getMarkerId(canonicalMarkerImage, nRotations);
        if (id !=- 1)
        {
            marker.id = id;
            //sort the points so that they are always in the same order no matter the camera orientation
            std::rotate(marker.points.begin(), marker.points.begin() + 4 - nRotations, marker.points.end());

            goodMarkers.push_back(marker);
        }
    }  

    // Refine marker corners using sub pixel accuracy
    if (goodMarkers.size() > 0)
    {
        std::vector<cv::Point2f> preciseCorners(4 * goodMarkers.size());

        for (size_t i=0; i<goodMarkers.size(); i++)
        {  
            const Marker& marker = goodMarkers[i];      

            for (int c = 0; c <4; c++)
            {
                preciseCorners[i*4 + c] = marker.points[c];
            }
        }

        cv::TermCriteria termCriteria = cv::TermCriteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS, 30, 0.01);
        cv::cornerSubPix(grayscale, preciseCorners, cvSize(5,5), cvSize(-1,-1), termCriteria);

        // Copy refined corners position back to markers
        for (size_t i=0; i<goodMarkers.size(); i++)
        {
            Marker& marker = goodMarkers[i];      

            for (int c=0;c<4;c++) 
            {
                marker.points[c] = preciseCorners[i*4 + c];
            }      
        }
    }

#if SHOW_DEBUG_IMAGES
    {
        cv::Mat markerCornersMat(grayscale.size(), grayscale.type());
        markerCornersMat = cv::Scalar(0);

        for (size_t i=0; i<goodMarkers.size(); i++)
        {
            goodMarkers[i].drawContour(markerCornersMat, cv::Scalar(255));    
        }

        cv::showAndSave("Markers refined edges", grayscale * 0.5 + markerCornersMat);
    }
#endif

    detectedMarkers = goodMarkers;
}
// This function takes the input list of parallelepipeds and verifies wheter they are markers or not.
// The following are the main steps performed:
// 1.   Removal of the perspective projection to obtain a frontal view of the rectangle area.
// 2.   Perform a thresholding of the image using the Otsu algorithm (see: Marker::getMarkerId).
// 3.   Identify the marker internal code: the marker is divided into a 7x7 grid.
//      The internal 5x5 cells contain ID information, and the rest represent the external black border.
void MarkerDetector::detectMarkers(const cv::Mat& grayscale, std::vector<Marker>& detectedMarkers)
{
	std::vector<Marker> goodMarkers;
	// Identify the markers.
	for (size_t i = 0; i < detectedMarkers.size(); i++) {
		Marker& marker = detectedMarkers[i];
		// To get the rectangle marker image we have to unwarp the input image using the proper perspective transformation.
		// This matrix can be retrieved from pairs of corresponding points (marker coords in image space + square marker image coords).
		// Find the perspective transformation that brings current marker to rectangular form.
		// See: http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html#getperspectivetransform
		cv::Mat markerTransform = cv::getPerspectiveTransform(marker.points, markerCorners2D);
		// Transform image to get a canonical marker image.
		// See: http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html#warpperspective
		cv::warpPerspective(grayscale, canonicalMarkerImage, markerTransform, markerSize);

#ifdef _DEBUG
		cv::Mat markerImage = grayscale.clone();
		marker.drawContour(markerImage);
		cv::Mat markerSubImage = markerImage(cv::boundingRect(marker.points));
		cv::imshow("Source Marker", markerSubImage);
		cv::imshow("Marker After Warp", canonicalMarkerImage);
#endif

		int nRotations;
		int id = Marker::getMarkerId(canonicalMarkerImage, nRotations);
		if (id != -1) {
			// After finding the right marker orientation, 
			// we rotate the corners of the marker respectively to conform to their order.
			marker.id = id;
			// Sort the points so that they are always in the same order no matter the camera orientation.
			std::rotate(marker.points.begin(), marker.points.begin() + 4 - nRotations, marker.points.end());
			goodMarkers.push_back(marker);
		}
	}
	// Refine marker corners using sub pixel accuracy.
	if (goodMarkers.size() > 0) {
		// After detecting a marker and decoding its ID, we will refine its corners.
		// This operation will ease the next step consisting in the estimation of the marker 3D position.
		// To find the corner location with subpixel accuracy we use the cv::cornerSubPix function:
		// 1.   prepare the input data copying the list of vertices,
		// 2.   then we call cv::cornerSubPix with the proper input arguments,
		// 3.   finally we copy the refined locations back to marker corners.
		// *   We do not use cv::cornerSubPix in the earlier stages of marker detection due to its complexity.
		//     It is very computationally expensive to call this function for large numbers of points.
		//     Therefore we do this only for valid markers.
		std::vector<cv::Point2f> preciseCorners(4 * goodMarkers.size());
		for (size_t i = 0; i < goodMarkers.size(); i++) {
			const Marker& marker = goodMarkers[i];
			for (int c = 0; c < 4; c++) { preciseCorners[i * 4 + c] = marker.points[c]; }
		}
		cv::TermCriteria termCriteria = cv::TermCriteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS, 30, 0.01);
		cv::cornerSubPix(grayscale, preciseCorners, cv::Size(5, 5), cv::Size(-1, -1), termCriteria);
		// Copy refined corners position back to markers.
		for (size_t i = 0; i < goodMarkers.size(); i++) {
			Marker& marker = goodMarkers[i];
			for (int c = 0; c < 4; c++) { marker.points[c] = preciseCorners[i * 4 + c]; }
		}
	}

#ifdef _DEBUG
	cv::Mat markerCornersMat(grayscale.size(), grayscale.type());
	markerCornersMat = cv::Scalar(0);
	for (size_t i = 0; i < goodMarkers.size(); i++) { goodMarkers[i].drawContour(markerCornersMat, cv::Scalar(255)); }
	cv::imshow("Markers Refined Edges", grayscale * 0.5 + markerCornersMat);
#endif

	detectedMarkers = goodMarkers;
}