OpenCV C++ 图像处理模块 imgproc 详解

发布于:2025-06-18 ⋅ 阅读:(16) ⋅ 点赞:(0)

在计算机视觉领域,OpenCV 的图像处理模块imgproc(Image Processing)是开发者处理图像数据的核心工具集。它涵盖了从基础的颜色变换、图形绘制,到复杂的轮廓查找与分析等功能。本文将讲解imgproc模块中各个重要功能的使用方法与细节。

颜色变换​

色彩空间转换​

OpenCV 支持多种色彩空间之间的转换,最常用的是 RGB(红绿蓝)与灰度图、HSV(色调、饱和度、明度)之间的转换。使用cvtColor函数实现,其原型为:

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0);

其中,src为输入图像,dst为输出图像,code指定转换类型,dstCn指定输出图像的通道数(通常可省略)。​

1. RGB 转灰度图:
cv::Mat src = cv::imread("input.jpg");
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);  // 注意OpenCV中图像默认通道顺序为BGR
cv::imshow("Gray Image", gray);
2. RGB 转 HSV:​
cv::Mat hsv;​

cv::cvtColor(src, hsv, cv::COLOR_BGR2HSV);​

HSV 色彩空间常用于图像分割,因为它将颜色信息(色调、饱和度)与亮度分离,便于根据颜色范围提取目标。​

颜色映射​

applyColorMap函数可以将灰度图像映射为伪彩色图像,增强图像的视觉效果,常用于热力图、深度图可视化。其原型为:

void applyColorMap(InputArray src, OutputArray dst, int colormap);

colormap参数指定映射类型,如cv::COLORMAP_JET(彩虹色)、cv::COLORMAP_HOT(热图)等。

cv::Mat gray = cv::imread("gray_image.jpg", cv::IMREAD_GRAYSCALE);
cv::Mat colored;
cv::applyColorMap(gray, colored, cv::COLORMAP_JET);
cv::imshow("Colored Map", colored);

基本图形绘制​

点​

使用circle函数绘制点,通过设置半径为 1 来实现。函数原型为:

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

其中,img为输入输出图像(即绘制结果会覆盖原图),center为圆心(点坐标),radius为半径,color为颜色,thickness为线条宽度(绘制点时设为 -1 可填充圆形),lineType为线条类型,shift为坐标精度(通常为 0)。

cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);  // 创建黑色背景画布
cv::Point point(200, 200);
cv::circle(canvas, point, 1, cv::Scalar(0, 0, 255), -1);  // 绘制红色点
cv::imshow("Point", canvas);

矩形​

rectangle函数用于绘制矩形,原型为:

void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);

pt1和pt2分别为矩形对角线上的两个顶点。

cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);
cv::rectangle(canvas, cv::Point(50, 50), cv::Point(300, 300), cv::Scalar(255, 0, 0), 2);  // 绘制蓝色矩形
cv::imshow("Rectangle", canvas);

圆​

circle函数除绘制点外,也可绘制圆形:

cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);
cv::circle(canvas, cv::Point(200, 200), 100, cv::Scalar(0, 255, 0), 3);  // 绘制绿色圆
cv::imshow("Circle", canvas);

椭圆​

ellipse函数用于绘制椭圆,原型较为复杂:

void ellipse(InputOutputArray img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);

center为椭圆中心,axes为长短轴的半轴长度,angle为旋转角度,startAngle和endAngle为绘制的起始和结束角度。

cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);
cv::ellipse(canvas, cv::Point(200, 200), cv::Size(150, 100), 45, 0, 360, cv::Scalar(255, 255, 0), 2);  // 绘制黄色椭圆
cv::imshow("Ellipse", canvas);

线段​

line函数用于绘制线段:

void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);
cv::line(canvas, cv::Point(50, 50), cv::Point(350, 350), cv::Scalar(0, 128, 255), 3);  // 绘制橙色线段
cv::imshow("Line", canvas);

多边形​

polylines函数可绘制多边形(多条线段连接而成),原型为:

void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);

pts是一个包含多边形顶点坐标的数组(vector<vector<Point>>),isClosed表示多边形是否闭合。

cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);
std::vector<cv::Point> polygonPoints = {cv::Point(100, 100), cv::Point(300, 100), cv::Point(300, 300), cv::Point(100, 300)};
std::vector<std::vector<cv::Point>> polygons;
polygons.push_back(polygonPoints);
cv::polylines(canvas, polygons, true, cv::Scalar(128, 0, 128), 2);  // 绘制紫色闭合多边形
cv::imshow("Polygon", canvas);

Scalar 类​

Scalar类用于表示颜色、向量等标量数据,本质是一个包含 4 个元素的数组,常用于指定图形绘制的颜色。在 OpenCV 中,RGB 颜色需按 BGR 顺序传入,如Scalar(0, 0, 255)表示红色。此外,Scalar也可用于图像的像素值操作,例如使用Mat::setTo函数填充图像时:

cv::Mat image = cv::Mat::zeros(200, 200, CV_8UC3);
image.setTo(cv::Scalar(128, 128, 128));  // 将图像填充为灰色

随机数 RNG 类​

RNG类用于生成随机数,可用于随机颜色、随机坐标等场景。其常用方法如下:​

1.构造函数:通过种子初始化随机数生成器,若不传入种子,系统会自动生成一个随机种子。

cv::RNG rng;  // 使用系统默认种子-1
cv::RNG rngWithSeed(12345);  // 使用指定种子12345

 2.生成随机整数:

int randomInt = rng.uniform(0, 100);  // 生成0到99之间的随机整数

3.生成随机浮点数:​

float randomFloat = rng.uniform(0.0f, 1.0f); // 生成0.0到1.0之间的随机浮点数​

4.生成随机颜色:​

cv::Scalar randomColor(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256)); // 生成随机BGR颜色​

5.next 方法:next方法可以生成不同数据类型的随机数,其重载形式根据所需生成的随机数类型而定。例如,生成随机无符号整数:​

unsigned int randomUInt = rng.next();​

若要生成特定类型(如int、float)的随机数,可以使用next方法配合类型转换。例如,生成随机int类型数据:​

int randomIntFromNext = static_cast<int>(rng.next());​

文字绘制​

使用putText函数在图像上绘制文字,原型为:

void putText(InputOutputArray img, const String& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1, int lineType = LINE_8, bool bottomLeftOrigin = false);

text为要绘制的文字内容,org为文字起始坐标(字符的左下角点在画面中的位置),fontFace指定字体类型(如FONT_HERSHEY_SIMPLEX),fontScale为字体缩放比例。

cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);
cv::putText(canvas, "OpenCV Tutorial", cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2);
cv::imshow("Text", canvas);

获取文字大小​

在绘制文字前,有时需要获取文字的尺寸,以便更好地布局。可以使用getTextSize函数,其原型为:

Size getTextSize(const String& text, int fontFace, double fontScale, int thickness, int* baseLine = 0);

text为文字内容,fontFace、fontScale、thickness与putText函数中的参数含义相同,baseLine用于输出文字基线的偏移量(可选参数)。该函数返回一个Size对象,表示文字的宽度和高度。

cv::Mat canvas = cv::Mat::zeros(400, 400, CV_8UC3);
std::string text = "OpenCV Tutorial";
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
double fontScale = 1;
int thickness = 2;
int baseLine;
cv::Size textSize = cv::getTextSize(text, fontFace, fontScale, thickness, &baseLine);
cv::Point org((canvas.cols - textSize.width) / 2, (canvas.rows + textSize.height) / 2);  // 计算文字居中位置
cv::putText(canvas, text, org, fontFace, fontScale, cv::Scalar(255, 255, 255), thickness);
cv::imshow("Text with Size Calculation", canvas);

添加边框​

copyMakeBorder函数用于给图像添加边框,原型为:

void copyMakeBorder(InputArray src, OutputArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value = Scalar());

