14、计算机视觉中的直方图、轮廓与形态学变换及实际应用

计算机视觉中的直方图、轮廓与形态学变换及实际应用

1. 直方图均衡化

直方图均衡化是一种用于改善图像对比度的图像处理技术。它通过扩展图像中最频繁的强度值,拉伸图像的强度范围,从而增强低对比度区域的对比度,提升图像质量。实现直方图均衡化主要有两种方法:

  • 全局直方图均衡化 :使用 cv2.equalizeHist() 函数对整个图像的直方图进行均衡化。
  • 对比度受限的自适应直方图均衡化(CLAHE) :为图像的不同区域计算多个直方图,也称为局部直方图均衡化。

以下是实现这两种方法的代码示例:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('/home/pi/book/dataset/4.2.03.tiff', 1)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
R, G, B = cv2.split(img)

# 全局直方图均衡化
output1_R = cv2.equalizeHist(R)
output1_G = cv2.equalizeHist(G)
output1_B = cv2.equalizeHist(B)
output1 = cv2.merge((output1_R, output1_G, output1_B))

# CLAHE方法
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
output2_R = clahe.apply(R)
output2_G = clahe.apply(G)
output2_B = clahe.apply(B)
output2 = cv2.merge((output2_R, output2_G, output2_B))

output = [img, output1, output2]
titles = ['Original Image', 'Adjusted Histogram', 'CLAHE']

for i in range(3):
    plt.subplot(1, 3, i+1)
    plt.imshow(output[i])
    plt.title(titles[i])
    plt.axis('off')
plt.show()

运行上述代码后,会依次显示原始图像、经过全局直方图均衡化调整后的图像以及使用CLAHE方法处理后的图像。

2. 可视化图像轮廓

轮廓是连接图像边界上具有相同像素颜色值的连续点所形成的曲线。它常用于检测图像中的边界和进行图像分割。在提取轮廓之前,通常对图像进行阈值处理,以提高轮廓计算的准确性。

cv2.findContours() 函数用于计算图像中的轮廓,该函数接受图像数组、轮廓检索模式和轮廓近似方法作为参数,并返回图像中计算得到的轮廓列表。轮廓检索模式包括:
- CV_RETR_CCOMP
- CV_RETR_TREE
- CV_RETR_EXTERNAL
- CV_RETR_LIST

轮廓近似方法包括:
- CV_CHAIN_APPROX_TC89_L1
- CV_CHAIN_APPROX_TC89_KCOS
- CV_CHAIN_APPROX_NONE
- CV_CHAIN_APPROX_SIMPLE

计算出轮廓后,可以使用 cv2.drawContours() 函数将其可视化。以下是一个计算并可视化图像中所有轮廓的示例代码:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('/home/pi/book/dataset/4.2.07.tiff', 1)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 75, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0, 0, 255), 2)

original = cv2.imread('/home/pi/book/dataset/4.2.07.tiff', 1)
original = cv2.cvtColor(original, cv2.COLOR_BGR2RGB)

output = [original, img]
titles = ['Original', 'Contours']

for i in range(2):
    plt.subplot(1, 2, i+1)
    plt.imshow(output[i])
    plt.title(titles[i])
    plt.axis('off')
plt.show()

运行上述代码后,会显示原始图像和带有轮廓的图像。

3. 对图像应用形态学变换

形态学操作本质上是数学运算,用于改变图像的形状。这些操作在二值图像上的效果最为直观,可用于消除图像中的噪声等不必要信息。形态学操作接受图像和核作为输入。

常见的形态学操作包括:
- 腐蚀(Erosion) :收缩图像中的边界,将背景部分边界上的白色像素设置为黑色,从而缩小白色区域。
- 膨胀(Dilation) :与腐蚀操作相反,在前景边界附近添加白色像素,扩大白色前景区域。
- 形态学梯度(Morphological Gradient) :计算膨胀操作和腐蚀操作的差值。

