Segmentaion標簽的三種表示:poly、mask、rle

Segmentaion標簽的三種表示:poly、mask、rle

不同于圖像分類這樣比較簡單直接的計算機視覺任務,圖像分割任務(又分為語義分割、實例分割、全景分割)的標簽形式稍為復雜。在分割任務中,我們需要在像素級上表達的是一張圖的哪些區域是哪個類別。

多邊形坐標Polygon

第一感下,要表達圖像中某個區域是什么類別,只要這個區域“圈起來”,并給它一個標簽就好了。的確,用多邊形來將目標圈出來確實是最符合我們視覺上對圖像的感知的方法。并且在很多數據集的標注過程中,來自人類的手工標注也是通過給出一個一個點的坐標,從而形成一個閉合的多邊形區域,從而實現對圖像中目標物體的分割。

我們通過 OpenCV 的 polylines 函數來將這種做法畫出來看一下:

import numpy as np
import cv2
cat_poly = [[390.56410256410254, 1134.179487179487], # ...[407.2307692307692, 1158.5384615384614]]dog_poly = [[794.4102564102564, 635.4615384615385], # ...[780.3076923076923, 531.6153846153846]]img = cv2.imread("cat-dog.jpeg")cat_points = np.array(cat_poly, dtype=np.int32)
cv2.polylines(img, [cat_points], True, (255, 0, 0), 3)
dog_points  = np.array(dog_poly, dtype=np.int32)
cv2.polylines(img, [dog_points], True, (0, 0, 255), 3)cv2.imshow("window", img)
cv2.waitKey(0)

這里的數據 cat_poly 是一個 n×2n\times 2n×2 的二維數組,表示多邊形框的 nnn 個坐標,即 [[x1,y1],[x2,y2],...[xn,yn]][[x_1,y_1],[x_2,y_2],...[x_n,y_n]][[x1?,y1?],[x2?,y2?],...[xn?,yn?]]。畫出來大概就是下面這樣子:

在這里插入圖片描述

這樣的確可以劃分出我們想要的區域,但是沒有體現出“區域”的概念,即在整個多邊形框內,都是貓/狗區域。

掩膜區域Mask

為了體現出區域的概念,我們可以將整個區域展示出來,這里用到 fillPoly 函數,就是下面這樣大家常常見到的樣子:

img = cv2.imread("cat-dog.jpeg")dog_poly = [# ...
]
cat_poly = [# ...
]cat_points = np.array(cat_poly, dtype=np.int32)
dog_points = np.array(dog_poly, dtype=np.int32)zeros = np.zeros((img.shape), dtype=np.uint8)
mask = cv2.fillPoly(zeros, [cat_points], color=(255, 0, 0))
mask = cv2.fillPoly(zeros, [dog_points], color=(0, 0, 255))
mask_img = 0.5 * mask + imgcv2.imshow("window", mask_img)
cv2.waitKey(0)

在這里插入圖片描述

在模型的設計與訓練中,我們有時最后輸出的就是與原圖尺寸相同二值的 mask 圖,其中 1 的地方表示該位置有某一類物體,0 表示沒有該類物體。因此我們通常要將上面的多邊形標注轉為二值的 mask 圖來作為直接用來計算損失的標簽。由多邊形標簽轉為掩膜標簽的代碼如下:

def poly2mask(points, width, height):mask = np.zeros((width, height), dtype=np.int32)obj = np.array([points], dtype=np.int32)cv2.fillPoly(mask, obj, 1)return mask

這里的 points 就是上面我們的 cat_poly 這樣的二維數組的多邊形數據。

就是將有該類物體的地方置為1,其他為0,有些區別會在語義分割和實例分割中有所不同,可能是某一類有一個mask,也可能是每一個實例一個 mask。大家按需調整即可。

將上述貓狗的例子轉換后可視化如下:

width, height = img.shape[: 2]
cat_mask = poly2mask(cat_poly, width, height)
dog_mask = poly2mask(dog_poly, width, height)

注意,在做可視化時建議將上面的 poly2mask 函數中的 1 改為 255。因為灰度值為 1 也基本是黑的,但是在訓練中為 1 即可。

在這里插入圖片描述

在這里插入圖片描述

從掩膜 mask 轉換回多邊形 poly 的函數會比較復雜,在這個過程中可能會有標簽精度的損失。我們用越多的坐標點來表示掩膜自然也就越精確,極端情況下,將掩膜邊緣處的每一個像素都連接起來,這時不會有精度的損失。但我們通常不會這樣做。

這里給出轉換的函數,該函數會返回一個數組,數組的長度就是 mask 中閉合區域的個數,數組的每個元素是一組坐標:[x1,y1,x2,y2,...,xn,yn][x_1,y_1,x_2,y_2,...,x_n,y_n][x1?,y1?,x2?,y2?,...,xn?,yn?] ,注意這里的坐標并不是成對的,與我們上面的數據輸入略有不同,因此在下面的實驗中,筆者用 get_paired_coord 函數統一了一下接口規范。

其中 tolerance 參數(中文意為容忍度)表示的就是輸出的多邊形的每個坐標點之間的最大距離,可想而知,該值越大,可能的精度損失越大。

from skimage import measuredef close_contour(contour):if not np.array_equal(contour[0], contour[-1]):contour = np.vstack((contour, contour[0]))return contourdef binary_mask_to_polygon(binary_mask, tolerance=0):"""Converts a binary mask to COCO polygon representationArgs:binary_mask: a 2D binary numpy array where '1's represent the objecttolerance: Maximum distance from original points of polygon to approximatedpolygonal chain. If tolerance is 0, the original coordinate array is returned."""polygons = []# pad mask to close contours of shapes which start and end at an edgepadded_binary_mask = np.pad(binary_mask, pad_width=1, mode='constant', constant_values=0)contours = measure.find_contours(padded_binary_mask, 0.5)contours = np.subtract(contours, 1)for contour in contours:contour = close_contour(contour)contour = measure.approximate_polygon(contour, tolerance)if len(contour) < 3:continuecontour = np.flip(contour, axis=1)segmentation = contour.ravel().tolist()# after padding and subtracting 1 we may get -0.5 points in our segmentationsegmentation = [0 if i < 0 else i for i in segmentation]polygons.append(segmentation)return polygons

下面看一下本例中的小狗在 tolerance 為 0 和 100 下的區別。

def get_paired_coord(coord):points = Nonefor i in range(0, len(coord), 2):point = np.array(coord[i: i+2], dtype=np.int32).reshape(1, 2)if (points is None): points = pointelse: points = np.concatenate([points, point], axis=0)return pointspoly_0 = binary_mask_to_polygon(cat_mask+dog_mask, tolerance=0)
poly_100 = binary_mask_to_polygon(cat_mask+dog_mask, tolerance=100)poly0_0 = get_paired_coord(poly_0[0])		# poly_0[0]是小狗,poly[1]是小貓
poly100_0 = get_paired_coord(poly_100[0])p0_img = img
p0_points = np.array(poly0_0, dtype=np.int32)
cv2.polylines(p0_img, [p0_points], True, (255, 0, 0), 3)
cv2.imwrite("poly_dog_0.jpeg", p0_img)p100_img = cv2.imread("cat-dog.jpeg")
p100_points = np.array(poly100_0, dtype=np.int32)
cv2.polylines(p100_img, [p100_points], True, (255, 0, 0), 3)
cv2.imwrite("poly_dog_100.jpeg", p100_img)

在這里插入圖片描述

tolerance=0

在這里插入圖片描述

tolerance=100

與我們的預期相符,tolerance=0 時不會有精度損失,而當 tolerance=100 時可以看到進度損失已經比較大了。

RLE編碼

mask 大概是這種形式:

mask=np.array([[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 1, 1, 0, 0, 1, 0],[0, 0, 1, 1, 1, 1, 1, 0],[0, 0, 1, 1, 1, 1, 1, 0],[0, 0, 1, 1, 1, 1, 1, 0],[0, 0, 1, 0, 0, 0, 1, 0],[0, 0, 1, 0, 0, 0, 1, 0],[0, 0, 0, 0, 0, 0, 0, 0]])

可以看到其實是有很多信息冗余的,因為只有0,1兩種元素,RLE編碼就是將相同的數據進行壓縮計數,同時記錄當前數據出現的初始為位置和對應的長度,例如:[0,1,1,1,0,1,1,0,1,0] 編碼之后為1,3,5,2,8,1。其中的奇數位表示數字1出現的對應的index,而偶數位表示它對應的前面的坐標位開始數字1重復的個數。

RLE全稱(run-length encoding),翻譯為游程編碼,又譯行程長度編碼,又稱變動長度編碼法(run coding),在控制論中對于二值圖像而言是一種編碼方法,對連續的黑、白像素數(游程)以不同的碼字進行編碼。游程編碼是一種簡單的非破壞性資料壓縮法,其好處是加壓縮和解壓縮都非常快。其方法是計算連續出現的資料長度壓縮之。

RLE是COCO數據集的規范格式之一,也是許多圖像分割比賽指定提交結果的格式。

mask轉rle編碼,這里我們借助 pycocotools 工具包:

def singleMask2rle(mask):rle = mask_util.encode(np.array(mask[:, :, None], order='F', dtype="uint8"))[0]rle["counts"] = rle["counts"].decode("utf-8")return rle

該函數的返回值 rle 是一個字典,有兩個字段 sizecounts ,該字典通常直接作為 COCO 數據集的 segmentation 字段。

RLE編碼的理解推薦:https://blog.csdn.net/wuda19920215/article/details/113865418

Ref:

https://wall.alphacoders.com/big.php?i=324547&lang=Chinese

https://blog.csdn.net/wuda19920215/article/details/113865418

https://www.cnblogs.com/aimhabo/p/9935815.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532517.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532517.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532517.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

tensorboard報錯:ValueError Duplicate plugins for name projector 問題的出現及解決過程

tensorboard報錯&#xff1a;ValueError: Duplicate plugins for name projector 問題的出現及解決過程 記錄如題問題的出現及解決過程。 報錯命令及信息 筆者在終端調用 tensorboard 時&#xff1a; tensorboard --logdirruns/ --bind_all報錯&#xff1a; raise ValueEr…

發布自己的Python包(Pypi)

發布自己的Python包(Pypi) 我們經常使用 Pypi 來安裝包&#xff0c;但是有時候我們也想要發布自己的 Pypi 包&#xff0c;有可能我們寫了一個特別牛的包&#xff0c;也有可能我們只是想使用自己常用的一些輪子&#xff0c;可能這是我們日常編碼中很常用的一些輪子&#xff0c;…

Ubuntu PPA 使用指南

Ubuntu PPA 使用指南 轉自&#xff1a;https://zhuanlan.zhihu.com/p/55250294 一篇涵蓋了在 Ubuntu 和其他 Linux 發行版中使用 PPA 的幾乎所有問題的深入的文章。 如果你一直在使用 Ubuntu 或基于 Ubuntu 的其他 Linux 發行版&#xff0c;例如 Linux Mint、Linux Lite、Zorin…

如何在 Linux 中快速地通過 HTTP 提供文件訪問服務

如何在 Linux 中快速地通過 HTTP 提供文件訪問服務 轉自&#xff1a;https://linux.cn/article-10205-1.html 如今&#xff0c;我有很多方法來通過 Web 瀏覽器為局域網中的其他系統提供單個文件或整個目錄的訪問。我在我的 Ubuntu 測試機上測試了這些方法&#xff0c;它們如下面…

Linux apt命令

Linux apt命令及其與apt-get的關系 轉自&#xff1a;https://blog.csdn.net/taotongning/article/details/82320472、https://www.runoob.com/linux/linux-comm-apt.html apt&#xff08;Advanced Packaging Tool&#xff09;是一個在 Debian 和 Ubuntu 中的 Shell 前端軟件包管…

楊宏宇:騰訊多模態內容理解技術及應用

楊宏宇&#xff1a;騰訊多模態內容理解技術及應用 分享嘉賓&#xff1a;楊宇鴻 騰訊 內容理解高級工程師 編輯整理&#xff1a;吳祺堯 出品平臺&#xff1a;DataFunTalk 導讀&#xff1a; 搜索內容的理解貫穿了整個搜索系統。我們需要從多個粒度理解搜索內容&#xff0c;包括語…

git登錄相關操作梳理

git登錄相關操作梳理 本文主要基于 Linux/Mac &#xff0c;Windows下未經測試&#xff0c;不過估計差不多&#xff0c;在 git bash 內操作即可。 創建ssh key并關聯github等賬號 因為本地Git倉庫和GitHub倉庫之間的傳輸是通過SSH加密傳輸的&#xff0c;GitHub需要識別是否是…

關于mmdetection上手的幾點說明

關于mmdetection上手的幾點說明 官方的文檔很有參考價值&#xff0c;并且也有中文版&#xff0c;應當是大家上手 mmdetection 的第一參考&#xff0c;本文是記錄一些筆者在小白階段上手 mmdetection 時的一些心得&#xff0c;這些東西沒有人提&#xff0c;可能是大佬們覺得這些…

docker gpu報錯Error response from daemon: could not select device driver ““ with capabilities: [[gpu]]

Docker容器中使用Nvidia GPU報錯 docker: Error response from daemon: could not select device driver “” with capabilities: [[gpu]]. 問題出現 我們知道&#xff0c;想要在 docker19 及之后的版本中使用 nvidia gpu 已經不需要單獨安裝 nvidia-docker 了&#xff0c;這…

CUDA環境詳解

CUDA環境詳解 本文主要介紹 CUDA 環境&#xff0c;這一堆東西網上有很多博客介紹過了&#xff0c;我再來一篇:)&#xff0c;參考前輩們的文章&#xff0c;看能不能寫的更清楚一點。讀后仍有問題&#xff0c;歡迎留言交流。 CUDA APIs CUDA是由NVIDIA推出的通用并行計算架構&…

共享內存簡介及docker容器的shm設置與修改

共享內存簡介及docker容器的shm設置與修改 共享內存簡介 共享內存指 (shared memory)在多處理器的計算機系統中&#xff0c;可以被不同中央處理器&#xff08;CPU&#xff09;訪問的大容量內存。由于多個CPU需要快速訪問存儲器&#xff0c;這樣就要對存儲器進行緩存&#xff…

對Docker鏡像layer的理解

對Docker鏡像layer的理解 轉自&#xff1a;https://blog.csdn.net/u011069294/article/details/105583522 FROM python:3.6.1-alpine RUN pip install flask CMD [“python”,“app.py”] COPY app.py /app.py上面是一個Dockerfile的例子&#xff0c;每一行都會生成一個新的l…

ssh免密登錄配置方法及配置

ssh免密登錄配置方法及配置 直接上步驟&#xff0c;記我們本機為機器A&#xff0c;而機器B、機器C等是我們的服務器&#xff0c;我們要配置的是A到B、C等的 ssh 免密登錄。 1 在機器A上生成秘鑰對 ssh-keygen會得到輸出&#xff1a; Generating public/private rsa key pai…

機器學習系統:設計與實現 計算圖

機器學習系統:設計與實現 計算圖 轉自&#xff1a;https://openmlsys.github.io/chapter_computational_graph/index.html 在上一章節中&#xff0c;我們展示了用戶利用機器學習框架所編寫的程序。這些用戶程序包含了對于訓練數據&#xff0c;模型和訓練過程的定義。然而為了…

常見浮點數格式梳理

常見浮點數格式梳理 IEEE 754 標準 浮點數轉換網站&#xff1a;https://www.h-schmidt.net/FloatConverter/IEEE754.html IEEE二進制浮點數算術標準&#xff0c;為許多CPU與浮點運算器所采用。這個標準定義了表示浮點數的格式&#xff08;包括負零-0&#xff09;與反常值&am…

Python拾遺1:collections、itertools和內存io

Python拾遺1&#xff1a;collections、itertools和內存io 轉自&#xff1a;https://www.liaoxuefeng.com/wiki/1016959663602400 本系列旨在補充python中一些很好用但是并非常規課程主線中的知識。 collections collections是Python內建的一個集合模塊&#xff0c;提供了許…

混合精度訓練

混合精度訓練 轉自&#xff1a;https://zhuanlan.zhihu.com/p/441591808 通常我們訓練神經網絡模型的時候默認使用的數據類型為單精度FP32。近年來&#xff0c;為了加快訓練時間、減少網絡訓練時候所占用的內存&#xff0c;并且保存訓練出來的模型精度持平的條件下&#xff0…

拓撲排序C++

拓撲排序C 幾個基本概念的介紹 入度和出度 圖中的度&#xff1a;所謂頂點的度(degree)&#xff0c;就是指和該頂點相關聯的邊數。在有向圖中&#xff0c;度又分為入度和出度。 入度 (in-degree) &#xff1a;以某頂點為弧頭&#xff0c;終止于該頂點的邊的數目稱為該頂點的…

C++面試常考題——編譯內存相關

C面試常考題——編譯內存相關 轉自&#xff1a;https://leetcode-cn.com/leetbook/read/cpp-interview-highlights/e4ns5g/ C程序編譯過程 編譯過程分為四個過程&#xff1a;編譯&#xff08;編譯預處理、編譯、優化&#xff09;&#xff0c;匯編&#xff0c;鏈接。 編譯預處…

C++遍歷刪除元素

C遍歷刪除元素 轉自&#xff1a;http://zencoder.info/2019/10/11/erase-element-from-container/ 今天看到一個patch fix從std::map中遍歷刪除元素導致crash問題&#xff0c;突然意識到自己對如何正確地從map等C容器中刪除元素也沒有很牢固清醒的認知。重新梳理了下這塊的正…