13、图像分割、深度估计与直方图计算

图像分割、深度估计与直方图计算

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
  1. 安装完成后,在命令提示符中运行以下命令检查是否安装成功:
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[可视化各通道直方图];

综上所述,图像分割、深度估计和直方图计算是图像处理中的重要技术,它们在许多实际应用中都有广泛的用途,如网络图像传输、三维场景感知等。通过掌握这些技术的原理和实现方法,可以更好地处理和分析图像数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值