以下是一个展示这些形态学操作的示例代码:

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = np.array([[0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 255, 255, 255, 0, 0],
                [0, 0, 255, 255, 255, 0, 0],
                [0, 0, 255, 255, 255, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)

kernel = np.ones((3, 3), np.uint8)
erosion = cv2.erode(img, kernel, iterations = 1)
dilation = cv2.dilate(img, kernel, iterations = 1)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)

titles = ['Original', 'Erosion', 'Dilation', 'Gradient']
output = [img, erosion, dilation, gradient]

for i in range(4):
    plt.subplot(2, 2, i+1)
    plt.imshow(output[i], cmap='gray')
    plt.title(titles[i])
    plt.axis('off')
plt.show()

运行上述代码后,会依次显示原始图像、经过腐蚀操作后的图像、经过膨胀操作后的图像以及形态学梯度图像。

此外,OpenCV还提供了 cv2.getStructuringElement() 函数,用于返回指定形状和大小的自定义核。形状可以是 cv2.MORPH_CROSS cv2.MORPH_RECT cv2.MORPH_ELLIPSE ,大小必须是奇数正整数。以下是不同形状核的示例:

import cv2

# 矩形结构元素
k = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
print(k)

# 椭圆形结构元素
k = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
print(k)

# 十字形结构元素
k = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
print(k)

以下是使用自定义3x3十字形核进行其他形态学操作的示例代码:

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = np.array([[0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 255, 255, 255, 0, 0],
                [0, 0, 255, 255, 255, 0, 0],
                [0, 0, 255, 255, 255, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0]], dtype=np.uint8)

kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))

open = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
close = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
hitmiss = cv2.morphologyEx(img, cv2.MORPH_HITMISS, kernel)

titles = ['Original', 'Open', 'Close', 'Top hat', 'Black hat', 'Hit Miss']
output = [img, open, close, tophat, blackhat, hitmiss]

for i in range(6):
    plt.subplot(2, 3, i+1)
    plt.imshow(output[i], cmap='gray')
    plt.title(titles[i])
    plt.axis('off')
plt.show()

运行上述代码后,会显示原始图像和经过各种形态学操作后的图像。这些操作的含义如下:
- 开运算(Opening) :先进行腐蚀操作,再进行膨胀操作。
- 闭运算(Closing) :先进行膨胀操作,再进行腐蚀操作。
- 顶帽变换(Top Hat) :提取图像中的小元素和细节,是输入图像与开运算结果的差值。
- 黑帽变换(Black Hat) :是闭运算结果与输入图像的差值。
- 击中击不中变换(Hit Miss) :用于检测二值图像中的给定配置或模式。

4. 计算机视觉的实际应用

在实际应用中,计算机视觉技术有广泛的用途,以下将介绍几种常见的应用及实现代码。

4.1 实现Max RGB滤波器

Max RGB滤波器是一种基于像素颜色强度值的特殊滤波器。对于彩色图像中的每个像素,比较其所有颜色通道的强度,保留强度最大的通道,将其他通道的强度值置为零。以下是实现该滤波器的代码:

import cv2
import numpy as np

def maxRGB(img):
    b = img[:, :, 0]
    g = img[:, :, 1]
    r = img[:, :, 2]
    M = np.maximum(np.maximum(b, g), r)
    b[b < M] = 0
    g[g < M] = 0
    r[r < M] = 0
    return(cv2.merge((b, g, r)))

cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    cv2.imshow('Max RGB Filter', maxRGB(frame))
    if cv2.waitKey(1) == 27:
        break
cv2.destroyAllWindows()
cap.release()

运行上述代码后,可以看到经过Max RGB滤波器处理后的实时视频流。

4.2 实现背景减除

在许多应用中,如安全监控,会使用静态相机。背景减除是一种将背景和移动对象分离的方法,通常返回一个二值图像,其中背景(场景的静态部分)用黑色像素表示,移动(变化或动态)部分用白色像素表示。OpenCV提供了两种实现背景减除的算法:

  • cv2.createBackgroundSubtractorKNN() :创建一个K近邻(KNN)背景减除器对象。
  • cv2.createBackgroundSubtractorMOG2() :另一种生成前景掩码的方法。

以下是使用 cv2.createBackgroundSubtractorKNN() 的示例代码:

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorKNN()

while(True):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    cv2.imshow('frame', fgmask)
    if cv2.waitKey(30) == 27:
        break
cap.release()
cv2.destroyAllWindows()

使用 cv2.createBackgroundSubtractorMOG2() 的代码类似,只需将创建背景减除器对象的函数替换即可:

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
fgbg = cv2.createBackgroundSubtractorMOG2()

while(True):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    cv2.imshow('frame', fgmask)
    if cv2.waitKey(30) == 27:
        break