top、bottom、left、right分别指定上下左右边框的宽度,borderType指定边框类型,value用于指定常量边框的颜色(当borderType为BORDER_CONSTANT时有效)。常见的borderType类型如下:

  • BORDER_CONSTANT:用常量值填充边框,需要指定value参数,根据value填充,默认value值为0,即以黑色填充;

  • BORDER_REPLICATE:复制边缘像素来填充边框,即边框的像素值与最靠近的图像边缘像素值相同;

  • BORDER_REFLECT:以边缘为轴进行反射填充,例如像素序列[1, 2, 3],反射后为[2, 1, 2, 3, 2];

  • BORDER_WRAP:通过循环方式填充边框,看起来像是图像进行了平铺;

  • BORDER_REFLECT_101(或 BORDER_DEFAULT):类似BORDER_REFLECT,但不重复边缘像素,例如像素序列[1, 2, 3],反射后为[3, 2, 1, 2, 3]。

轮廓查找和绘制​

轮廓查找​

轮廓查找通常用于图像分割与形状分析,一般步骤如下:​

1.将图像转换为灰度图:

cv::Mat src = cv::imread("input.jpg");
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);

2.进行阈值处理:将灰度图像转换为二值图像,便于轮廓检测,常用threshold函数:

cv::Mat binary;
cv::threshold(gray, binary, 127, 255, cv::THRESH_BINARY);

3.查找轮廓:使用findContours函数,其原型为:

void findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point());

image为输入的二值图像,contours是存储轮廓的向量(每个轮廓是一个vector<Point>),hierarchy用于存储轮廓的层级关系,mode指定轮廓检索模式,method指定轮廓逼近方法,offset用于对轮廓坐标进行偏移(通常为Point())。​

不同的 mode 轮廓检索模式

 

  • cv::RETR_EXTERNAL:只检索最外层轮廓,忽略内层轮廓。适用于仅关注图像中物体最外层边界的场景,例如统计图像中独立物体的数量,这种模式下计算量相对较小。
  • cv::RETR_LIST:检索所有轮廓,但不建立轮廓间的层级关系。所有轮廓被平等对待,常用于不需要考虑轮廓嵌套关系,只需要获取所有轮廓信息的情况,如简单的线条提取。
  • cv::RETR_CCOMP:检索所有轮廓,并将轮廓组织成两级层次结构。顶层为物体的外轮廓,第二层为物体内的孔的轮廓。适用于处理具有孔洞的物体轮廓分析,比如检测带孔的零件。
  • cv::RETR_TREE:检索所有轮廓,并建立完整的轮廓树状层级关系。这种模式能详细描述轮廓之间的包含、嵌套关系,适用于复杂场景下的轮廓分析,如场景理解中物体间关系的建模 。

不同的 method 轮廓逼近方法

  • cv::CHAIN_APPROX_NONE:存储所有轮廓点,不进行任何压缩。会保留轮廓上的每一个细节点,数据量较大,适用于需要精确轮廓信息,后续可能进行高精度处理的场景,如医学图像中细胞轮廓的精确分析。
  • cv::CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角线段,仅保留端点。大大减少轮廓点数量,在保证轮廓基本形状的前提下,显著降低数据量,是最常用的轮廓逼近方法,例如在一般的物体形状识别中,既能保证形状特征,又能提高处理效率。
  • cv::CHAIN_APPROX_TC89_L1cv::CHAIN_APPROX_TC89_KCOS:使用 Teh-Chin 链逼近算法的两种不同实现方式。这两种方法在某些特定形状的轮廓逼近上可能会有更好的效果,但计算复杂度相对较高,适用于对轮廓逼近质量有特殊要求的场景 。

实际使用示例:

std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(binary, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

轮廓绘制

使用drawContours函数绘制找到的轮廓,原型为:

void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness = 1, int lineType = LINE_8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point());

contourIdx指定绘制第几个轮廓(-1 表示绘制所有轮廓)。

cv::Mat result = src.clone();
cv::drawContours(result, contours, -1, cv::Scalar(0, 255, 0), 2);  // 绘制所有绿色轮廓
cv::imshow("Contours", result);

通过对 OpenCV imgproc模块的深入学习,我们掌握了从基础图形绘制到复杂轮廓分析的核心功能。这些知识将为后续图像分割、目标检测等高级计算机视觉任务提供坚实的基础。


网站公告

今日签到

点亮在社区的每一天
去签到