• 根据轮廓创建旋转框和椭圆


    1.目标

    在这篇文章中,我们将学习

    • 使用OpenCV的cv::minAreaRect函数
    • 使用OpenCV的cv::fitEllipse函数

    2.主要函数讲解

    2.1 cv::minAreaRect

    C++:
    RotatedRect cv::minAreaRect(InputArray points)
    Python:
    cv.minAreaRect(points[, ])-> retval
    
    • 1
    • 2
    • 3
    • 4
    参数
    points:2D点集,存储在std::vector<>或Mat中
    
    • 1
    • 2

    查找包含输入2D点集的最小面积的旋转矩形。
    该函数计算并返回指定点集的最小面积边界矩形(可能经过旋转)。

    2.2 cv::fitEllipse

    C++
    RotatedRect cv::fitEllipse(InputArray points	)
    Python:
    cv.fitEllipse(points[, ]) ->	retval
    
    • 1
    • 2
    • 3
    • 4

    拟合一组二维点的椭圆。
    该函数计算最适合(在最小二乘意义上)一组2D点的椭圆。它返回内接椭圆的旋转矩形。

    3.代码案例

    3.1 Python代码

    import cv2 as cv
    import numpy as np
    import argparse
    import random as rng
    
    rng.seed(12345)
    
    
    def thresh_callback(val):
        global src_gray
        threshold = val
        src_gray = cv.GaussianBlur(src_gray, (3, 3), 0.1)
        canny_output = cv.Canny(src_gray, threshold, threshold * 2)
    
        contours, _ = cv.findContours(canny_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    
        # Find the rotated rectangles and ellipses for each contour
        minRect = [None] * len(contours)
        minEllipse = [None] * len(contours)
        for i, c in enumerate(contours):
            minRect[i] = cv.minAreaRect(c)
            if c.shape[0] > 5:
                minEllipse[i] = cv.fitEllipse(c)
        # Draw contours + rotated rects + ellipses
    
        drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
    
        for i, c in enumerate(contours):
            color = (rng.randint(0, 256), rng.randint(0, 256), rng.randint(0, 256))
            # contour
            cv.drawContours(drawing, contours, i, color)
            # ellipse
            if c.shape[0] > 5:
                cv.ellipse(drawing, minEllipse[i], color, 2)
            # rotated rectangle
            box = cv.boxPoints(minEllipse[i])
            # box = cv.boxPoints(minRect[i])
            box = np.intp(box)  # np.intp: Integer used for indexing (same as C ssize_t; normally either int32 or int64)
            # box = np.int0(box)  # normally either int32 or int64)
            cv.drawContours(drawing, [box], 0, color)
    
    
        cv.imshow('Contours', drawing)
    
    
    parser = argparse.ArgumentParser(
        description='Code for Creating Bounding rotated boxes and ellipses for contours tutorial.')
    parser.add_argument('--input', help='Path to input image.', default='balloon1.png')
    args = parser.parse_args()
    src = cv.imread(cv.samples.findFile(args.input))
    if src is None:
        print('Could not open or find the image:', args.input)
        exit(0)
    # Convert image to gray and blur it
    src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
    src_gray = cv.blur(src_gray, (3, 3))
    source_window = 'Source'
    cv.namedWindow(source_window)
    cv.imshow(source_window, src)
    max_thresh = 255
    thresh = 100  # initial threshold
    cv.createTrackbar('Canny Thresh:', source_window, thresh, max_thresh, thresh_callback)
    thresh_callback(thresh)
    cv.waitKey()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    3.2 C++代码

    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgproc.hpp"
    #include 
    using namespace cv;
    using namespace std;
    Mat src_gray;
    int thresh = 100;
    RNG rng(12345);
    void thresh_callback(int, void* );
    int main( int argc, char** argv )
    {
        CommandLineParser parser( argc, argv, "{@input | stuff.jpg | input image}" );
        Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
        if( src.empty() )
        {
            cout << "Could not open or find the image!\n" << endl;
            cout << "Usage: " << argv[0] << " " << endl;
            return -1;
        }
        cvtColor( src, src_gray, COLOR_BGR2GRAY );
        blur( src_gray, src_gray, Size(3,3) );
        const char* source_window = "Source";
        namedWindow( source_window );
        imshow( source_window, src );
        const int max_thresh = 255;
        createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
        thresh_callback( 0, 0 );
        waitKey();
        return 0;
    }
    void thresh_callback(int, void* )
    {
        Mat canny_output;
        Canny( src_gray, canny_output, thresh, thresh*2 );
        vector<vector<Point> > contours;
        findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
        vector<RotatedRect> minRect( contours.size() );
        vector<RotatedRect> minEllipse( contours.size() );
        for( size_t i = 0; i < contours.size(); i++ )
        {
            minRect[i] = minAreaRect( contours[i] );
            if( contours[i].size() > 5 )
            {
                minEllipse[i] = fitEllipse( contours[i] );
            }
        }
        Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
        for( size_t i = 0; i< contours.size(); i++ )
        {
            Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
            // contour
            drawContours( drawing, contours, (int)i, color );
            // ellipse
            ellipse( drawing, minEllipse[i], color, 2 );
            // rotated rectangle
            Point2f rect_points[4];
            minRect[i].points( rect_points );
            for ( int j = 0; j < 4; j++ )
            {
                line( drawing, rect_points[j], rect_points[(j+1)%4], color );
            }
        }
        imshow( "Contours", drawing );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    在这里插入图片描述

    参考目录

    https://docs.opencv.org/5.x/de/d62/tutorial_bounding_rotated_ellipses.html

  • 相关阅读:
    PyTorch实现苹果M1芯片GPU加速:训练速度提升7倍,性能最高提升21倍
    FFmpeg —— 录制windows系统声音(附源码)
    深度学习【PyTorch中序列化容器、QA机器人、环境准备】
    (一)JPA的快速入门
    HX3001升压IC芯片-Synchronous Boost DC/DC Regulator
    知识图谱 | DDoS攻击恶意行为知识库构建
    springboot基础(69):Controller相关注解
    【性能测试】Jenkins+Ant+Jmeter自动化框架的搭建思路
    【艾特淘】8月22日之后,抖音精选联盟准入标准变了
    小程序蓝牙连接ESP32通信(可直接拿来用)
  • 原文地址:https://blog.csdn.net/weixin_43229348/article/details/126029651