diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 04ed254f28..310d4bc05b 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -4173,8 +4173,6 @@ The function finds the minimal enclosing circle of a 2D point set using an itera CV_EXPORTS_W void minEnclosingCircle( InputArray points, CV_OUT Point2f& center, CV_OUT float& radius ); -/** @example samples/cpp/minarea.cpp -*/ /** @brief Finds a triangle of minimum area enclosing a 2D point set and returns its area. @@ -4209,8 +4207,8 @@ The function compares two shapes. All three implemented methods use the Hu invar CV_EXPORTS_W double matchShapes( InputArray contour1, InputArray contour2, int method, double parameter ); -/** @example samples/cpp/convexhull.cpp -An example using the convexHull functionality +/** @example samples/cpp/geometry.cpp +An example program illustrates the use of cv::convexHull, cv::fitEllipse, cv::minEnclosingTriangle, cv::minEnclosingCircle and cv::minAreaRect. */ /** @brief Finds the convex hull of a point set. @@ -4291,9 +4289,6 @@ of the other, they are not considered nested and an intersection will be found r CV_EXPORTS_W float intersectConvexConvex( InputArray p1, InputArray p2, OutputArray p12, bool handleNested = true ); -/** @example samples/cpp/fitellipse.cpp -An example using the fitEllipse technique -*/ /** @brief Fits an ellipse around a set of 2D points. @@ -4750,10 +4745,6 @@ CV_EXPORTS void polylines(InputOutputArray img, const Point* const* pts, const i int ncontours, bool isClosed, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0 ); -/** @example samples/cpp/contours2.cpp -An example program illustrates the use of cv::findContours and cv::drawContours -\image html WindowsQtContoursOutput.png "Screenshot of the program" -*/ /** @example samples/cpp/segment_objects.cpp An example using drawContours to clean up a background segmentation result diff --git a/samples/cpp/contours2.cpp b/samples/cpp/contours2.cpp deleted file mode 100644 index c3653fb5d6..0000000000 --- a/samples/cpp/contours2.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "opencv2/imgproc.hpp" -#include "opencv2/highgui.hpp" -#include -#include - -using namespace cv; -using namespace std; - -static void help(char** argv) -{ - cout - << "\nThis program illustrates the use of findContours and drawContours\n" - << "The original image is put up along with the image of drawn contours\n" - << "Usage:\n"; - cout - << argv[0] - << "\nA trackbar is put up which controls the contour level from -3 to 3\n" - << endl; -} - -const int w = 500; -int levels = 3; - -vector > contours; -vector hierarchy; - -static void on_trackbar(int, void*) -{ - Mat cnt_img = Mat::zeros(w, w, CV_8UC3); - int _levels = levels - 3; - drawContours( cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128,255,255), - 3, LINE_AA, hierarchy, std::abs(_levels) ); - - imshow("contours", cnt_img); -} - -int main( int argc, char** argv) -{ - cv::CommandLineParser parser(argc, argv, "{help h||}"); - if (parser.has("help")) - { - help(argv); - return 0; - } - Mat img = Mat::zeros(w, w, CV_8UC1); - //Draw 6 faces - for( int i = 0; i < 6; i++ ) - { - int dx = (i%2)*250 - 30; - int dy = (i/2)*150; - const Scalar white = Scalar(255); - const Scalar black = Scalar(0); - - if( i == 0 ) - { - for( int j = 0; j <= 10; j++ ) - { - double angle = (j+5)*CV_PI/21; - line(img, Point(cvRound(dx+100+j*10-80*cos(angle)), - cvRound(dy+100-90*sin(angle))), - Point(cvRound(dx+100+j*10-30*cos(angle)), - cvRound(dy+100-30*sin(angle))), white, 1, 8, 0); - } - } - - ellipse( img, Point(dx+150, dy+100), Size(100,70), 0, 0, 360, white, -1, 8, 0 ); - ellipse( img, Point(dx+115, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 ); - ellipse( img, Point(dx+185, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 ); - ellipse( img, Point(dx+115, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 ); - ellipse( img, Point(dx+185, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 ); - ellipse( img, Point(dx+115, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 ); - ellipse( img, Point(dx+185, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 ); - ellipse( img, Point(dx+150, dy+100), Size(10,5), 0, 0, 360, black, -1, 8, 0 ); - ellipse( img, Point(dx+150, dy+150), Size(40,10), 0, 0, 360, black, -1, 8, 0 ); - ellipse( img, Point(dx+27, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 ); - ellipse( img, Point(dx+273, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 ); - } - //show the faces - namedWindow( "image", 1 ); - imshow( "image", img ); - //Extract the contours so that - vector > contours0; - findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); - - contours.resize(contours0.size()); - for( size_t k = 0; k < contours0.size(); k++ ) - approxPolyDP(Mat(contours0[k]), contours[k], 3, true); - - namedWindow( "contours", 1 ); - createTrackbar( "levels+3", "contours", &levels, 7, on_trackbar ); - - on_trackbar(0,0); - waitKey(); - - return 0; -} diff --git a/samples/cpp/convexhull.cpp b/samples/cpp/convexhull.cpp deleted file mode 100644 index d839b8061f..0000000000 --- a/samples/cpp/convexhull.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "opencv2/imgproc.hpp" -#include "opencv2/highgui.hpp" -#include - -using namespace cv; -using namespace std; - -static void help(char** argv) -{ - cout << "\nThis sample program demonstrates the use of the convexHull() function\n" - << "Call:\n" - << argv[0] << endl; -} - -int main( int argc, char** argv ) -{ - CommandLineParser parser(argc, argv, "{help h||}"); - if (parser.has("help")) - { - help(argv); - return 0; - } - Mat img(500, 500, CV_8UC3); - RNG& rng = theRNG(); - - for(;;) - { - int i, count = (unsigned)rng%100 + 1; - - vector points; - - for( i = 0; i < count; i++ ) - { - Point pt; - pt.x = rng.uniform(img.cols/4, img.cols*3/4); - pt.y = rng.uniform(img.rows/4, img.rows*3/4); - - points.push_back(pt); - } - - vector hull; - convexHull(points, hull, true); - - img = Scalar::all(0); - for( i = 0; i < count; i++ ) - circle(img, points[i], 3, Scalar(0, 0, 255), FILLED, LINE_AA); - - polylines(img, hull, true, Scalar(0, 255, 0), 1, LINE_AA); - imshow("hull", img); - - char key = (char)waitKey(); - if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC' - break; - } - - return 0; -} diff --git a/samples/cpp/fitellipse.cpp b/samples/cpp/fitellipse.cpp deleted file mode 100644 index 7d217014d5..0000000000 --- a/samples/cpp/fitellipse.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/******************************************************************************** - * - * - * This program is demonstration for ellipse fitting. Program finds - * contours and approximate it by ellipses using three methods. - * 1: OpenCV's original method fitEllipse which implements Fitzgibbon 1995 method. - * 2: The Approximate Mean Square (AMS) method fitEllipseAMS proposed by Taubin 1991 - * 3: The Direct least square (Direct) method fitEllipseDirect proposed by Fitzgibbon1999. - * - * Trackbar specify threshold parameter. - * - * White lines is contours/input points and the true ellipse used to generate the data. - * 1: Blue lines is fitting ellipses using openCV's original method. - * 2: Green lines is fitting ellipses using the AMS method. - * 3: Red lines is fitting ellipses using the Direct method. - * - * - * Original Author: Denis Burenkov - * AMS and Direct Methods Author: Jasper Shemilt - * - * - ********************************************************************************/ -#include "opencv2/imgproc.hpp" -#include "opencv2/imgcodecs.hpp" -#include "opencv2/highgui.hpp" -#include - -using namespace cv; -using namespace std; - -class canvas{ -public: - bool setupQ; - cv::Point origin; - cv::Point corner; - int minDims,maxDims; - double scale; - int rows, cols; - cv::Mat img; - - void init(int minD, int maxD){ - // Initialise the canvas with minimum and maximum rows and column sizes. - minDims = minD; maxDims = maxD; - origin = cv::Point(0,0); - corner = cv::Point(0,0); - scale = 1.0; - rows = 0; - cols = 0; - setupQ = false; - } - - void stretch(cv::Point2f min, cv::Point2f max){ - // Stretch the canvas to include the points min and max. - if(setupQ){ - if(corner.x < max.x){corner.x = (int)(max.x + 1.0);}; - if(corner.y < max.y){corner.y = (int)(max.y + 1.0);}; - if(origin.x > min.x){origin.x = (int) min.x;}; - if(origin.y > min.y){origin.y = (int) min.y;}; - } else { - origin = cv::Point((int)min.x, (int)min.y); - corner = cv::Point((int)(max.x + 1.0), (int)(max.y + 1.0)); - } - - int c = (int)(scale*((corner.x + 1.0) - origin.x)); - if(cmaxDims){ - scale = scale * (double)maxDims/(double)c; - } - } - int r = (int)(scale*((corner.y + 1.0) - origin.y)); - if(rmaxDims){ - scale = scale * (double)maxDims/(double)r; - } - } - cols = (int)(scale*((corner.x + 1.0) - origin.x)); - rows = (int)(scale*((corner.y + 1.0) - origin.y)); - setupQ = true; - } - - void stretch(vector pts) - { // Stretch the canvas so all the points pts are on the canvas. - cv::Point2f min = pts[0]; - cv::Point2f max = pts[0]; - for(size_t i=1; i < pts.size(); i++){ - Point2f pnt = pts[i]; - if(max.x < pnt.x){max.x = pnt.x;}; - if(max.y < pnt.y){max.y = pnt.y;}; - if(min.x > pnt.x){min.x = pnt.x;}; - if(min.y > pnt.y){min.y = pnt.y;}; - }; - stretch(min, max); - } - - void stretch(cv::RotatedRect box) - { // Stretch the canvas so that the rectangle box is on the canvas. - cv::Point2f min = box.center; - cv::Point2f max = box.center; - cv::Point2f vtx[4]; - box.points(vtx); - for( int i = 0; i < 4; i++ ){ - cv::Point2f pnt = vtx[i]; - if(max.x < pnt.x){max.x = pnt.x;}; - if(max.y < pnt.y){max.y = pnt.y;}; - if(min.x > pnt.x){min.x = pnt.x;}; - if(min.y > pnt.y){min.y = pnt.y;}; - } - stretch(min, max); - } - - void drawEllipseWithBox(cv::RotatedRect box, cv::Scalar color, int lineThickness) - { - if(img.empty()){ - stretch(box); - img = cv::Mat::zeros(rows,cols,CV_8UC3); - } - - box.center = scale * cv::Point2f(box.center.x - origin.x, box.center.y - origin.y); - box.size.width = (float)(scale * box.size.width); - box.size.height = (float)(scale * box.size.height); - - ellipse(img, box, color, lineThickness, LINE_AA); - - Point2f vtx[4]; - box.points(vtx); - for( int j = 0; j < 4; j++ ){ - line(img, vtx[j], vtx[(j+1)%4], color, lineThickness, LINE_AA); - } - } - - void drawPoints(vector pts, cv::Scalar color) - { - if(img.empty()){ - stretch(pts); - img = cv::Mat::zeros(rows,cols,CV_8UC3); - } - for(size_t i=0; i < pts.size(); i++){ - Point2f pnt = scale * cv::Point2f(pts[i].x - origin.x, pts[i].y - origin.y); - img.at(int(pnt.y), int(pnt.x))[0] = (uchar)color[0]; - img.at(int(pnt.y), int(pnt.x))[1] = (uchar)color[1]; - img.at(int(pnt.y), int(pnt.x))[2] = (uchar)color[2]; - }; - } - - void drawLabels( std::vector text, std::vector colors) - { - if(img.empty()){ - img = cv::Mat::zeros(rows,cols,CV_8UC3); - } - int vPos = 0; - for (size_t i=0; i < text.size(); i++) { - cv::Scalar color = colors[i]; - std::string txt = text[i]; - Size textsize = getTextSize(txt, FONT_HERSHEY_COMPLEX, 1, 1, 0); - vPos += (int)(1.3 * textsize.height); - Point org((img.cols - textsize.width), vPos); - cv::putText(img, txt, org, FONT_HERSHEY_COMPLEX, 1, color, 1, LINE_8); - } - } - -}; - -static void help(char** argv) -{ - cout << "\nThis program is demonstration for ellipse fitting. The program finds\n" - "contours and approximate it by ellipses. Three methods are used to find the \n" - "elliptical fits: fitEllipse, fitEllipseAMS and fitEllipseDirect.\n" - "Call:\n" - << argv[0] << " [image_name -- Default ellipses.jpg]\n" << endl; -} - -int sliderPos = 70; - -Mat image; - -bool fitEllipseQ, fitEllipseAMSQ, fitEllipseDirectQ; -cv::Scalar fitEllipseColor = Scalar(255, 0, 0); -cv::Scalar fitEllipseAMSColor = Scalar( 0,255, 0); -cv::Scalar fitEllipseDirectColor = Scalar( 0, 0,255); -cv::Scalar fitEllipseTrueColor = Scalar(255,255,255); - -void processImage(int, void*); - -int main( int argc, char** argv ) -{ - fitEllipseQ = true; - fitEllipseAMSQ = true; - fitEllipseDirectQ = true; - - cv::CommandLineParser parser(argc, argv,"{help h||}{@image|ellipses.jpg|}"); - if (parser.has("help")) - { - help(argv); - return 0; - } - string filename = parser.get("@image"); - image = imread(samples::findFile(filename), 0); - if( image.empty() ) - { - cout << "Couldn't open image " << filename << "\n"; - return 0; - } - - imshow("source", image); - namedWindow("result", WINDOW_NORMAL ); - - // Create toolbars. HighGUI use. - createTrackbar( "threshold", "result", &sliderPos, 255, processImage ); - - processImage(0, 0); - - // Wait for a key stroke; the same function arranges events processing - waitKey(); - return 0; -} - -inline static bool isGoodBox(const RotatedRect& box) { - //size.height >= size.width awalys,only if the pts are on a line or at the same point,size.width=0 - return (box.size.height <= box.size.width * 30) && (box.size.width > 0); -} - -// Define trackbar callback function. This function finds contours, -// draws them, and approximates by ellipses. -void processImage(int /*h*/, void*) -{ - RotatedRect box, boxAMS, boxDirect; - vector > contours; - Mat bimage = image >= sliderPos; - - findContours(bimage, contours, RETR_LIST, CHAIN_APPROX_NONE); - - canvas paper; - paper.init(int(0.8*MIN(bimage.rows, bimage.cols)), int(1.2*MAX(bimage.rows, bimage.cols))); - paper.stretch(cv::Point2f(0.0f, 0.0f), cv::Point2f((float)(bimage.cols+2.0), (float)(bimage.rows+2.0))); - - std::vector text; - std::vector color; - - if (fitEllipseQ) { - text.push_back("OpenCV"); - color.push_back(fitEllipseColor); - } - if (fitEllipseAMSQ) { - text.push_back("AMS"); - color.push_back(fitEllipseAMSColor); - } - if (fitEllipseDirectQ) { - text.push_back("Direct"); - color.push_back(fitEllipseDirectColor); - } - paper.drawLabels(text, color); - - int margin = 2; - vector< vector > points; - for(size_t i = 0; i < contours.size(); i++) - { - size_t count = contours[i].size(); - if( count < 6 ) - continue; - - Mat pointsf; - Mat(contours[i]).convertTo(pointsf, CV_32F); - - vectorpts; - for (int j = 0; j < pointsf.rows; j++) { - Point2f pnt = Point2f(pointsf.at(j,0), pointsf.at(j,1)); - if ((pnt.x > margin && pnt.y > margin && pnt.x < bimage.cols-margin && pnt.y < bimage.rows-margin)) { - if(j%20==0){ - pts.push_back(pnt); - } - } - } - points.push_back(pts); - } - - for(size_t i = 0; i < points.size(); i++) - { - vector pts = points[i]; - - //At least 5 points can fit an ellipse - if (pts.size()<5) { - continue; - } - if (fitEllipseQ) { - box = fitEllipse(pts); - if (isGoodBox(box)) { - paper.drawEllipseWithBox(box, fitEllipseColor, 3); - } - } - if (fitEllipseAMSQ) { - boxAMS = fitEllipseAMS(pts); - if (isGoodBox(boxAMS)) { - paper.drawEllipseWithBox(boxAMS, fitEllipseAMSColor, 2); - } - } - if (fitEllipseDirectQ) { - boxDirect = fitEllipseDirect(pts); - if (isGoodBox(boxDirect)){ - paper.drawEllipseWithBox(boxDirect, fitEllipseDirectColor, 1); - } - } - - paper.drawPoints(pts, fitEllipseTrueColor); - } - - imshow("result", paper.img); -} diff --git a/samples/cpp/geometry.cpp b/samples/cpp/geometry.cpp new file mode 100644 index 0000000000..f88893c9e4 --- /dev/null +++ b/samples/cpp/geometry.cpp @@ -0,0 +1,268 @@ +/******************************************************************************* + * + * This program demonstrates various shape fitting techniques using OpenCV. + * It reads an image, applies binary thresholding, and then detects contours. + * + * For each contour, it fits and draws several geometric shapes including + * convex hulls, minimum enclosing circles, rectangles, triangles, and ellipses + * using different fitting methods: + * 1: OpenCV's original method fitEllipse which implements Fitzgibbon 1995 method. + * 2: The Approximate Mean Square (AMS) method fitEllipseAMS proposed by Taubin 1991 + * 3: The Direct least square (Direct) method fitEllipseDirect proposed by Fitzgibbon1999 + * + * The results are displayed with unique colors + * for each shape and fitting method for clear differentiation. + * + * + *********************************************************************************/ + +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include +#include + +using namespace cv; +using namespace std; + +const string hot_keys = + "\n\nHot keys: \n" + "\tESC - quit the program\n" + "\tq - quit the program\n" + "\tc - make the circle\n" + "\tr - make the rectangle\n" + "\th - make the convexhull\n" + "\tt - make the triangle\n" + "\te - make the ellipse\n" + "\ta - make all shapes\n" + "\t0 - use OpenCV's method for ellipse fitting\n" + "\t1 - use Approximate Mean Square (AMS) method for ellipse fitting \n" + "\t2 - use Direct least square (Direct) method for ellipse fitting\n"; + +static void help(char** argv) +{ + cout << "\nThis program demonstrates various shape fitting techniques on a set of points using functions: \n" + << "minAreaRect(), minEnclosingTriangle(), minEnclosingCircle(), convexHull(), and ellipse().\n\n" + << "Usage: " << argv[0] << " [--image_name= Default: ellipses.jpg]\n\n"; + cout << hot_keys << endl; +} + +void processImage(int, void*); +void drawShapes(Mat &img, const vector &points, int ellipseMethod, string shape); +void drawConvexHull(Mat &img, const vector &points); +void drawMinAreaRect(Mat &img, const vector &points); +void drawFittedEllipses(Mat &img, const vector &points, int ellipseMethod); +void drawMinEnclosingCircle(Mat &img, const vector &points); +void drawMinEnclosingTriangle(Mat &img, const vector &points); + +// Shape fitting options +Mat image; +enum EllipseFittingMethod { + OpenCV_Method, + AMS_Method, + Direct_Method +}; + +struct UserData { + int sliderPos = 70; + string shape = "--all"; + int ellipseMethod = OpenCV_Method; +}; + +const char* keys = + "{help h | | Show help message }" + "{@image |ellipses.jpg| Path to input image file }"; + +int main(int argc, char** argv) { + + cv::CommandLineParser parser(argc, argv, keys); + help(argv); + + if (parser.has("help")) + { + return 0; + } + + UserData userData; // variable to pass all the necessary values to trackbar callback + + string filename = parser.get("@image"); + image = imread(samples::findFile(filename), IMREAD_COLOR); // Read the image from the specified path + + if (image.empty()) { + cout << "Could not open or find the image" << endl; + return -1; + } + + namedWindow("Shapes", WINDOW_AUTOSIZE); // Create a window to display the results + createTrackbar("Threshold", "Shapes", NULL, 255, processImage, &userData); // Create a threshold trackbar + setTrackbarPos("Threshold", "Shapes", userData.sliderPos); + + for(;;) { + char key = (char)waitKey(0); // Listen for a key press + if (key == 'q' || key == 27) break; // Exit the loop if 'q' or ESC is pressed + + switch (key) { + case 'h': userData.shape = "--convexhull"; break; + case 'a': userData.shape = "--all"; break; + case 't': userData.shape = "--triangle"; break; + case 'c': userData.shape = "--circle"; break; + case 'e': userData.shape = "--ellipse"; break; + case 'r': userData.shape = "--rectangle"; break; + case '0': userData.ellipseMethod = OpenCV_Method; break; + case '1': userData.ellipseMethod = AMS_Method; break; + case '2': userData.ellipseMethod = Direct_Method; break; + default: break; // Do nothing for other keys + } + + processImage(userData.sliderPos, &userData); // Process the image with the current settings + } + + return 0; +} + +// Function to draw the minimum enclosing circle around given points +void drawMinEnclosingCircle(Mat &img, const vector &points) { + Point2f center; + float radius = 0; + minEnclosingCircle(points, center, radius); // Find the enclosing circle + // Draw the circle + circle(img, center, cvRound(radius), Scalar(0, 0, 255), 2, LINE_AA); +} + +// Function to draw the minimum enclosing triangle around given points +void drawMinEnclosingTriangle(Mat &img, const vector &points) { + vector triangle; + minEnclosingTriangle(points, triangle); // Find the enclosing triangle + + if (triangle.size() != 3) { + return; + } + // Use polylines to draw the triangle. The 'true' argument closes the triangle. + polylines(img, triangle, true, Scalar(255, 0, 0), 2, LINE_AA); + +} + +// Function to draw the minimum area rectangle around given points +void drawMinAreaRect(Mat &img, const vector &points) { + RotatedRect box = minAreaRect(points); // Find the minimum area rectangle + Point2f vtx[4]; + box.points(vtx); + // Convert Point2f to Point because polylines expects a vector of Point + vector rectPoints; + for (int i = 0; i < 4; i++) { + rectPoints.push_back(Point(cvRound(vtx[i].x), cvRound(vtx[i].y))); + } + + // Use polylines to draw the rectangle. The 'true' argument closes the loop, drawing a rectangle. + polylines(img, rectPoints, true, Scalar(0, 255, 0), 2, LINE_AA); +} + +// Function to draw the convex hull of given points +void drawConvexHull(Mat &img, const vector &points) { + vector hull; + convexHull(points, hull, false); // Find the convex hull + // Draw the convex hull + polylines(img, hull, true, Scalar(255, 255, 0), 2, LINE_AA); +} + +inline static bool isGoodBox(const RotatedRect& box) { + //size.height >= size.width awalys,only if the pts are on a line or at the same point,size.width=0 + return (box.size.height <= box.size.width * 30) && (box.size.width > 0); +} + +// Function to draw fitted ellipses using different methods +void drawFittedEllipses(Mat &img, const vector &points, int ellipseMethod) { + switch (ellipseMethod) { + case OpenCV_Method: // Standard ellipse fitting + { + RotatedRect fittedEllipse = fitEllipse(points); + if (isGoodBox(fittedEllipse)) { + ellipse(img, fittedEllipse, Scalar(255, 0, 255), 2, LINE_AA); + } + putText(img, "OpenCV", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA); + } + break; + case AMS_Method: // AMS ellipse fitting + { + RotatedRect fittedEllipseAMS = fitEllipseAMS(points); + if (isGoodBox(fittedEllipseAMS)) { + ellipse(img, fittedEllipseAMS, Scalar(255, 0, 255), 2, LINE_AA); + } + putText(img, "AMS", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA); + } + break; + case Direct_Method: // Direct ellipse fitting + { + RotatedRect fittedEllipseDirect = fitEllipseDirect(points); + if (isGoodBox(fittedEllipseDirect)) { + ellipse(img, fittedEllipseDirect, Scalar(255, 0, 255), 2, LINE_AA); + } + putText(img, "Direct", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA); + } + break; + default: // Default case falls back to OpenCV method + { + RotatedRect fittedEllipse = fitEllipse(points); + if (isGoodBox(fittedEllipse)) { + ellipse(img, fittedEllipse, Scalar(255, 0, 255), 2, LINE_AA); + } + putText(img, "OpenCV (default)", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA); + cout << "Warning: Invalid ellipseMethod value. Falling back to default OpenCV method." << endl; + } + break; + } +} + +// Function to draw shapes +void drawShapes(Mat &img, const vector &points, int ellipseMethod, string shape) { + if (shape == "--circle") { + drawMinEnclosingCircle(img, points); + } else if (shape == "--triangle") { + drawMinEnclosingTriangle(img, points); + } else if (shape == "--rectangle") { + drawMinAreaRect(img, points); + } else if (shape == "--convexhull") { + drawConvexHull(img, points); + } else if (shape == "--ellipse"){ + drawFittedEllipses(img, points, ellipseMethod); + } + else if (shape == "--all") { + drawMinEnclosingCircle(img, points); + drawMinEnclosingTriangle(img, points); + drawMinAreaRect(img, points); + drawConvexHull(img, points); + drawFittedEllipses(img, points, ellipseMethod); + } +} + +// Main function to process the image based on the current trackbar position +void processImage(int position, void* userData){ + + UserData* data = static_cast(userData); + + data->sliderPos = position; + + Mat processedImg = image.clone(); // Clone the original image for processing + Mat gray; + cvtColor(processedImg, gray, COLOR_BGR2GRAY); // Convert to grayscale + threshold(gray, gray, data->sliderPos, 255, THRESH_BINARY); // Apply binary threshold + + Mat filteredImg; + medianBlur(gray, filteredImg, 3); + + vector> contours; + findContours(filteredImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); // Find contours + + if (contours.empty()) { + return; + } + + imshow("Mask", filteredImg); // Show the mask + for (size_t i = 0; i < contours.size(); ++i) { + if (contours[i].size() < 5) { // Check if the contour has enough points + continue; + } + drawShapes(processedImg, contours[i], data->ellipseMethod, data->shape); + } + + imshow("Shapes", processedImg); // Display the processed image with fitted shapes +} diff --git a/samples/cpp/minarea.cpp b/samples/cpp/minarea.cpp deleted file mode 100644 index 97264721bf..0000000000 --- a/samples/cpp/minarea.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "opencv2/highgui.hpp" -#include "opencv2/imgproc.hpp" - -#include - -using namespace cv; -using namespace std; - -static void help() -{ - cout << "This program demonstrates finding the minimum enclosing box, triangle or circle of a set\n" - << "of points using functions: minAreaRect() minEnclosingTriangle() minEnclosingCircle().\n" - << "Random points are generated and then enclosed.\n\n" - << "Press ESC, 'q' or 'Q' to exit and any other key to regenerate the set of points.\n\n"; -} - -int main( int /*argc*/, char** /*argv*/ ) -{ - help(); - - Mat img(500, 500, CV_8UC3, Scalar::all(0)); - RNG& rng = theRNG(); - - for(;;) - { - int i, count = rng.uniform(1, 101); - vector points; - - // Generate a random set of points - for( i = 0; i < count; i++ ) - { - Point pt; - pt.x = rng.uniform(img.cols/4, img.cols*3/4); - pt.y = rng.uniform(img.rows/4, img.rows*3/4); - - points.push_back(pt); - } - - // Find the minimum area enclosing bounding box - Point2f vtx[4]; - RotatedRect box = minAreaRect(points); - box.points(vtx); - - // Find the minimum area enclosing triangle - vector triangle; - minEnclosingTriangle(points, triangle); - - // Find the minimum area enclosing circle - Point2f center; - float radius = 0; - minEnclosingCircle(points, center, radius); - - img = Scalar::all(0); - - // Draw the points - for( i = 0; i < count; i++ ) - circle( img, points[i], 3, Scalar(0, 0, 255), FILLED, LINE_AA ); - - // Draw the bounding box - for( i = 0; i < 4; i++ ) - line(img, vtx[i], vtx[(i+1)%4], Scalar(0, 255, 0), 1, LINE_AA); - - // Draw the triangle - for( i = 0; i < 3; i++ ) - line(img, triangle[i], triangle[(i+1)%3], Scalar(255, 255, 0), 1, LINE_AA); - - // Draw the circle - circle(img, center, cvRound(radius), Scalar(0, 255, 255), 1, LINE_AA); - - imshow( "Rectangle, triangle & circle", img ); - - char key = (char)waitKey(); - if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC' - break; - } - - return 0; -}