Opencv中文网

画圆circle()函数

circle() 是 OpenCV 中用于在图像上绘制圆形的基本函数。它的原型如下所示:

void circle(
    InputOutputArray img, 
    Point center, 
    int radius, 
    const Scalar& color, 
    int thickness = 1, 
    int lineType = LINE_8, 
    int shift = 0
);

其中,img表示图像,center表示圆心坐标(x,y),radius表示圆的半径(int型),Scalar表示圆的颜色(BGR格式),thickness表示线条的粗细(默认为1),如果thickness=-1表示填充整个圆,lineType表示线条类型(默认LINE_8),shift表示圆心和半径的小数位数(默认为0)。

下面利用该函数绘制奥运五环图标。

#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

int main()
{
    Mat image(300, 450, CV_8UC3, Scalar(255, 255, 255)); 
    int x = 100;
    int y = 125;
    Point center(x, y);//圆心
    int radius = 50;//半径
    Scalar color(200, 130, 0); //蓝色
    circle(image, center, radius, color, 5);//1号圆
    center.x += 120;
    color = Scalar(0,0,0);//黑色
    circle(image, center, radius, color, 5);//2号圆
    center.x += 120;
    color = Scalar(78, 52, 238);//红色
    circle(image, center, radius, color, 5);//3号圆
    center.x = x + 60;
    center.y = y + 50;
    color = Scalar(50, 177, 252);//黄色
    circle(image, center, radius, color, 5);//4号圆
    center.x += 120;
    color = Scalar(81, 167, 0);//绿色
    circle(image, center, radius, color, 5);//5号圆    
    radius = 5;
    color = Scalar(0, 0, 255);//纯红色
    center.x = image.cols / 2 - radius;
    center.y = image.rows / 2 - radius;
    circle(image, center, radius, color, -1,LINE_AA);//实心圆
    imshow("image", image);//显示图像
    imwrite("output.jpg", image);   
    waitKey(0);//等待按键
    return 0;
}

先看一下这段代码的最终效果图。

奥运5环

在图中一共有6个圆,从代码的注释中可得知,前5个圆都是空心圆,最后一个圆是实心圆,因为它的thickness参数等于-1。

第二个关键点,实心圆比较圆滑(抗锯齿),而5个空心圆有很明显的锯齿感。这是因为实心圆的lineType参数采用了LINE_AA枚举值。对于高分辨率的图像,使用LINE_AA可以获得更好的视觉效果。

如果需要绘制大量的圆,可以考虑使用UMat代替Mat,利用GPU加速;另外批量绘制时,先准备所有参数,再一次性绘制。

UMat类介绍

UMat可自动利用CPU/GPU异构计算资源(通过OpenCL加速),适合大规模图像处理。针对本例,可以将图像创建成UMat。

UMat image(300, 450, CV_8UC3, Scalar(255, 255, 255)); 

Mat和UMat转换

两者可以实现互相转换,实现方式也比较简单。如下面的代码所示。

#include <opencv2/opencv.hpp>
using namespace cv;

int main() {
    // 1. 创建UMat(默认使用OpenCL加速)
    UMat uimage1(480, 640, CV_8UC3, Scalar(0, 0, 255)); // 红色背景
    
    // 2. 从Mat转换到UMat
    Mat matImage = imread("input.jpg");
    UMat uimage2;
    matImage.copyTo(uimage2); // 显式转换
    
    // 3. UMat转回Mat
    Mat outputMat;
    uimage2.copyTo(outputMat);
    
    imshow("UMat Demo", outputMat);
    waitKey(0);
    return 0;
}

那什么时候用Mat,什么时候用UMat呢?

如果需要处理1MP(即1000*1000=百万像素)以上的图像,且有独立GPU,可以使用UMat+OpenCL。

为什么用1MP作为性能分界?这是因为,对于CPU来说,超过1MP的图像,CPU单线程处理可能开始出现明显延迟(如高斯模糊>10ms)。对于内存来说,1MP的RGB图像约占用3MB内存(1000×1000×3字节),超过L3缓存容量,内存带宽成为瓶颈。

——重庆教主 2025年5月16日

copyright @重庆教主 WPF中文网 联系站长:(QQ)23611316 (微信)movieclip (QQ群).NET小白课堂:864486030 | 本文由WPF中文网原创发布,谢绝转载 渝ICP备2023009518号-1