计算机视觉中的直方图、轮廓与形态学变换及实际应用
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网络摄像头的实时流)中连续帧之间的差异,然后在需要检测差异的像素区域周围绘制轮廓。以下是实现该系统的详细步骤和代码:
- 导入必要的库并初始化摄像头对象 :
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
- 定义用于膨胀操作的核 :
k = np.ones((3, 3), np.uint8)
- 捕获并存储连续帧 :
t0 = cap.read()[1]
t1 = cap.read()[1]
- 在循环中计算帧之间的绝对差异并转换为灰度图像 :
while(True):
d = cv2.absdiff(t1, t0)
grey = cv2.cvtColor(d, cv2.COLOR_BGR2GRAY)
- 对灰度图像进行高斯模糊以去除噪声 :
blur = cv2.GaussianBlur(grey, (3, 3), 0)
- 对模糊后的图像进行二值阈值处理 :
ret, th = cv2.threshold(blur, 15, 255, cv2.THRESH_BINARY)
- 对二值图像进行膨胀操作,以便更容易检测边界 :
dilated = cv2.dilate(th, k, iterations=2)
- 查找膨胀图像中的轮廓并绘制在图像上 :
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)
- 更新帧并捕获下一帧 :
t0 = t1
t1 = cap.read()[1]
if cv2.waitKey(5) == 27:
break
- 释放摄像头并关闭所有窗口 :
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滤波器 | 保留像素中强度最大的颜色通道,其他通道置零 | 图像增强、特效处理 |
| 背景减除 | 分离背景和移动对象,返回二值图像 | 安全监控、运动检测 |
| 光流计算 | 突出视频中的相对运动 | 对象检测和跟踪、机器人导航 |
| 运动检测和跟踪 | 计算连续帧差异,绘制轮廓 | 安全监控、行为分析 |
| 条形码检测 | 识别图像中的条形码数据和类型 | 物流管理、零售结算 |
| 色度键效果 | 替换特定颜色背景 | 视频制作、特效合成 |
通过以上的学习和实践,相信读者对计算机视觉技术有了更深入的了解,并能够运用这些技术解决实际问题。不断探索和创新,将计算机视觉技术应用到更多的领域中。
超级会员免费看
1459

被折叠的 条评论
为什么被折叠?



