一、项目代码如下:
import numpy as np
import PIL
import matplotlib.pyplot as plt
from skimage.segmentation import mark_boundaries
from fast_slic import Slic
from PIL import Image
#进行超像素分割
with Image.open(r"C:\Users\26277\Desktop\before.jpg") as f:
image = np.array(f)
# import cv2; image = cv2.cvtColor(image, cv2.COLOR_RGB2LAB) # You can convert the image to CIELAB space if you need.
slic = Slic(num_components=3000, compactness=10)
assignment = slic.iterate(image) # Cluster Map
print(assignment)
print(slic.slic_model.clusters) # The cluster information of superpixels.`
#输出超像素分割的结果
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_title("Superpixels -- %d segments" % (3000))
ax.imshow(mark_boundaries(image, assignment))
plt.axis("off")
plt.savefig(r"C:\Users\26277\Desktop\after.jpg")
plt.show()
二、代码运行结果如下:
三、超像素块进一步分类的方法(chatGPT生成)
# 导入相关的库和模块
import torch
import torchvision
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
# 加载预训练好的Mask R-CNN模型
model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)
# 设置模型为评估模式
model.eval()
# 设置设备为CPU或GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 将模型移动到设备上
model.to(device)
# 定义一个函数来处理每个超像素块图像,并将其输入到模型中
def process_superpixel_image(image_path):
# 读取图像文件并转换为RGB格式
image = Image.open(image_path).convert('RGB')
# 将图像转换为张量,并将其缩放到256x256大小
image_tensor = torchvision.transforms.functional.resize(torchvision.transforms.functional.to_tensor(image), (256, 256))
# 将张量划分为16x16大小的小块,并将每个小块作为一个RoI输入到模型中
rois = []
for i in range(0, 256, 16):
for j in range(0, 256, 16):
rois.append([i, j, i + 16, j + 16])
rois = torch.tensor(rois, dtype=torch.float32).to(device)
# 获取模型输出中每个RoI上的类别标签、边界框位置和掩码值,并将它们存储在列表或字典中
output = model([image_tensor.to(device)], [rois])
labels = output[0]['labels'].cpu().numpy()
boxes = output[0]['boxes'].cpu().numpy()
masks = output[0]['masks'].cpu().numpy()
# 对于每个类别标签,找出对应的超像素块,并将其与原始图像合并成一个新图像
new_image = np.array(image)
for label in np.unique(labels):
# 生成一个随机的颜色
color = np.random.randint(0, 255, 3)
# 获取该类别标签对应的RoI的索引
indices = np.where(labels == label)[0]
# 对于每个RoI,将其对应的掩码和边界框绘制到新图像上
for index in indices:
mask = masks[index, 0]
box = boxes[index]
# 将掩码转换为二值图像,并将其缩放到原始大小
mask = Image.fromarray((mask > 0.5).astype(np.uint8) * 255)
mask = mask.resize((image.width, image.height), Image.NEAREST)
# 将边界框转换为整数坐标,并将其缩放到原始大小
box = box.astype(np.int32)
box = box * image.width // 256
# 将掩码和边界框绘制到新图像上
new_image[mask > 0] = color
new_image[box[1]:box[3], box[0], :] = color
new_image[box[1]:box[3], box[2], :] = color
new_image[box[1], box[0]:box[2], :] = color
new_image[box[3], box[0]:box[2], :] = color
# 将新图像转换回原始大小,并保存或显示出来
new_image = Image.fromarray(new_image)
new_image = new_image.resize((image.width, image.height), Image.NEAREST)
new_image.save('output.jpg')
new_image.show()
# 调用函数来处理一个超像素块图像
process_superpixel_image('superpixel.jpg')
四、加强版代码如下
# coding=UTF-8
import numpy as np
import PIL
import matplotlib.pyplot as plt
import cv2
from skimage.segmentation import mark_boundaries
from skimage import io
from fast_slic import Slic
from PIL import Image
# 进行超像素分割
with Image.open(r"C:\Users\26277\Desktop\before.jpg") as f:
image = np.array(f)
# # 此段代码用于将图像变换到希尔伯特空间
# image = cv2.cvtColor(image, cv2.COLOR_RGB2LAB)
# print('***0',image)
# fig = plt.figure()
# ax = fig.add_subplot(1, 1, 1)
# ax.imshow(image)
# plt.show()
slic = Slic(num_components=10, compactness=10)
assignment = slic.iterate(image) # Cluster Map 得到的是图像中每个像素的聚类标签
print('***1', assignment) # ’***1‘是用于调试的标识符,无意义
print(slic.slic_model.clusters) # The cluster information of superpixels.`
# 输出超像素分割的结果
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_title("Superpixels -- %d segments" % (10))
ax.imshow(mark_boundaries(image, assignment))
plt.axis("off")
plt.savefig(r"C:\Users\26277\Desktop\after.jpg")
plt.show()
# 逐个输出超像素的分割结果
maxn = max(assignment.reshape(int(assignment.shape[0] * assignment.shape[1]), ))
for i in range(1, maxn + 1):
a = np.array(assignment == i) # 创建的是布尔类型的矩阵,由于原图像为RGB三通道,故而构建三维矩阵
height, width = a.shape
aaa = np.zeros((height, width, 3), dtype=np.uint8)
aaa[:, :, 0] = a
aaa[:, :, 1] = a
aaa[:, :, 2] = a
b = image * aaa
# 这是从一个更大的数组中提取子数组的常用的方法, 代码将创建一个 numpy 数组 c,其中包含 w 和 h 范围内的 b 元素。(也就是将c从b中切割出来)
w, h = [], []
for x in range(b.shape[0]):
for y in range(b.shape[1]):
if b[x][y][0] != 0:
w.append(x)
h.append(y)
c = b[min(w):max(w), min(h):max(h)]
# 下列代码用于将二维矩阵拓展为三维矩阵,其中axis表示在第三个维度(深度)上将矩阵进行拼接
# 由于上述代码处理的矩阵为RGB通道上的三维矩阵,因此不需要进行拼接扩充
# d = c.reshape(c.shape[0], c.shape[1], 1)
# e = np.concatenate((d, d), axis=2)
# e = np.concatenate((e, d), axis=2)
img2 = Image.fromarray(np.uint8(c))
img2.save('C:\\Users\\26277\\Desktop\\' + str(i) + '.png')
print('已保存第' + str(i) + '张图片')
# 逐个输出超像素块的掩膜
for (i, segVal) in enumerate(np.unique(assignment)): # z使用enumerate和np.unique函数,得到assignment数组中的唯一值和它们的索引
# construct a mask for the segment
print("[x] inspecting assignment {}, for {}".format(i, segVal))
mask = np.zeros(image.shape[:2], dtype="uint8")
mask[assignment == segVal] = 255
# show the masked region
cv2.imshow("Mask", mask)
cv2.imshow("Applied", np.multiply(image, cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) > 0))
cv2.waitKey(0)
# 将输出的超像素块按照一定的特征进行聚类
运行结果如下:
整体分割如下:
掩膜如下:
超像素块如下:
五、其他体素分割算法
根据我搜索到的信息,我为您总结了以下几种常用的超像素块分类算法的优缺点:
1.SLIC(Simple Linear Iterative Clustering):
这是一种基于图论的分割算法,它从预分割核开始定义核的粗略中心和大小,通过笛卡尔坐标系中的椭圆状边界映射到极坐标系统中的线,并利用动态规划和确保最佳闭合轮廓的迭代方法来识别所构建图中的全局最佳路径。
优点:参数简单,只需要一个参数K(超像素的个数),生成的超像素大小一致,整齐紧凑,分割效果较高2。
缺点:超像素个数要人为确定,很大程度上依赖于经验值,会直接影响到分割效果。
2.SEEDS(Simple Efficient Iterative Decimation of Segments):
这也是一种基于图论的分割算法,它把图像平均分割成很多矩形区域,初始超像素即为这些矩形。每一步迭代,超像素的边缘不断变化,直到汇合。
优点:速度快,内存占用低,可以处理任意大小和形状的输入图像,可以实现实时分割。
缺点:分割结果受到初始化的影响,可能出现不连续或过分割的情况,需要后处理来增强连通性
3.LSC(Local Scale Clustering):
这是一种基于梯度上升的分割算法,它从一个相对比较粗糙的聚类开始计算,通过梯度上升不断地迭代修改聚类,直到满足特定的收敛标准形成超像素。
优点:分割结果更加贴合图像边缘,可以处理不同尺度和复杂度的图像,可以实现多尺度分割。
缺点:计算复杂度较高,需要更多的时间和内存,对于噪声和纹理较多的图像可能表现不佳。