【CV实践】之零基础入门语义分割---Task1赛题理解

参加本次活动的目标:通过本次赛题可以引导大家熟练掌握语义分割任务的定义具体的解题流程和相应的模型并掌握语义分割任务的发展

0x10:赛题理解与 baseline

学习主题:理解赛题内容解题流程
学习内容赛题理解、数据读取、比赛 baseline 构建
学习成果:比赛 baseline 提交

0x20:赛题数据分析

0x21:赛题数据

本赛题使用航拍数据,需要参赛选手完成地表建筑物识别,将地表航拍图像素划分为有建筑物和无建筑物两类,还需要识别图片中的地表建筑具体像素位置

如下图,左边为原始航拍图,右边为对应的建筑物标注。
在这里插入图片描述

0x22:数据标签

赛题为语义分割任务,因此具体的标签为图像像素类别

在赛题数据中像素属于 2 类(无建筑物和有建筑物),因此标签为有建筑物的像素

赛题原始图片为 jpg 格式,标签为 RLE 编码的字符串
RLE 全称(run-length encoding),翻译为游程编码或行程长度编码,对连续的黑、白像素数以不同的码字进行编码。RLE 是一种简单的非破坏性资料压缩法,经常用在在语义分割比赛中对标签进行编码

RLE编码的原理:名为行程长度压缩算法,也是最早最简单无损数据压缩算法。
RLE算法的基本思路是把数据按照线性序列分成两种情况:一种是连续的重复数据块,另一种是连续的不重复数据块。对于第一种情况,对连续的重复数据块进行压缩,压缩方法就是用一个表示块数的属性加上一个数据块代表原来连续的若干块数据。对于第二种情况,RLE算法有两种处理方法,一种处理方法是用和第一种情况一样的方法处理连续的不重复数据块,仅仅是表示块数的属性总是1;另一种处理方法是不对数据进行任何处理,直接将原始数据作为压缩后的数据。
下面代码是对基本思路进行了优化,使其更适合大数据的压缩,具体思路为:首先设置搜索起始位置(一开始就是原始数据的第一个字节),每次搜索是从起始位置开始向后搜索比较数据,根据搜索比较结果:一种情况就是后面数据重复且数据长度超过2,则设置连续重复数据的标志,然后继续向后查找,直到找到第一个与之不相同的数据为止,将这个位置记为下次搜索的起始位置,根据位置差计算重复次数,连重复标志和重复次数以及原始数据一起写入压缩数据;另一种情况是后面的数据都没有连续重复的,则继续次昂后查找,直到找到连续重复的数据,然后设置不重复数据标志,将新位置几位下次搜索的起始位置,最后将标志字节写入压缩数据并将原始数据复制到压缩数据。

RLE与图片之间的转化coding

import numpy as np
import pandas as pd
import cv2

# 将图片编码为rle格式
def rle_encode(im):
    '''
    :param im: numpy array,1 - mask, 0 - background
    :return: run length as string formated(格式化的)
    '''

    # pixel:像素点
    pixels = im.flatten(order='F') # 按列排序降成一维
    pixels = np.concatenate([[0], pixels, [0]]) # 前后加个0
    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1 # 寻找索引位置不对应的索引的第一行
    runs[1::2] -= runs[::2]
    return ' '.join(str(x) for x in runs)


# 将rle格式进行解码为图片
def rle_decode(mask_rle, shape=(512, 512)):
    '''
    :param mask_rle: run-length as string formated (state length)
    :param shape: (height, width) of array to return
    :return: numpy array, 1 - mask, 0 - background
    '''
    s = mask_rle.split()
    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]
    starts -= 1
    ends = starts + lengths
    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)
    for lo, hi in zip(starts, ends):
        img[lo:hi] = 1
    return img.reshape(shape, order='F')

0x23:读取数据

import opencv as cv
import pandas as pd

# train_mask = ['name', 'mask']:图片名称,图片的rle码
train_mask = pd.read_csv('train_mask.csv', sep='\t', names=['name', 'mask']) # size:30000

# 读取一张图片
img = cv2.imread('train/' + train_mask['name'].iloc[0]) # 第一张图片对应的像素点矩阵

mask = rle_decode(train_mask['mask'].iloc[0]) # rle解码
print(rle_encode(mask) == train_mask['mask'].iloc[0]) # True

0x24:可视化图片

data = Image.fromarray(mask * 255) # 因为数据是0和1,需要乘以255才能显示出黑白
data.show()

在这里插入图片描述

0x25:统计所有图片钟没有任何建筑的图片数量


res = 0
for img in train_mask['mask'].iloc[:]:
    if img != img: # {float}nan:该数据表示0,用这种方法可以比较大小,
        res += 1
print(res) # 5204

0x26:统计账房像素占所有像素的比例


res = 0
for img in train_mask['mask'].iloc[:]:
    if img == img:
        mask = rle_decode(img)
        res += np.sum(np.reshape(mask, (mask.size,)))

print(res) #  1235338412  总像素:7864320000

0x27:统计所有图片中建筑物区域平均区域大小

ans = []
for img in train_mask['mask'].iloc[:]:
    if img == img:
        mask = rle_decode(img)
        ans.append(np.sum(np.reshape(mask, (mask.size,))) / (512 * 512))
    else:
        ans.append(0)

print(ans)

参考文章

flatten()函数用法
cancatenate()函数用法
where()函数用法
float的nan处理方法
RLE算法及其优化

猜你喜欢

转载自blog.csdn.net/qq_45914759/article/details/113841431