opencv rechteckigen Bereich betrachten



  • Achso jetzt habe ich das Beispielbild vergessen:

    PuzzleTeileScan.jpg
    http://s14.directupload.net/file/d/3124/qjnndszd_jpg.htm

    Edge.jpg
    http://s1.directupload.net/file/d/3124/2tmhdjb5_jpg.htm



  • Hilft es dir vielleicht schon, die Ausrichtung der Teile grob zu kennen?
    Eingabe: http://daiw.de/share/Forum/cpp/20130104Puzzle/ten_small.jpg
    Ausgabe: http://daiw.de/share/Forum/cpp/20130104Puzzle/output_contours.jpg

    #include "opencv2/opencv.hpp"
    
    int main()
    {
    	using namespace cv;
    	using namespace std;
    
    	// Load image.
    	string imageFileName("ten_small.jpg");
    	Mat rgbImage(imread(imageFileName));
    
    	// No image data?
    	if(!rgbImage.data)
    	{
    		cout << "Unable to load: " << imageFileName << "\n";
    		return -1;
    	}
    
    	// Convert to HSV.
    	Mat hsvImage;
    	cvtColor(rgbImage, hsvImage, CV_BGR2HSV);
    
    	// Threshold and blur.
    	Mat mask;
    	inRange(hsvImage, Scalar(0, 0, 93), Scalar(255, 62, 255), mask);
    	blur(mask, mask, Size(5,5));
    
    	// Find the contours.
    	typedef vector<Point> Contour;
    	vector<Contour> contours;
    	{
    		// cv::findContours destroys the original image, so we need a copy.
    		Mat findImage(mask.clone());
    		findContours(findImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
    	}
    
    	// Helper function for drawing rotated rectangles.
    	auto drawRotatedRect([](Mat& image, const RotatedRect& rRect, const Scalar& col)
    	{
    		Point2f vertices[4];
    		rRect.points(vertices);
    		for (int i = 0; i < 4; i++)
    			line(image, vertices[i], vertices[(i+1)%4], col);
    	});
    
    	// Draw contours and minAreaRects.
    	Mat drawImage(mask.size(), CV_8UC3, Scalar(0, 0, 0));
    	for_each(begin(contours), end(contours), [&](const Contour& contour)
    	{
    		drawContours(drawImage, vector<Contour>(1, contour), 0, Scalar(255, 0, 0), 2);
    		drawRotatedRect(drawImage, minAreaRect(contour), Scalar(0, 0, 255));
    	});
    
    	// Save results.
    	imwrite("output_mask.jpg", mask);
    	imwrite("output_contours.jpg", drawImage);
    }
    


  • Dank dir, ich denke damit kann man nun recht gut die Ecken des Puzzles bestimmen.
    Gibt es so eine Funktion wie - bestimme den kürzesten Abstand von einem Punkt(Eckpunkt des Quadrates) zu einem Punkt auf der Kontur. Dies ist dann mit hoher Wahrscheinlichkeit ein Eckpunkt.



  • In OpenCV gibt es so eine Funktion nicht fertig, aber die ist ja schnell geschrieben:

    #include "opencv2/opencv.hpp"
    
    typedef std::vector<cv::Point> Contour;
    typedef std::vector<cv::Point> Corners;
    
    // Distance between two points.
    float Dist(const cv::Point& p1, const cv::Point& p2)
    {
    	float dx(p1.x-p2.x);
    	float dy(p1.y-p2.y);
    	return sqrt(dx * dx + dy * dy);
    }
    
    // Find possible corners.
    Corners ContourCorners(const Contour& contour)
    {
    	using namespace cv;
    	using namespace std;
    	Corners result;
    	auto rRect(minAreaRect(contour));
    	Point2f rectCorners[4];
    	rRect.points(rectCorners);
    	for_each(begin(rectCorners), end(rectCorners), [&](const Point& rectCorner)
    	{
    		result.push_back(
    			*min_element(begin(contour), end(contour),
    				[&rectCorner](const Point& lhs, const Point& rhs)
    			{
    				return Dist(lhs, rectCorner) < Dist(rhs, rectCorner);
    			})
    		);
    	});
    	return result;
    }
    
    // Draw rotated rectangle.
    void DrawRotatedRect(cv::Mat& image, const cv::RotatedRect& rRect, const cv::Scalar& col)
    {
    	using namespace cv;
    	using namespace std;
    	Point2f vertices[4];
    	rRect.points(vertices);
    	for (int i = 0; i < 4; i++)
    		line(image, vertices[i], vertices[(i+1)%4], col);
    }
    
    int main()
    {
    	using namespace cv;
    	using namespace std;
    
    	// Load image.
    	string imageFileName("ten_small.jpg");
    	Mat rgbImage(imread(imageFileName));
    
    	// No image data?
    	if(!rgbImage.data)
    	{
    		cout << "Unable to load: " << imageFileName << "\n";
    		return -1;
    	}
    
    	// Convert to HSV.
    	Mat hsvImage;
    	cvtColor(rgbImage, hsvImage, CV_BGR2HSV);
    
    	// Threshold and blur.
    	Mat mask;
    	inRange(hsvImage, Scalar(0, 0, 93), Scalar(255, 62, 255), mask);
    	blur(mask, mask, Size(5,5));
    
    	// Find the contours.
    	vector<Contour> contours;
    	{
    		// cv::findContours destroys the original image, so we need a copy.
    		Mat findImage(mask.clone());
    		findContours(findImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
    	}
    
    	// Draw contours, minAreaRects and possible corners.
    	Mat drawImage(mask.size(), CV_8UC3, Scalar(0, 0, 0));
    	for_each(begin(contours), end(contours), [&](const Contour& contour)
    	{
    		drawContours(drawImage, vector<Contour>(1, contour), 0, Scalar(255, 0, 0), 2);
    		DrawRotatedRect(drawImage, minAreaRect(contour), Scalar(0, 0, 255));
    
    		// Find Corners.
    		auto corners(ContourCorners(contour));
    		for_each(begin(corners), end(corners), [&](const Point& point)	
    		{
    			circle(drawImage, point, 4, Scalar(0, 255, 0), 2);
    		});
    	});
    
    	// Save result.
    	imwrite("output_corners.jpg", drawImage);
    }
    

    Meistens passt es auch, aber eben doch nicht immer. 😉
    Input: http://daiw.de/share/Forum/cpp/20130105Puzzle/ten_small.jpg
    Output: http://daiw.de/share/Forum/cpp/20130105Puzzle/output_corners.jpg



  • Danke, da kann man bestimmt noch was drehen.
    Ich habe diese Woche leider nicht viel Zeit melde mich dann aber bestimmt nochmal.



  • Hi hatte soeben mal kurz Zeit mir dein Beipiel genauer anzusehen.
    Beim compilieren erhalte ich folgende Fehler, woran kann das denn liegen ?

    ------ Erstellen gestartet: Projekt: Puzzle Solver, Konfiguration: Debug Win32 ------
    Find Contur.cpp
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(9): warning C4244: 'Initialisierung': Konvertierung von 'const int' in 'float', möglicher Datenverlust
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(10): warning C4244: 'Initialisierung': Konvertierung von 'const int' in 'float', möglicher Datenverlust
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(26): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(26): error C2143: Syntaxfehler: Es fehlt ',' vor '&'
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(28): error C2065: 'lhs': nichtdeklarierter Bezeichner
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(28): error C2065: 'rhs': nichtdeklarierter Bezeichner
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(26): error C3861: "min_element": Bezeichner wurde nicht gefunden.
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(28): error C2065: 'lhs': nichtdeklarierter Bezeichner
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(28): error C2065: 'rhs': nichtdeklarierter Bezeichner
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(83): error C2065: 'vector': nichtdeklarierter Bezeichner
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(83): error C2275: 'Contour': Ungültige Verwendung dieses Typs als Ausdruck
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(3): Siehe Deklaration von 'Contour'
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(83): error C3861: "Scalar": Bezeichner wurde nicht gefunden.
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(84): error C3861: "Scalar": Bezeichner wurde nicht gefunden.
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(88): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(88): error C2143: Syntaxfehler: Es fehlt ',' vor '&'
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(90): error C2065: 'point': nichtdeklarierter Bezeichner
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(88): error C3861: "for_each": Bezeichner wurde nicht gefunden.
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(90): error C3861: "Scalar": Bezeichner wurde nicht gefunden.
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(90): error C2065: 'point': nichtdeklarierter Bezeichner
    k:\projekte\c++\puzzle solver\puzzle solver\find contur.cpp(90): error C3861: "Scalar": Bezeichner wurde nicht gefunden.
    ========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========

    Ich benutze Visual Studio 2010 Express, liegt es vlt daran ?


  • Mod

    Tom1994 schrieb:

    Ich benutze Visual Studio 2010 Express, liegt es vlt daran ?

    Ja, VS2010 kann meines Wissens nach noch keine Lambdas. Du musst entweder einen Compiler mit besserer C++11-Unterstützung benutzen oder den Code auf C++98 umschreiben. VS 2010 kann allgemein so einiges aus C++11 nicht, der Code benutzt aber jede Menge. Wahrscheinlich bekommst du noch mehr Probleme, aber ich habe gerade keine Lust, jede Zeile durchzugehen und die benutzten Features mit den von VS 2010 unterstützten Features zu vergleichen.



  • Ne, daran liegts nicht. VS2010 kann Lambdas, allerdings stellt es sich was dämlich mit using namespace davor an. Hier eine Version, die fehlerfrei kompilieren sollte:

    #include "opencv2/opencv.hpp"
    #include <algorithm>
    
    typedef std::vector<cv::Point> Contour;
    typedef std::vector<cv::Point> Corners;
    
    // Distance between two points.
    float Dist(const cv::Point& p1, const cv::Point& p2)
    {
        float dx(static_cast<float>(p1.x-p2.x));
        float dy(static_cast<float>(p1.y-p2.y));
        return sqrt(dx * dx + dy * dy);
    }
    
    // Find possible corners.
    Corners ContourCorners(const Contour& contour)
    {
        using namespace cv;
        using namespace std;
        Corners result;
        auto rRect(minAreaRect(contour));
        Point2f rectCorners[4];
        rRect.points(rectCorners);
        for_each(begin(rectCorners), end(rectCorners), [&](const Point& rectCorner)
        {
            result.push_back(
                *std::min_element(begin(contour), end(contour),
                    [&rectCorner](const cv::Point& lhs, const cv::Point& rhs)
                {
                    return Dist(lhs, rectCorner) < Dist(rhs, rectCorner);
                })
            );
        });
        return result;
    }
    
    // Draw rotated rectangle.
    void DrawRotatedRect(cv::Mat& image, const cv::RotatedRect& rRect, const cv::Scalar& col)
    {
        using namespace cv;
        using namespace std;
        Point2f vertices[4];
        rRect.points(vertices);
        for (int i = 0; i < 4; i++)
            line(image, vertices[i], vertices[(i+1)%4], col);
    }
    
    int main()
    {
        using namespace cv;
        using namespace std;
    
        // Load image.
        string imageFileName("ten_small.jpg");
        Mat rgbImage(imread(imageFileName));
    
        // No image data?
        if(!rgbImage.data)
        {
            cout << "Unable to load: " << imageFileName << "\n";
            return -1;
        }
    
        // Convert to HSV.
        Mat hsvImage;
        cvtColor(rgbImage, hsvImage, CV_BGR2HSV);
    
        // Threshold and blur.
        Mat mask;
        inRange(hsvImage, Scalar(0, 0, 93), Scalar(255, 62, 255), mask);
        blur(mask, mask, Size(5,5));
    
        // Find the contours.
        vector<Contour> contours;
        {
            // cv::findContours destroys the original image, so we need a copy.
            Mat findImage(mask.clone());
            findContours(findImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
        }
    
        // Draw contours, minAreaRects and possible corners.
        Mat drawImage(mask.size(), CV_8UC3, Scalar(0, 0, 0));
        for_each(begin(contours), end(contours), [&](const Contour& contour)
        {
            drawContours(drawImage, std::vector<Contour>(1, contour), 0, cv::Scalar(255, 0, 0), 2);
            DrawRotatedRect(drawImage, minAreaRect(contour), cv::Scalar(0, 0, 255));
    
            // Find Corners.
            auto corners(ContourCorners(contour));
            std::for_each(begin(corners), end(corners), [&](const cv::Point& point) 
            {
                circle(drawImage, point, 4, cv::Scalar(0, 255, 0), 2);
            });
        });
    
        // Save result.
        imwrite("output_corners.jpg", drawImage);
    }
    


  • Danke dir,

    nun bekomme ich aber folgenden Fehler in der Zeile:

    circle(drawImage, point, 4, cv::Scalar(0, 255, 0), 2);

    "Ungültiger Verweis auf eine lokale Variable eines äußeren Gültigkeitsbereichs in einem Lambda-Text."



  • Mhh, das ist seltsam, denn bei mir compiliert der code fehlerfrei mit VC2010 express. Den Fehler von dir bekomme ich nur vom dusseligen Intellisense angezeigt, aber das ist ja kein Drama: http://i47.tinypic.com/1110d5k.png

    Aber na gut, hier eine Version, bei der auch nix mehr rot unterstrichen wird. Das mit dem innerDrawImage funktioniert, weil cv::Mat reference counted ist und der Bildspeicher nur neu angelegt und kopiert wird wenn man explizit .clone() sagt.

    #include "opencv2/opencv.hpp"
    #include <algorithm>
    
    typedef std::vector<cv::Point> Contour;
    typedef std::vector<cv::Point> Corners;
    
    // Distance between two points.
    float Dist(const cv::Point& p1, const cv::Point& p2)
    {
        float dx(static_cast<float>(p1.x-p2.x));
        float dy(static_cast<float>(p1.y-p2.y));
        return sqrt(dx * dx + dy * dy);
    }
    
    // Find possible corners.
    Corners ContourCorners(const Contour& contour)
    {
        using namespace cv;
        using namespace std;
        Corners result;
        auto rRect(minAreaRect(contour));
        Point2f rectCorners[4];
        rRect.points(rectCorners);
        for_each(begin(rectCorners), end(rectCorners), [&](const Point& rectCorner)
        {
            result.push_back(
                *std::min_element(begin(contour), end(contour),
                    [&rectCorner](const cv::Point& lhs, const cv::Point& rhs)
                {
                    return Dist(lhs, rectCorner) < Dist(rhs, rectCorner);
                })
            );
        });
        return result;
    }
    
    // Draw rotated rectangle.
    void DrawRotatedRect(cv::Mat& image, const cv::RotatedRect& rRect, const cv::Scalar& col)
    {
        using namespace cv;
        using namespace std;
        Point2f vertices[4];
        rRect.points(vertices);
        for (int i = 0; i < 4; i++)
            line(image, vertices[i], vertices[(i+1)%4], col);
    }
    
    int main()
    {
        using namespace cv;
        using namespace std;
    
        // Load image.
        string imageFileName("ten_small.jpg");
        Mat rgbImage(imread(imageFileName));
    
        // No image data?
        if(!rgbImage.data)
        {
            cout << "Unable to load: " << imageFileName << "\n";
            return -1;
        }
    
        // Convert to HSV.
        Mat hsvImage;
        cvtColor(rgbImage, hsvImage, CV_BGR2HSV);
    
        // Threshold and blur.
        Mat mask;
        inRange(hsvImage, Scalar(0, 0, 93), Scalar(255, 62, 255), mask);
        blur(mask, mask, Size(5,5));
    
        // Find the contours.
        vector<Contour> contours;
        {
            // cv::findContours destroys the original image, so we need a copy.
            Mat findImage(mask.clone());
            findContours(findImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);  
        }
    
        // Draw contours, minAreaRects and possible corners.
        Mat drawImage(mask.size(), CV_8UC3, Scalar(0, 0, 0));
        for_each(begin(contours), end(contours), [&](const Contour& contour)
        {
            drawContours(drawImage, std::vector<Contour>(1, contour), 0, cv::Scalar(255, 0, 0), 2);
            DrawRotatedRect(drawImage, minAreaRect(contour), cv::Scalar(0, 0, 255));
    
            // Find Corners.
            auto corners(ContourCorners(contour));
            cv::Mat innerDrawImage(drawImage); // (Lol, Billy!)
            std::for_each(begin(corners), end(corners), [&](const cv::Point& point)
            {
                circle(innerDrawImage, point, 4, cv::Scalar(0, 255, 0), 2);
            });
        });
    
        // Save result.
        imwrite("output_corners.jpg", drawImage);
    }
    


  • Danke!


Anmelden zum Antworten