OpenCV图像处理实战:从边缘检测到透视变换,掌握七大核心函数

一、引言

图像处理是计算机视觉领域中的基础,而边缘检测和轮廓分析则是其核心任务之一。OpenCV作为一个强大的计算机视觉库,提供了众多功能强大的函数,帮助开发者实现高效的图像处理。在本文中,我们将深入探索OpenCV中的七个重要函数:Sobel算子、Laplacian算子、Canny算子、findContours、drawContours、透视变换函数以及如何通过外接矩形框识别轮廓。通过这些函数的讲解和实例演示,您将能掌握图像边缘检测、轮廓分析和透视变换等常见技术,为后续的图像处理打下坚实的基础。

二、重要函数

1. Sobel算子

cv2.Sobel(src, ddepth, dx, dy, ksize=3, scale=1, delta=0, borderType=None)

  • 功能:

Sobel算子用于计算图像的边缘,通过计算图像在水平方向(X轴)和垂直方向(Y轴)的梯度,帮助检测图像中的边缘。

  • 参数:
  • src:输入图像,通常是灰度图(单通道图像)。
  • ddepth:通常,你可以使用 -1 来表示与输入图像相同的深度,或者使用如 cv2.CV_64F 等来指定特定的深度。
  • dx:x 方向上的导数阶数。如果你想要计算 x 方向上的梯度,设置这个参数为 1;如果你不关心 x 方向上的梯度,设置这个参数为 0。
  • dy:y 方向上的导数阶数。如果你想要计算 y 方向上的梯度,设置这个参数为 1;如果你不关心 y 方向上的梯度,设置这个参数为 0。通常,你不会同时设置 dx 和 dy 都为 0。
  • ksize:Sobel 核的大小。它必须是 1、3、5、7 或 9 之一。这个参数决定了用于计算梯度的滤波器的大小。大小为 1 时表示使用最小的滤波器,但通常你会使用更大的滤波器来平滑梯度计算。
  • scale:可选参数,表示计算梯度时的缩放因子。默认值为 1,表示不进行缩放。你可以通过调整这个参数来放大或缩小梯度的结果。
  • delta:可选参数,表示在将结果存储到目标图像之前要添加到结果中的可选增量值。默认值为 0,表示不添加增量。
  • borderType:像素外推方法,例如 cv2.BORDER_DEFAULT、cv2.BORDER_REFLECT 等。这个参数决定了在图像边界处如何处理像素外推。
  • 返回值:

返回值是一个与输入图像大小相同的矩阵,包含了图像在x和y方向的梯度值。该矩阵表示图像的梯度信息,用于边缘检测。

  • 应用:边缘检测的实际案例

代码:

python 复制代码
import cv2

img =cv2.imread("./shudu.png")
# 使用soble算子
img_sobel = cv2.Sobel(img, -1, 0, 1, ksize=3)
img_sobel_2 = cv2.Sobel(img, -1, 1, 0, ksize=3)

cv2.imshow('image',img)
cv2.imshow('img_sobel',img_sobel)
cv2.imshow('img_sobel_2',img_sobel_2)

cv2.waitKey(0)

结果展示:

2. Laplacian算子

cv2.Laplacian(src, ddepth[, ksize[, scale[, delta[, borderType]]]])

  • 功能:Laplacian算子通过计算图像的二阶导数,检测图像中的边缘。与Sobel算子不同,Laplacian算子一次性综合了水平方向和垂直方向的梯度变化,因此能快速得到边缘信息。

  • 参数:

  • src:输入图像,通常为灰度图。
  • ddepth:输出图像的所需深度。这个参数决定了输出图像的深度(数据类型)。通常,你可以使用 -1 来表示与输入图像相同的深度,或者使用 cv2.CV_64F 等来指定特定的深度。
  • ksize(可选):滤波核大小,默认为1(仅支持1、3、5、7等奇数值)
  • scale(可选):表示计算拉普拉斯算子时的缩放因子。默认值为 1,表示不进行缩放。你可以通过调整这个参数来放大或缩小拉普拉斯算子的结果。
  • delta(可选):表示在将结果存储到目标图像之前要添加到结果中的可选增量值。默认值为 0,表示不添加增量。
  • borderType(可选):像素外推方法,例如 cv2.BORDER_DEFAULT、cv2.BORDER_REFLECT 等。这个参数决定了在图像边界处如何处理像素外推。当 ksize 大于 1 时,这个参数才有意义。
  • 返回值:返回一个梯度图像(矩阵),其中每个像素的值表示该点的二阶导数值(边缘强度)。较大的值对应边缘区域。

  • 应用:综合数独图像水平方向和垂直方向的梯度变化

代码:

python 复制代码
import cv2