cap.release()
cv2.destroyAllWindows()

运行上述代码后,会显示经过背景减除处理后的二值视频流。需要注意的是,如果物体静止一段时间,OpenCV会将其视为背景的一部分,并在输出中逐渐淡化。

4.3 计算光流

光流是视频(实时或录制)中物体运动所呈现的模式。如果观察者(在我们的例子中是相机)处于运动状态,即使物体是静止的,也会被视为在运动,这就是相对运动。光流突出了视频中的相对运动。

OpenCV中的 cv2.calcOpticalFlowFarneback() 函数使用密集方法计算光流,即计算所有点的光流,该函数实现了Gunner Farneback算法。以下是计算光流的示例代码:

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
ret, frame1 = cap.read()
prvs = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[..., 1] = 255

while(cap):
    ret, frame2 = cap.read()
    next = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
    flow = cv2.calcOpticalFlowFarneback(prvs, next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
    mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
    hsv[..., 0] = ang * 180/np.pi/2
    hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
    rgb = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
    cv2.imshow('Optical Flow', rgb)
    if cv2.waitKey(1) == 27:
        break
    prvs = next

cap.release()
cv2.destroyAllWindows()

在上述代码中, cv2.calcOpticalFlowFarneback() 返回光流在XY(笛卡尔)坐标系中的坐标,然后使用 cv2.cartToPolar() 函数将其转换为极坐标。最终的HSV帧中,色调表示运动的角度,值表示运动的强度,将其转换为BGR格式并显示。光流的概念在以下领域有应用:
- 对象检测和跟踪
- 运动检测和跟踪
- 机器人导航

4.4 检测和跟踪运动

可以使用树莓派(RPi)、OpenCV和Python构建一个实时运动检测和跟踪系统。基本原理是计算视频帧(视频文件或USB网络摄像头的实时流)中连续帧之间的差异,然后在需要检测差异的像素区域周围绘制轮廓。以下是实现该系统的详细步骤和代码:

  1. 导入必要的库并初始化摄像头对象
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
  1. 定义用于膨胀操作的核
k = np.ones((3, 3), np.uint8)
  1. 捕获并存储连续帧
t0 = cap.read()[1]
t1 = cap.read()[1]
  1. 在循环中计算帧之间的绝对差异并转换为灰度图像
while(True):
    d = cv2.absdiff(t1, t0)
    grey = cv2.cvtColor(d, cv2.COLOR_BGR2GRAY)
  1. 对灰度图像进行高斯模糊以去除噪声
    blur = cv2.GaussianBlur(grey, (3, 3), 0)
  1. 对模糊后的图像进行二值阈值处理
    ret, th = cv2.threshold(blur, 15, 255, cv2.THRESH_BINARY)
  1. 对二值图像进行膨胀操作,以便更容易检测边界
    dilated = cv2.dilate(th, k, iterations=2)
  1. 查找膨胀图像中的轮廓并绘制在图像上
    contours, hierarchy = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    t2 = t0
    cv2.drawContours(t2, contours, -1, (0, 255, 0), 2)
    cv2.imshow('Output', t2)
  1. 更新帧并捕获下一帧
    t0 = t1
    t1 = cap.read()[1]
    if cv2.waitKey(5) == 27:
        break
  1. 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()

运行上述代码后,会显示带有运动检测轮廓的视频流。

综上所述,计算机视觉技术在图像处理、目标检测、运动跟踪等领域有着广泛的应用。通过学习和掌握直方图均衡化、轮廓检测、形态学变换以及各种实际应用的实现方法,可以更好地利用计算机视觉技术解决实际问题。

计算机视觉中的直方图、轮廓与形态学变换及实际应用

5. 检测图像中的条形码

在图像中检测条形码是计算机视觉的一个重要应用,例如在物流、零售等行业。虽然文档中未给出具体代码,但通常可以使用OpenCV结合一些条形码检测库(如 pyzbar )来实现。以下是一个简单的示例代码:

import cv2
from pyzbar.pyzbar import decode

def detect_barcode(image_path):
    image = cv2.imread(image_path)
    barcodes = decode(image)
    for barcode in barcodes:
        (x, y, w, h) = barcode.rect
        cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
        barcode_data = barcode.data.decode("utf-8")
        barcode_type = barcode.type
        text = f"{barcode_type}: {barcode_data}"
        cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
    cv2.imshow("Barcode Detection", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

image_path = "your_image_path.jpg"
detect_barcode(image_path)

上述代码的执行步骤如下:
1. 读取指定路径的图像。
2. 使用 pyzbar 库的 decode 函数解码图像中的条形码。
3. 遍历检测到的条形码,绘制矩形框标记条形码位置。
4. 提取条形码的数据和类型,并在图像上显示。
5. 显示处理后的图像。

6. 实现色度键效果

色度键效果常用于视频制作中,通过将特定颜色(通常是绿色或蓝色)的背景替换为其他图像或视频。以下是一个简单的实现代码:

import cv2
import numpy as np

# 读取前景和背景图像
foreground = cv2.imread('foreground.jpg')
background = cv2.imread('background.jpg')

# 定义色度键颜色范围(这里以绿色为例)
lower_green = np.array([0, 120, 0])
upper_green = np.array([100, 255, 100])

# 创建掩码
mask = cv2.inRange(foreground, lower_green, upper_green)

# 对掩码进行形态学操作,去除噪声
kernel = np.ones((3, 3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)

# 反转掩码
mask_inv = cv2.bitwise_not(mask)

# 提取前景和背景
fg = cv2.bitwise_and(foreground, foreground, mask=mask_inv)
bg = cv2.bitwise_and(background, background, mask=mask)

# 合并前景和背景
result = cv2.add(fg, bg)

# 显示结果
cv2.imshow('Chroma Key Effect', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

上述代码的执行步骤如下:
1. 读取前景和背景图像。
2. 定义色度键颜色范围,创建掩码。
3. 对掩码进行形态学操作,去除噪声。
4. 反转掩码。
5. 分别提取前景和背景。
6. 合并前景和背景,得到最终结果。
7. 显示处理后的图像。

7. 总结与展望

计算机视觉技术在各个领域都有着广泛的应用,通过本文介绍的直方图均衡化、轮廓检测、形态学变换以及各种实际应用的实现方法,可以解决许多实际问题。例如,在安全监控领域,可以使用背景减除和运动检测技术实时监测异常情况;在物流行业,可以使用条形码检测技术提高货物管理效率;在视频制作领域,可以使用色度键效果实现特效合成。

未来,随着计算机硬件性能的不断提升和算法的不断优化,计算机视觉技术将在更多领域得到应用。例如,在自动驾驶领域,计算机视觉技术可以用于识别道路、交通标志和其他车辆;在医疗领域,计算机视觉技术可以用于医学图像分析和疾病诊断。

为了更好地掌握计算机视觉技术,建议读者多实践、多尝试不同的算法和应用场景。同时,可以关注相关的学术研究和开源项目,了解最新的技术动态。

以下是一个简单的mermaid流程图,展示了运动检测和跟踪系统的主要步骤:

graph TD;
    A[初始化摄像头] --> B[定义膨胀核];
    B --> C[捕获连续帧];
    C --> D[计算帧间绝对差异];
    D --> E[转换为灰度图像];
    E --> F[高斯模糊去除噪声];
    F --> G[二值阈值处理];
    G --> H[膨胀操作];
    H --> I[查找轮廓并绘制];
    I --> J[更新帧并捕获下一帧];
    J --> K{是否按下Esc键};
    K -- 否 --> D;
    K -- 是 --> L[释放摄像头并关闭窗口];

另外,为了更清晰地展示各种计算机视觉应用的特点和用途,以下是一个表格:
| 应用名称 | 特点 | 用途 |
| ---- | ---- | ---- |
| Max RGB滤波器 | 保留像素中强度最大的颜色通道,其他通道置零 | 图像增强、特效处理 |
| 背景减除 | 分离背景和移动对象,返回二值图像 | 安全监控、运动检测 |
| 光流计算 | 突出视频中的相对运动 | 对象检测和跟踪、机器人导航 |
| 运动检测和跟踪 | 计算连续帧差异,绘制轮廓 | 安全监控、行为分析 |
| 条形码检测 | 识别图像中的条形码数据和类型 | 物流管理、零售结算 |
| 色度键效果 | 替换特定颜色背景 | 视频制作、特效合成 |

通过以上的学习和实践,相信读者对计算机视觉技术有了更深入的了解,并能够运用这些技术解决实际问题。不断探索和创新,将计算机视觉技术应用到更多的领域中。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值