【世说新语】OpenCV4中联通组件分析算法的一个缺点

2024-01-08 12:07:52

学习《OpenCV应用开发:入门、进阶与工程化实践》一书

做真正的OpenCV开发者,从入门到入职,一步到位!

数据集

最近别人给了我一个生物数据分割的标注数据集,让我训练一下,发现这个数据集比较诡异,图像格式是tif的16位的浮点数,OpenCV读取过来要显示得先转换,然后它的Mask是PNG的带透明通道,最坑人的是Mask标记都是1、只有相互连接的对象标记才相互不同。官方给出的原始图像解析以后是这样:
在这里插入图片描述

OpenCV读取显示图像样本

OpenCV读取tif格式16位的图像在于imread的第二个参数,默认情况下会转换为BGR彩色八位字节的图像,如果这样就是一片漆黑;这里选择为-1表示不改变原图像的通道数据信息,这样就可以读取原始图像数据了,然后转换为32f的,再归一化到0~1之间,直接显示即可。代码如下:

import numpy as np
img = cv.imread("D:/11111.tif", -1)  # uint16
img_16 = img.astype(np.float32)
cv.normalize(img_16, img_16, 0, 1, cv.NORM_MINMAX)
img_16.astype(np.float32)
result = np.uint8(img_16*255)
cv.imwrite('D:/tensor_cv2.jpg', result)

在这里插入图片描述

OpenCV读取显示Mask图像

Mask图像是带透明通道的RGBA的图像,但是实际上所有的标注信息只存在于red通道中,所以读取以后,直接拆分通道,然后把red通道数据作为灰度图像处理,因为灰度值太低了,显示的时候我给扩大了点倍数,直接把灰度图像扔到联通组件扫描的函数中,然后就可以看到结果了。相关代码如下:

import numpy as np
img = cv.imread("D:/11111.png")  # uint16
bb, gg, rr = cv.split(img)
h, w, c = img.shape
print(img.shape, img.dtype)
numOfcons, labels = cv.connectedComponents(rr)

colors = []
for i in range(numOfcons):
    b = np.random.randint(0, 256)
    g = np.random.randint(0, 256)
    r = np.random.randint(0, 256)
    colors.append((b, g, r))

colors[0] = (0, 0, 0)
image = np.zeros((h, w, 3), dtype=np.uint8)
for row in range(h):
    for col in range(w):
        image[row, col] = colors[labels[row, col]]

cv.imshow("colored labels", image)
cv.imwrite("D:/opencv_labels.png", image)
cv.imshow("bgr", rr*100)
cv.waitKey(0)
cv.destroyAllWindows()

标记的Mask信息原图
在这里插入图片描述
基于联通组件查找以后的彩色显示(注意白色粘连)
在这里插入图片描述

对比与解决

对比之后发现,OpenCV中联通组件扫描以后把不同标签的样本粘连在一起了,这个是因为OpenCV寻找联通组件只分为两种值0为背景,非0就作为前景,不做灰度级别区分的联通域识别,所以导致了粘连。这个时候,只要用skimage库的函数来替换OpenCV的联通组件扫描就可以避免粘连了,因为skimage库的联通组件扫描支持独立标签分级。代码演示如下:

import skimage.io
import skimage.morphology

# Load one image after uncompressing masks.zip
gt = skimage.io.imread("D:/11111.png")

# Keep first channel only
gt = gt[:, :, 0]

# Label independent connected components
gt = skimage.morphology.label(gt)
colors = []
for i in range(150):
    b = np.random.randint(0, 256)
    g = np.random.randint(0, 256)
    r = np.random.randint(0, 256)
    colors.append((b, g, r))
colors[0] = (0, 0, 0)
h, w = gt.shape
image = np.zeros((h, w, 3), dtype=np.uint8)
for row in range(h):
    for col in range(w):
        image[row, col] = colors[gt[row, col]]

# Display image or use as needed
cv.imshow("colored labels", image)
cv.imwrite("D:/labels.png", image)
cv.waitKey(0)
cv.destroyAllWindows()

运行结果对比 - 可以发现白色区域没有粘连,成功分割!
在这里插入图片描述
希望OpenCV迟早有一天可以支持这种分级的区域联通组件扫描算法。

好书推荐

《OpenCV应用开发:入门、进阶与工程化实践》 全书共计16个章节,重点聚焦OpenCV开发常用模块详解与工程化开发实践,提升OpenCV应用开发能力,助力读者成为OpenCV开发者,同时包含深度学习模型训练与部署加速等知识,帮助OpenCV开发者进一步拓展技能地图,满足工业项目落地所需技能提升。购买请点链接:
《OpenCV4 应用开发-入门、进阶与工程化实践》

学习课程有专属答疑群,负责贴身答疑解惑

读者专属QQ群 :657875553
进群暗号:OpenCV4读者

文章来源:https://blog.csdn.net/jia20003/article/details/135451671
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。