img =cv2.imread("./shudu.png")

# 使用拉普拉斯算子
img_lap = cv2.Laplacian(img, -1,ksize=5)

cv2.imshow('image',img)
cv2.imshow('img_lap',img_lap)

cv2.waitKey(0)

结果:

3. Canny算子

cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]])

  • 功能:Canny算子用于检测图像中的边缘。它通过以下步骤实现:

(1)降噪:使用高斯滤波器平滑图像,减少噪声影响。

(2)计算梯度和方向:使用Sobel算子计算每个像素点的梯度幅值和方向。

(3)非极大值抑制:确保边缘的精确性,去掉梯度方向上非边缘点。

(4)双阈值检测筛选:确定强边缘、弱边缘以及非边缘。

  • 参数:

-image‌:输入图像,它应该是一个灰度图像(单通道)。
-‌threshold1‌:第一个阈值,用于边缘检测的滞后过程。这个值较低,用于确定边缘的初始点。
-‌threshold2‌:第二个阈值,用于边缘检测的滞后过程。这个值较高,用于确定边缘的最终点。如果某个像素点的梯度值高于这个阈值,它被认为是边缘;如果低于这个值但高于threshold1,并且与高于threshold2的像素点相连,它也被认为是边缘。
-‌edges‌:输出图像,与输入图像大小相同,但通常是二值图像(即只包含边缘和非边缘的像素)。
‌-apertureSize‌(可选,默认为3):Sobel算子的大小,它决定了梯度计算的邻域大小。它必须是1、3、5或7之一。
-‌L2gradient‌(可选,默认为False):一个布尔值,指示是否使用更精确的L2范数进行梯度计算。如果为True,则使用L2范数(即欧几里得距离);如果为False,则使用L1范数(即曼哈顿距离)。L2范数通常更精确,但计算成本也更高。

  • 返回值:返回一个与输入图像大小相同的二值图像,其中:

  • 白色像素(255)表示边缘。

  • 黑色像素(0)表示非边缘区域。

  • 应用:精确边缘检测

代码:

python 复制代码
import cv2

img = cv2.imread("./card.png")

# 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化
_, img_binary = cv2.threshold(img_gray,130,255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# 进行高斯滤波
img_blur = cv2.GaussianBlur(img_binary, (3,3),3)

# 边缘检测
img_canny = cv2.Canny(img_blur, 30,70)

cv2.imshow('image',img)
cv2.imshow('img_gray',img_gray)
cv2.imshow('img_binary',img_binary)
cv2.imshow('img_canny',img_canny)
cv2.waitKey(0)

结果:

4. findContours函数

contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

  • 功能:用于检测二值图像中的轮廓。

  • 它可以将边界连续的白色区域识别为一个轮廓(通常是目标物体的形状)。

  • 常用在处理二值化后的图像,例如经过阈值处理或 Canny 边缘检测后的结果。

  • 参数:

-image:输入图像,必须是二值图像(非零像素被视为目标,零像素为背景)。

  • mode:轮廓检索模式,用于决定提取的轮廓层级关系:

  • cv2.RETR_EXTERNAL:只检索最外层轮廓。

  • cv2.RETR_LIST:检索所有轮廓,不建立层级关系。

  • cv2.RETR_CCOMP:检索所有轮廓,建立两级层次结构。

  • cv2.RETR_TREE:检索所有轮廓,并建立完整的层次结构(父子关系)。

  • method:轮廓近似方法,用于减少轮廓点数以节省计算量:

  • cv2.CHAIN_APPROX_NONE:存储所有轮廓点。

  • cv2.CHAIN_APPROX_SIMPLE:只存储拐点,从而压缩水平、垂直和对角线段的冗余点。

  • contours(可选):存储轮廓点的列表(与返回值重复,较少用)。

  • hierarchy(可选):存储轮廓层次关系的数组。

  • offset(可选):可选的偏移量,用于调整轮廓坐标。

  • 返回值:

  • contours:轮廓列表,其中每个轮廓是一个点集的数组。例如:`contours[0]` 表示第一个轮廓,包含其所有点的坐标。

  • hierarchy:层次关系数组,形状为 (轮廓数, 4),每行的四个值分别表示当前轮廓的下一轮廓、前一轮廓、子轮廓和父轮廓的索引。

5. drawContours函数

cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])

  • 功能:将指定的轮廓绘制在图像上,用于显示或标注目标区域的边界。

  • 参数:

  • image:目标图像,用于绘制轮廓,通常是彩色图像。
  • contours:轮廓点列表,通常由 `cv2.findContours` 返回,每个轮廓是一个点集。
  • contourIdx:要绘制的轮廓索引:

-1:绘制所有轮廓。

具体索引:绘制指定的轮廓(如第0个轮廓)。

