图像分割、深度估计与直方图计算
1. 图像分割方法概述
图像分割是将图像划分为多个部分或区域的过程,常见的分割方法有阈值法、均值漂移算法和k - 均值聚类。
1.1 均值漂移算法分割
均值漂移算法由Bogdan Georgescu和Chris M. Christoudias开发并以C++实现,Python实现版本为PyMeanShift。它使用ndarrays和NumPy存储和处理图像,因此与基于NumPy的图像处理库(如OpenCV、Mahotas和scikit - image)兼容。
1.1.1 安装步骤
在Linux、Unix等系统上,没有PyMeanShift的二进制包,需要从源代码构建和安装:
1. 从https://github.com/fjean/pymeanshift下载最新版本的源代码,下载的是ZIP文件。
2. 将ZIP文件复制到pi用户的主目录
/pi/home
并解压。
3. 在LXTerminal中依次运行以下命令:
cd ~
cd pymeanshift-master/
sudo python3 setup.py build
sudo python3 setup.py install
- 安装完成后,在命令提示符中运行以下命令检查是否安装成功:
python3 -c "import pymeanshift as pms"
1.1.2 代码示例
import cv2
import pymeanshift as pms
from matplotlib import pyplot as plt
img = cv2.imread('/home/pi/book/dataset/house.tiff', 1)
input = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
(segmented_image, labels_image, number_regions) = pms.segment(
input, spatial_radius=2, range_radius=2, min_density=300)
plt.subplot(131)
plt.imshow(input)
plt.title('Input')
plt.axis('off')
plt.subplot(132)
plt.imshow(segmented_image)
plt.title('Segmented Output')
plt.axis('off')
plt.subplot(133)
plt.imshow(labels_image)
plt.title('Labeled Output')
plt.axis('off')
plt.show()
1.1.3 应用于实时视频
import cv2
import pymeanshift as pms
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
(segmented_image, labels_image, number_regions) = pms.segment(
frame, spatial_radius=2, range_radius=2, min_density=50)
cv2.imshow('Segmented', segmented_image)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
cap.release()
由于分割计算量较大,实时视频的帧率通常较低。
1.2 k - 均值聚类和图像量化
k - 均值聚类算法是一种分类算法,输入是大小为n的数据集,输出将其划分为k个分区。OpenCV的
cv2.kmeans()
函数可实现单维和多维数据的k - 均值聚类,其参数如下:
| 参数 | 说明 |
| ---- | ---- |
| Data | 输入数据,必须是浮点数值格式 |
| K | 输出的分区总数,需提前确定(对于彩色图像,即输出分割图像的颜色数量) |
| Criteria | 算法的终止条件 |
| Attempts | 算法使用不同初始标签运行的次数 |
| Flags | 聚类初始中心的位置,可选值为
cv2.KMEANS_RANDOM_CENTERS
、
cv2.KMEANS_PP_CENTERS
、
cv2.KMEANS_USE_INITIAL_LABELS
|
1.2.1 一维数据示例
import numpy as np
import cv2
from matplotlib import pyplot as plt
x = np.random.randint(25, 100, 25)
y = np.random.randint(175, 255, 25)
z = np.hstack((x, y))
z = z.reshape((50, 1))
z = np.float32(z)
criteria = (cv2.TERM_CRITERIA_EPS +
cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
flags = cv2.KMEANS_RANDOM_CENTERS
compactness, labels, centers = cv2.kmeans(z, 2,
None,
criteria,
10, flags)
A = z[labels == 0]
B = z[labels == 1]
plt.hist(A, 256, [0, 256], color='g')
plt.hist(B, 256, [0, 256], color='b')
plt.hist(centers, 32, [0, 256], color='r')
plt.show()
1.2.2 二维数据示例
import numpy as np
import cv2
from matplotlib import pyplot as plt
X = np.random.randint(25, 50, (25, 2))
Y = np.random.randint(60, 85, (25, 2))
Z = np.vstack((X, Y))
Z = np.float32(Z)
criteria = (cv2.TERM_CRITERIA_EPS +
cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret, label, center = cv2.kmeans(Z, 2, None, criteria,
10, cv2.KMEANS_RANDOM_CENTERS)
A = Z[label.ravel() == 0]
B = Z[label.ravel() == 1]
plt.scatter(A[:, 0], A[:, 1])
plt.scatter(B[:, 0], B[:, 1], c='g')
plt.scatter(center[:, 0], center[:, 1],
s=80, c='r', marker='s')
plt.xlabel('X - Axis')
plt.ylabel('Y - Axis')
plt.show()
1.2.3 彩色图像示例
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('/home/pi/book/dataset/4.2.03.tiff', 1)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
Z = img.reshape((-1, 3))
Z = np.float32(Z)
criteria = (cv2.TERM_CRITERIA_EPS +
cv2.TERM_CRITERIA_MAX_ITER,
10, 1.0)
k = 2
ret, label1, center1 = cv2.kmeans(Z, k, None, criteria, 10,
cv2.KMEANS_RANDOM_CENTERS)
center1 = np.uint8(center1)
res1 = center1[label1.flatten()]
output1 = res1.reshape((img.shape))
k = 4
ret, label1, center1 = cv2.kmeans(Z, k, None, criteria, 10,
cv2.KMEANS_RANDOM_CENTERS)
center1 = np.uint8(center1)
res1 = center1[label1.flatten()]
output2 = res1.reshape((img.shape))
k = 12
ret, label1, center1 = cv2.kmeans(Z, k, None, criteria, 10,
cv2.KMEANS_RANDOM_CENTERS)
center1 = np.uint8(center1)
res1 = center1[label1.flatten()]
output3 = res1.reshape((img.shape))
output = [img, output1, output2, output3]
titles = ['Original Image', 'K=2', 'K=4', 'K=12']
for i in range(4):
plt.subplot(2, 2, i + 1)
plt.imshow(output[i])
plt.title(titles[i])
plt.xticks([])
plt.yticks([])
plt.show()
1.3 k - 均值和均值漂移算法比较
| 算法 | 时间复杂度 | 适用情况 |
|---|---|---|
| k - 均值算法 | O(n) | 已知聚类数量时,运行速度较快 |
| 均值漂移算法 | O(n²) | 未知聚类数量时使用 |
2. 视差图和深度估计
视差是指左右眼或相机捕获的图像中物体位置的差异,由视差产生的视差信息可用于计算物体的深度。OpenCV提供了
cv2.StereoBM.compute()
函数计算图像对的视差图。
2.1 代码示例
import cv2
import matplotlib.pyplot as plt
Right = cv2.imread('/home/pi/book/dataset/imRsmall.jpg', 0)
Left = cv2.imread('/home/pi/book/dataset/imLsmall.jpg', 0)
stereo_BM_state = cv2.StereoBM_create()
output_map = stereo_BM_state.compute(Left, Right)
titles = ['Left', 'Right', 'Depth Map']
output = [Left, Right, output_map]
for i in range(3):
plt.subplot(1, 3, i + 1)
plt.imshow(output[i], cmap='gray')
plt.title(titles[i])
plt.axis('off')
plt.show()
输出视差图中,较亮区域表示视差较大,对应输入图像中离相机较近的物体;较暗区域表示视差较小,对应离相机较远的物体。
以下是图像分割和深度估计的流程图:
graph TD;
A[图像输入] --> B{选择分割方法};
B --> C[均值漂移算法];
B --> D[k - 均值聚类];
C --> E[分割图像];
D --> F[聚类图像];
A --> G[左右图像对];
G --> H[计算视差图];
H --> I[估计深度];
3. 直方图的计算与可视化
直方图是数据分布的图形表示,本质上是频率分布表的图形化展示。在图像处理中,图像的直方图用于表示灰度或颜色色调的出现频率。
3.1 基本概念与示例
假设有数据集
(1, 2, 1, 3, 4, 1, 2, 3, 4, 4, 2, 3, 4)
,其频率分布可通过绘制直方图来展示。可以使用
np.histogram()
计算直方图,使用
plt.hist()
直接计算并绘制。以下是代码示例:
import numpy as np
import matplotlib.pyplot as plt
a = np.array([1, 2, 1, 3, 4, 1, 2, 3, 4, 4, 2, 3, 4])
hist, bins = np.histogram(a)
print(hist)
print(bins)
plt.hist(a)
plt.show()
3.2 灰度图像直方图
对于灰度图像,其直方图计算是针对整个图像进行的。以下是计算并可视化灰度图像直方图的代码:
import numpy as np
import matplotlib.pyplot as plt
import cv2
img = cv2.imread('/home/pi/book/dataset/boat.512.tiff', 0)
plt.subplots_adjust(hspace=0.25, wspace=0.25)
plt.subplot(1, 2, 1)
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.title('Original Image')
plt.subplot(1, 2, 2)
hist, bins = np.histogram(img.ravel(), bins=256, range=(0, 255))
plt.bar(bins[:-1], hist)
plt.title('Histogram')
plt.show()
也可以使用
plt.hist()
函数替代
np.histogram()
和
plt.bar()
来计算和绘制直方图:
plt.hist(img.ravel(), bins=256, range=(0, 255))
3.3 彩色图像直方图
彩色图像的直方图需要分别计算每个颜色通道的直方图。以下是使用
plt.hist()
计算并可视化彩色图像各通道直方图的代码:
import numpy as np
import matplotlib.pyplot as plt
import cv2
img = cv2.imread('/home/pi/book/dataset/house.tiff', 1)
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
plt.subplots_adjust(hspace=0.5, wspace=0.25)
plt.subplot(2, 2, 1)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB), cmap='gray')
plt.axis('off')
plt.title('Original Image')
plt.subplot(2, 2, 2)
plt.hist(r.ravel(), bins=256, range=(0, 255), color='r')
plt.title('Red Histogram')
plt.subplot(2, 2, 3)
plt.hist(g.ravel(), bins=256, range=(0, 255), color='g')
plt.title('Green Histogram')
plt.subplot(2, 2, 4)
plt.hist(b.ravel(), bins=256, range=(0, 255), color='b')
plt.title('Blue Histogram')
plt.show()
此外,OpenCV提供了
cv2.calcHist()
函数来计算和可视化彩色图像各通道的直方图:
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('/home/pi/book/dataset/house.tiff', 1)
input = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
histr_RED = cv2.calcHist([input], [0], None, [256], [0, 255])
histr_GREEN = cv2.calcHist([input], [1], None, [256], [0, 255])
histr_BLUE = cv2.calcHist([input], [2], None, [256], [0, 255])
plt.subplot(221)
plt.imshow(input)
plt.title('Original Image')
plt.axis('off')
plt.subplot(222)
plt.plot(histr_RED, color='r')
plt.title('Red')
plt.xlim([0, 255])
plt.yticks([])
plt.subplot(223)
plt.plot(histr_GREEN, color='g')
plt.title('Green')
plt.xlim([0, 255])
plt.yticks([])
plt.subplot(224)
plt.plot(histr_BLUE, color='b')
plt.title('Blue')
plt.xlim([0, 255])
plt.yticks([])
plt.show()
3.4 直方图计算流程总结
| 图像类型 | 计算方法 | 代码示例 |
|---|---|---|
| 灰度图像 |
使用
np.histogram()
或
plt.hist()
|
hist, bins = np.histogram(img.ravel(), bins=256, range=(0, 255))
或
plt.hist(img.ravel(), bins=256, range=(0, 255))
|
| 彩色图像 |
分别计算各通道直方图,可使用
plt.hist()
或
cv2.calcHist()
|
plt.hist(r.ravel(), bins=256, range=(0, 255), color='r')
或
histr_RED = cv2.calcHist([input], [0], None, [256], [0, 255])
|
以下是直方图计算的流程图:
graph TD;
A[图像输入] --> B{图像类型};
B --> C[灰度图像];
B --> D[彩色图像];
C --> E[计算灰度直方图];
D --> F[分离各通道];
F --> G[计算各通道直方图];
E --> H[可视化灰度直方图];
G --> I[可视化各通道直方图];
综上所述,图像分割、深度估计和直方图计算是图像处理中的重要技术,它们在许多实际应用中都有广泛的用途,如网络图像传输、三维场景感知等。通过掌握这些技术的原理和实现方法,可以更好地处理和分析图像数据。
超级会员免费看
14万+

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



