OpenMMLab-AI实战营第二期——相关3. RGB语义分割标注图像转为Gray格式的mask

news2025/1/10 3:23:22

文章目录

  • 1. 转换代码
    • 1.1 查看原始图像
    • 1.2 转换
    • 1.3 cv::IMREAD_GRAYSCALE与CV_BGR2GRAY结果不一致
      • 1.3.1 现象描述
      • 1.3.2 原因
      • 1.3.3 推荐做法
    • 1.4 CV_BGR2GRAY和CV_RGB2GRAY不一致
  • 2. macOS上查看mask(使用默认的预览)

1. 转换代码

  • 找到了一个语义分割的数据集,但是标注图像是RGB格式的,需要转为mask。
  • 受损花朵分割(280MB):Accurate damaged flower shapes/segmentation

1.1 查看原始图像

import matplotlib.pyplot as plt
import cv2
%matplotlib ipympl

mask = cv2.imread("datasets/05-damaged-01/mask/mask00000001.png")
plt.imshow(mask[:,:,::-1])

在这里插入图片描述
结论一:大致可以看到,给出的原始标记图像是RGB格式的,三通道。


另外由于数据集没有给出标签信息,需要自己分析这个图像上一共有多少种颜色,可以使用np.unique函数来完成这个操作,参考stackoverflow-numpy: unique list of colors in the image

import numpy as np
np.unique(mask.reshape(-1, mask.shape[2]), axis=0,return_counts=True)
>(array([[  0,   0,   0],
        [  4,   0,  67],
        [ 12,   0, 243],
        [ 13,   0, 252],
        [ 13,   0, 255]], dtype=uint8),
 array([813467,    322,      1,    336, 107474]))

# 或者用counter方法
from collections import Counter
Counter([tuple(colors) for i in mask for colors in i])

>Counter({(0, 0, 0): 813467,
         (4, 0, 67): 322,
         (13, 0, 252): 336,
         (13, 0, 255): 107474,
         (12, 0, 243): 1})

结论2:可以看到其实频率最高的两类就是背景的黑色和花的红色,其他3种颜色其实是边缘,这在之后可以看到。


将原图转为灰度图,构建映射词典,查看灰度图的语义mask

gray_img = cv2.cvtColor(mask, cv2.COLOR_BGRA2GRAY)
print(np.unique(gray_img,return_counts=True))
>((array([ 0, 20, 74, 77, 78], dtype=uint8),
  array([813467,    322,      1,    336, 107474])))

uniqueRs=np.unique(gray_img)
indexMapDict = {}
# 这里一开始是默认每个颜色按顺序对应index
for i in range(len(uniqueRs)):
    indexMapDict[uniqueRs[i]]=i

# 构建相同大小的数组
pngArray = np.zeros_like(gray_img)
height = gray_img.shape[0]
width = gray_img.shape[1]

for i in range(height):
    for j in range(width):
        grayLevel = gray_img[i,j]
        pngArray[i,j]=indexMapDict[grayLevel]
np.unique(pngArray,return_counts=True)
>(array([0, 1, 2, 3, 4], dtype=uint8),
 array([813467,    322,      1,    336, 107474])) # 频率和上面是一致的

# 可视化看一下结果
import matplotlib
# 5种颜色,所以建立一个5类的colormap
flower_cmap = matplotlib.colors.ListedColormap(["black", "white","yellow","white","red"],N=5)

plt.figure()
plt.imshow(pngArray,cmap=flower_cmap)

在这里插入图片描述
结论3:除了红色和黑色,显示为白色和黄色的其实就是刚刚出现频率比较低的那三种颜色值,可以看出来,是花的边缘(与背景挨着的地方)。

  • 可能是使用的标注软件或者是利用了一定的视频追踪标注技术导致的
  • 因此实际使用的时候,只考虑背景类是0,前景类是1

参考语义分割中数据样本的整理标注及调色板代码

1.2 转换

整体思路:

  1. RGB图像转为灰度图,这样颜色的三通道就变成一个数值了,方便操作
  2. 用np.unique找出颜色种类
  3. 构建映射dict,出现频率最高的颜色就是背景(0),次高的是前景(1),其余是花的边缘,这里暂时赋值为0
  4. 构建对应的numpy矩阵并存储

具体代码:

import os
import cv2
import numpy as np

raw_mask_base = "datasets/05-damaged-01/mask"
save_mask_base = "datasets/05-damaged-01/maskLabel"
os.makedirs(save_mask_base,exist_ok=True)

maskList = os.listdir(raw_mask_base)

for imgName in maskList:
    imgPath = os.path.join(raw_mask_base,imgName)
    savePath = os.path.join(save_mask_base,imgName.split(".")[0]+str('.png'))
	
	# 1. 转为灰度图
    mask = cv2.imread(imgPath)
    gray_img = cv2.cvtColor(mask, cv2.COLOR_BGRA2GRAY)
    
    # 2. 找出颜色种类
    uniqueRs,index,count=np.unique(gray_img,return_inverse=True,return_counts=True)
    
    # 3. 构建dict
    mapDict = {}
    indexSort=np.argsort(count)
    for i in indexSort[:-2]:
        mapDict[uniqueRs[i]]=0        
    mapDict[uniqueRs[indexSort[-1]]]=0
    mapDict[uniqueRs[indexSort[-2]]]=1
    
    # 4. 映射并报错图像
    try:
        pngArray = np.array([mapDict[x] for x in uniqueRs])[index].reshape(gray_img.shape)
        cv2.imwrite(savePath, pngArray)
    except Exception as e:
        print(f'处理出现问题:{e},文件是 {imgName}')
  1. 处理过程中,发现不是所有图像的颜色种类都是5种,因此在构建mapDict时,只对频率最高的两类做明确处理,其他颜色类别都作为背景
  2. 在使用numpy进行dict映射时,发现上述方法是最快的,相对于下面这种纯纯for循环,能快100X以上。
     for i in range(height):
         for j in range(width):
             grayLevel = gray_img[i,j]
             pngArray[i,j]=mapDict[grayLevel] 
    
    详见:Translate every element in numpy array according to key
  3. 使用imwrite保存单通道灰度图时,需要保证值的范围是0-255的整数,详见:Saving GRAYSCALE .png image with cv2.imwrite() not working

1.3 cv::IMREAD_GRAYSCALE与CV_BGR2GRAY结果不一致

1.3.1 现象描述

"""
上面代码采取了
"""
mask = cv2.imread(imgPath)
gray_img = cv2.cvtColor(mask, cv2.COLOR_BGRA2GRAY)

"""
而不是直接一步到位
"""
gray_img = cv2.imread(imgPath,cv2.IMREAD_GRAYSCALE)

这是因为虽然上述两种方式都可以用来进行灰度图的转换,但是结果会有些差异,见下面的示例:

# 1
gray_image = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
np.unique(gray_image)
>array([ 0, 20, 74, 77, 78], dtype=uint8)

# 3
gray_image = cv2.imread("datasets/05-damaged-01/mask/mask00000001.png",cv2.IMREAD_GRAYSCALE)
np.unique(gray_image)
>array([ 0, 20, 74, 76, 77], dtype=uint8)

可以看到,上面是77和78,下面是76和78。

1.3.2 原因

在opencv-imread的文档里,提到:

在这里插入图片描述
大致意思就是:

  • 当使用IMREAD_GRAYSCALE时,直接调用了当前平台可以使用的编码解码器(codec)来进行灰度转换,所以结果会和cvtColor()有些不同。
  • 对于Windows和macOS系统,默认使用(libjpeg,libpng,libtiff以及libjasper)这些编解码器对opencv图像进行处理,这也是为什么Opencv能处理这些格式图像的原因。

另外,根据Opencv - Grayscale mode Vs gray color conversion

  • cvtColor() 是一种Opencv的实现,同时在所有平台下都会保持一致(本质是对数组进行处理)
  • 而使用imread()来把彩色图转为灰度图时,则会受制于imread()函数在特定平台下的具体实现,即上面说的编解码器(要和存储系统打交道,浮点数的规定等会有差异)
  • 所以问题其实来源于:为什么要用一个读图的函数去完成色彩转换?

感谢OpenCV 中 imread cvtColor cv::IMREAD_GRAYSCALE与CV_BGR2GRAY得到灰度图不一致问题,下面是搬运的:请去原博点赞。

在opencv3.0中,

  • cv::IMREAD_COLOR 解析jpg时候,由cv::JpegDecoder解码得到一个RGB图像,然后由icvCvt_RGB2BGR_8u_C3R() 函数交换R和B空间,得到BGR格式的彩色图。
  • cv::IMREAD_GRAYSCALE 这个图像由cv::JpegDecoder解码得到一个灰度图,所有的颜色转换和其他预处理或后处理等相关细节都是由libjpeg处理的,最后,将解压缩的数据复制到给定cv::Mat的内部缓冲区中。因此,在cv::IMREAD_GRAYSCALE中没有调用opencv中的函数cv::cvtColor来进行颜色转换。

1.3.3 推荐做法

在这里插入图片描述

  • 如果原图是彩色图,则imread之后再用cvtColor转为灰度图
  • 如果原图本身就是灰度图,则imread的时候添加cv2.IMREAD_GRAYSCALE参数读取灰度图

1.4 CV_BGR2GRAY和CV_RGB2GRAY不一致

# 1
gray_image = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
np.unique(gray_image)
>array([ 0, 20, 74, 77, 78], dtype=uint8)

# 2
gray_image = cv2.cvtColor(mask,cv2.COLOR_RGB2GRAY)
np.unique(gray_image)
>array([ 0,  9, 31, 33], dtype=uint8)

cv2.COLOR_RGB2GRAYcv2.COLOR_BGR2GRAY对同一图像处理,结果不同
根据Why would cv2.COLOR_RGB2GRAY and cv2.COLOR_BGR2GRAY give different results?可知:

  • RGB2GRAY过程中,三个通道不是平均的,是不同的权重系数,所以对同一个图分别调用cv2.COLOR_RGB2GRAYcv2.COLOR_BGR2GRAY结果会不一样,这个很好理解。
  • Opencv中关于RGB→GRAY图像的转换公式,详见文档:https://docs.opencv.org/4.x/de/d25/imgproc_color_conversions.html#color_convert_rgb_gray documentation

2. macOS上查看mask(使用默认的预览)

常规的软件打开这种灰度图是什么都看不见的,即便是matplotlib这种程序读图,如果不设置合适的cmap,也看不到东西。

其实稍微设置一下就可以看到了

在这里插入图片描述
点击①标记->②滑块->③自动色阶,就可以看到:
在这里插入图片描述

  • 就可以看到了(这样操作并不会影响图像的值,是靠颜色描述文件来正确显示这种灰度图像的)
  • 其实照片里的编辑以及色彩同步实用工具的灰度系数也可以看到,只是用起来相对麻烦,这个是目前最简单的
  • 另外,仔细看花的边缘也有点像原始标注图一样的杂色,截图不是很清晰

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/701673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rc表格卡方检验

一、案例介绍 某医院用三种穴位针刺治疗急性腰扭伤,现在想比较三种穴位针刺效果有无差别,结果汇总如下表: 二、问题分析 本案例想比较三种穴位针刺效果有无差别,可以使用RxC卡方检验进行分析。 通常情况下,共有三种…

uniapp项目 封装一个饼图组件 并且修改显示项的排列方式

需求如下: 真实数据渲染后的完成效果如下: 记录一下代码: <template><view><view style"height: 600rpx;"><l-echart ref"chart" finished"init"></l-echart></view></view> </template><…

【面试】一文知晓---拦截器和过滤器的区别

目录 背景关系图 拦截器和过滤器的区别实操1.过滤器1.1HttpServletRequestWrapper1.2 OncePerRequestFilter1.3 配置 2.拦截器2.1登录拦截2.2配置 3.监听器 三、注意1.静态资源问题2.登录拦截ajax重定向 总结 背景 关系图 然后具体执行流程如下&#xff1a; 拦截器和过滤器的区…

IDEA创建一个Servlet项目(tomcat10)

一、创建maven项目 org.apache.maven.archetypes:maven-archetype-webapp 二、增加Servlet依赖 tomcat9及以前依赖 <!--加入servlet依赖&#xff08;servlet的jar&#xff09;--><dependency><groupId>javax.servlet</groupId><artifactId>ja…

MoblieNet

论文信息 论文名称&#xff1a;MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications 论文地址&#xff1a;https://arxiv.org/abs/1704.04861 研究背景和研究意义 之前的网络都倾向于将网络做得又大又深&#xff0c;并且不考虑网络的速度&…

测试CefSharp.WinForms的基本用法

微信公众号“dotNET全栈开发”的文章《C#使用CefSharp内嵌网页-并给出C#与JS的交互示例》介绍了CefSharp的基本用法。CefSharp支持在.net程序中内置Chromium&#xff0c;它是Chromium Embedded Framework (CEF) 的轻量化封装。   CefSharp面向Winform、wpf等提供对应的NuGet包…

SpringBoot初始化接口CommandLineRunner

CommandLineRunner的使用 接口定义使用执行顺序使用 Order 注解实现Orderd接口排序总结 接口定义 Spring官方给出的接口定义 package org.springframework.boot;FunctionalInterface public interface CommandLineRunner {void run(String... args) throws Exception; }在 Sp…

卡方检验之多重比较

一、案例介绍 某医师研究物理疗法、药物治疗和外用膏药3种疗法治疗周围性面神经麻痹的疗效&#xff0c;通过整体卡方检验已经得知3种疗法有效率的差异有统计学意义&#xff08;χ221.0377&#xff0c;p0.000&#xff09;的结论。现在想进一步知道&#xff0c;具体是哪两种疗法…

Android后台应用开启前台服务---android8到android12梳理

1、Android 8.0 异常报错 在Android 8.0 系统中&#xff0c;处于后台的应用想要开启前台服务&#xff0c;必须满足两点&#xff1a; 在Activity中调用startForegroundService()方法所调起的Service必须执行startForeground(int id, Notification notification)方法&#xff0…

计算几何——gitf-wrapping算法

几何中的"gift-wrapping"算法&#xff0c;又称为"Jarvis算法"&#xff0c;是一种用于计算凸包(convex hull)的方法。下面我将为你解释一下该算法的步骤&#xff1a; 1. 找到具有最小x坐标的点P&#xff0c;我们将其作为凸包的起点。 2. 将P标记为当前点&a…

doker安装RabbitMQ以及用java连接

目录 doker安装&#xff1a; RabitMq安装&#xff1a; java链接 doker安装&#xff1a; 参考链接&#xff08;非常详细&#xff09;&#xff1a; docker安装以及部署_docker bu shuminio_春风与麋鹿的博客-CSDN博客 安装好后开启doker //启动docker服务 systemctl start do…

PromQL讲解与实战操作

PromQL讲解与实战操作 一、PromQL 介绍 PromQL&#xff08;Prometheus Query Language&#xff09;是 Prometheus 内置的数据查询语言&#xff0c;它能实现对事件序列数据的查 询、聚合、逻辑运算等。它并且被广泛应用在 Prometheus 的日常应用当中&#xff0c;包括对数据查询…

在Linux服务器上简单部署一个Python项目

一、在对应的服务器上检查有无Python环境 大部分Linux系统都是自带了Python环境的&#xff0c;查看是否具备Python的运行环境&#xff0c;可以通过命令Python --version 或者 Python3 --version 查看。如果你的项目需要Python3的环境&#xff0c;而系统又没有&#xff0c;则需要…

Linux 开启 swap 分区详细教程

故事背景&#xff1a; 哥们云机器内存资源不足&#xff0c;搞个 kafka eagle 监控&#xff0c;刚跑起来就卡死了&#xff0c;就很无语&#xff0c;哥们忙活&#xff0c;算了直接开搞&#xff0c;内存不够&#xff0c;硬盘来凑&#xff0c;拿着硬盘去做swap分区&#xff0c;也能…

JavaEE-SpringMVC-云借阅图书管理系统(包含源码、数据库sql文件、报告)

文章目录 前言云借阅系统功能结构图云借阅系统结构层次云借阅系统项目文件组织结构开发环境具体操作1. Maven仓库修改2. MySQL数据库配置文件3. Tomcat运行截图 总结 前言 参考借鉴黑马程序员书籍&#xff1b;和老师上课讲解的代码和PPT。核心代码由自己编写完成&#xff0c;核…

【夜深人静学数据结构与算法】回溯算法

目录 前言&#xff1a; 回溯算法&#xff1a; 回溯法的常见应用: 回溯法的模板: 回溯法的图解&#xff1a;​ 案例&#xff1a; 77. 组合 - 力扣&#xff08;LeetCode&#xff09; 总结&#xff1a; 前言&#xff1a; 回溯算法是一个比较抽象的算法&#xff0c;因此我们…

JavaScript中的面向对象

面向对象编程是一种编程范式。 面向对象。何为对象&#xff1f; 复习一下&#xff1a; JavaScript中的数据类型分为&#xff1a; 原始类型&#xff1a;数值型&#xff0c;字符串型&#xff0c;布尔型、ES6新增的symbol 特殊类型&#xff1a;undefined型&#xff0c;null型 组合…

chatgpt赋能python:隐藏输入:保护密码和敏感数据的有效方法

隐藏输入&#xff1a;保护密码和敏感数据的有效方法 在今天的数字时代&#xff0c;网络安全成为了无所不在的话题。密码和敏感数据的泄漏是任何人都不想看到的结果。因此&#xff0c;在这种情况下&#xff0c;隐藏输入成为了保护我们的密码和敏感数据的有效方法。 Python是数…

el-date-picker设置右侧显示图标

<template><div><el-form ref"form" label-width"100px"><el-form-item label"日期&#xff1a;" class"date_box"><el-date-picker v-model"time" type"date" :clearable"true&…

【GaussDB分布式特性】

GaussDB分布式特性 实验环境一、分布式架构二、分片和分区 实验环境 华为云GaussDB云数据库&#xff0c;规则如下&#xff1a; 集群拓扑结构&#xff0c;如下&#xff1a; 一、分布式架构 逻辑架构 常用部署方式 部署说明&#xff1a; 1.双AZ采用带第三方仲裁方式部署&am…