color:轮廓颜色(如 `(0, 255, 0)` 表示绿色),使用 BGR 格式。

thickness(可选):轮廓线的厚度,默认为 1。

正值:设置具体厚度。

-1:填充轮廓内部。

  • lineType(可选):线条类型,默认为 `cv2.LINE_8`。

`cv2.LINE_4`:4连接线。
`cv2.LINE_8`:8连接线。
`cv2.LINE_AA`:抗锯齿线。

  • hierarchy(可选):层次结构数组,用于指定绘制哪些轮廓。
  • maxLevel(可选):绘制轮廓的最大层次,仅在 `hierarchy` 不为空时有效。
  • offset(可选):偏移量,用于调整绘制轮廓的坐标。
  • 应用:轮廓可视化

代码:

python 复制代码
import cv2
import numpy as np

img = cv2.imread("./31.png")

# 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值化
_, img_binary = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 寻找轮廓
contours, _ = cv2.findContours(img_binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

# 绘制轮廓
img_draw = img.copy()
cv2.drawContours(img_draw,contours,-1,(0,0,255),3)

cv2.imshow('image',img)
cv2.imshow('image_draw',img_draw)

cv2.waitKey(0)

结果 :

6. 透视变换函数

可跳转另一篇博客阅读
图像矫正小白指南:从理论到实践的简单实现-CSDN博客

7. 轮廓的外接边界框

(1)外接矩形

x, y, w, h = cv2.boundingRect(contour)

  • 功能:外接矩形是包围轮廓的一个矩形,它的边缘与图像坐标轴平行

-参数:

  • contour:输入的轮廓,是通过 `cv2.findContours()` 获取的一个轮廓。

-返回值

  • x, y:外接矩形左上角的坐标。

  • w, h:外接矩形的宽度和高度。

(2)最小外接矩形

box = cv2.minAreaRect(contour)

  • 功能:最小外接矩形(也叫旋转矩形)是包围轮廓的一个矩形,但它可以根据轮廓的方向进行旋转,以最小化矩形的面积。这种矩形能够更紧凑地包围轮廓,适应有旋转的物体形状。

  • 参数:

contour:输入的轮廓。

-返回值:

  • box:返回一个最小外接矩形,包含:

  • center:矩形中心点的坐标 (cx, cy)。

  • size:矩形的宽度和高度 (w, h)。

  • angle:矩形的旋转角度(相对于水平线的角度)。

对比:

外接矩形:适合简单的目标检测任务,尤其是当物体不旋转或旋转不明显时,计算简单且快速。

最小外接矩形:适合需要更精确描述轮廓,尤其是当物体存在旋转时,它能提供更加紧凑的包围矩形。

代码:

python 复制代码
import cv2
import numpy as np

img = cv2.imread("./outline.png")
# 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
# 二值化
_, img_binary = cv2.threshold(img_gray,
                              127,
                              255,
                              cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 寻找轮廓
contours, _ = cv2.findContours(img_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
img_draw = img.copy()
cv2.drawContours(img_draw, contours, -1, (0, 0, 255), 2)


# 给所有轮廓都绘制 外接
for i in contours:
    # 第一种:调用外接矩形函数,获取当前轮廓点的左上角的坐标(x, y) 宽w 高h
    x, y, w, h = cv2.boundingRect(i)
    # 画矩形
    cv2.rectangle(img_draw, [x, y], [x+w, y+h], (0, 255, 0), 2)

    # 第二种:调用最小面积外接矩形函数,获取包含三个元素的元组(中心点坐标、长宽、旋转角度)
    # ((center_x, center_y), (width, height), angle)
    ret = cv2.minAreaRect(i)
    # 调用cv2.boxPoints(ret)可以获取旋转矩阵的四个顶点
    box = np.int32(cv2.boxPoints(ret))
    # 绘制轮廓
    cv2.drawContours(img_draw, [box], -1, (255, 255, 0), 3)


cv2.imshow('image', img)
cv2.imshow('image_draw', img_draw)
cv2.waitKey(0)

结果展示:

三、 结语

在本文中,我们探讨了多个图像处理技术,包括 Sobel 算子、Laplacian 算子、Canny 边缘检测、轮廓提取与绘制、以及透视变换等。通过这些基础方法,能够有效地处理图像中的边缘和形状,帮助我们从复杂的图像中提取出有用的信息。掌握这些技术,对于图像处理和计算机视觉的进一步学习与应用至关重要。希望本文能够为你深入理解这些常见操作提供一定的帮助,继续探索和应用这些工具来解决实际问题。

相关推荐
NAGNIP41 分钟前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab2 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab2 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP6 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年6 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼6 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS6 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区7 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈7 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang8 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx