OpenCV Shape Detection in C++

Overview

This C++ guide demonstrates how to detect basic shapes using OpenCV. It includes preprocessing steps, contour detection, polygon approximation, and classification of shapes such as triangles, rectangles, and circles.

1. Required Headers & Setup


#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;
    

// Make sure OpenCV is properly linked during compilation.

2. Preprocessing the Image


Mat image = imread("shapes.png");
Mat gray, blurred, edged;

cvtColor(image, gray, COLOR_BGR2GRAY);
GaussianBlur(gray, blurred, Size(5, 5), 0);
Canny(blurred, edged, 50, 150);
    

// Canny edge detection prepares the image for shape extraction.

3. Detecting and Approximating Contours


vector<vector<Point>> contours;
vector<Vec4i> hierarchy;

findContours(edged, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

for (const auto& contour : contours) {
    double epsilon = 0.02 * arcLength(contour, true);
    vector<Point> approx;
    approxPolyDP(contour, approx, epsilon, true);
    
    Rect bounding = boundingRect(approx);
    string shape;

    int vertices = approx.size();
    if (vertices == 3) {
        shape = "Triangle";
    } else if (vertices == 4) {
        float ar = (float)bounding.width / bounding.height;
        shape = (ar > 0.95 && ar < 1.05) ? "Square" : "Rectangle";
    } else if (vertices > 4) {
        shape = "Circle";
    } else {
        shape = "Unknown";
    }

    drawContours(image, vector<vector<Point>>{approx}, -1, Scalar(0, 255, 0), 2);
    putText(image, shape, Point(bounding.x, bounding.y - 10), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 2);
}
    

// Shape classification is based on the number of vertices in the approximated contour.

4. Display the Result


imshow("Detected Shapes", image);
waitKey(0);
    

// This renders the original image with outlines and labels over each detected shape.

5. Full Program


#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    Mat image = imread("shapes.png");
    if (image.empty()) {
        cout << "Could not open image" << endl;
        return -1;
    }

    Mat gray, blurred, edged;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    GaussianBlur(gray, blurred, Size(5, 5), 0);
    Canny(blurred, edged, 50, 150);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(edged, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    for (const auto& contour : contours) {
        double epsilon = 0.02 * arcLength(contour, true);
        vector<Point> approx;
        approxPolyDP(contour, approx, epsilon, true);

        Rect bounding = boundingRect(approx);
        string shape;
        int vertices = approx.size();

        if (vertices == 3) {
            shape = "Triangle";
        } else if (vertices == 4) {
            float ar = (float)bounding.width / bounding.height;
            shape = (ar > 0.95 && ar < 1.05) ? "Square" : "Rectangle";
        } else if (vertices > 4) {
            shape = "Circle";
        } else {
            shape = "Unknown";
        }

        drawContours(image, vector<vector<Point>>{approx}, -1, Scalar(0, 255, 0), 2);
        putText(image, shape, Point(bounding.x, bounding.y - 10),
                FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 2);
    }

    imshow("Detected Shapes", image);
    waitKey(0);
    return 0;
}
    

// Compile with: g++ shapes.cpp -o shapes `pkg-config --cflags --libs opencv4`