Python 中的连通分量标记算法
Connected Component Labeling Algorithm in Python
我的工作需要在图像上应用本地二元运算符。为此,我已经将图像转换为灰色,然后还对图像实施了连通分量分析。
代码如下:
添加库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from skimage.io import imread, imshow
from skimage.color import rgb2gray
from skimage.morphology import (erosion, dilation, closing, opening,area_closing, area_opening)
from skimage.measure import label, regionprops, regionprops_table
渲染图像
plt.figure(figsize=(6,6))
painting = imread("E:/Project/for_annotation/Gupi Gain0032.jpg")
plt.imshow(painting);
plt.figure(figsize=(6,6))
二值化图像
gray_painting = rgb2gray(painting)
binarized = gray_painting<0.55
plt.imshow(binarized);
4.Declaring 内核
square = np.array([[1,1,1],
[1,1,1],
[1,1,1]])
膨胀函数
def multi_dil(im, num, element=square):
for i in range(num):
im = dilation(im, element)
return im
侵蚀函数
def multi_ero(im, num, element=square):
for i in range(num):
im = erosion(im, element)
return im
应用的函数
plt.figure(figsize=(6,6))
multi_dilated = multi_dil(binarized, 7)
area_closed = area_closing(multi_dilated, 50000)
multi_eroded = multi_ero(area_closed, 7)
opened = opening(multi_eroded)
plt.imshow(opened);
标签函数
plt.figure(figsize=(6,6))
label_im = label(opened)
regions = regionprops(label_im)
plt.imshow(label_im);
提取特征
properties = ['area','convex_area','bbox_area', 'extent', 'mean_intensity','solidity', 'eccentricity', 'orientation']
pd.DataFrame(regionprops_table(label_im, gray_painting,
properties=properties))
过滤区域
masks = []
bbox = []
list_of_index = []
for num, x in enumerate(regions):
area = x.area
convex_area = x.convex_area
if (num!=0 and (area>100) and (convex_area/area <1.05)
and (convex_area/area >0.95)):
masks.append(regions[num].convex_image)
bbox.append(regions[num].bbox)
list_of_index.append(num)
count = len(masks)
提取图像
fig, ax = plt.subplots(2, int(count/2), figsize=(15,8))
for axis, box, mask in zip(ax.flatten(), bbox, masks):
red = painting[:,:,0][box[0]:box[2], box[1]:box[3]] * mask
green = painting[:,:,1][box[0]:box[2], box[1]:box[3]] * mask
blue = painting[:,:,2][box[0]:box[2], box[1]:box[3]] * mask
image = np.dstack([red,green,blue])
axis.imshow(image)
plt.tight_layout()
plt.figure(figsize=(6,6))
rgb_mask = np.zeros_like(label_im)
for x in list_of_index:
rgb_mask += (label_im==x+1).astype(int)
red = painting[:,:,0] * rgb_mask
green = painting[:,:,1] * rgb_mask
blue = painting[:,:,2] * rgb_mask
image = np.dstack([red,green,blue])
plt.imshow(image);
我收到一个错误。
ValueError: Number of columns must be a positive integer, not 0
有一种可能的方法与您尝试的方法相差不大。假设背景像素被分配标签 0,对象像素被分配值 1。
逐行扫描图像;
当遇到像素1时,设置一个新的label并进行flood fill操作,将1替换为新的label。
洪水填充可以很简单地实现:
将起始像素设置为新标签;
递归填充八个邻居,如果它们有一个 1。
https://en.wikipedia.org/wiki/Flood_fill
这个版本的代码非常简单。但是您会注意到它很容易溢出堆栈,因为待处理的填充数可能与图像大小一样大。
def FloodFill(X, Y, Label):
I[X,Y]= Label
for all 8-way neighbors (X'=X±1, Y'=Y±1, inside image):
if I[X',Y'] == 1:
FloodFill(X', Y', Label)
def CCL(Image I):
Label= 1
for Y in range(I.Height):
for X in range(I.Width):
if I[X, Y] == 1:
Label+= 1
FloodFill(X, Y, Label)
所以我会推荐扫描线版本,它涉及更多。
我的工作需要在图像上应用本地二元运算符。为此,我已经将图像转换为灰色,然后还对图像实施了连通分量分析。
代码如下:
添加库
import numpy as np import pandas as pd import matplotlib.pyplot as plt from skimage.io import imread, imshow from skimage.color import rgb2gray from skimage.morphology import (erosion, dilation, closing, opening,area_closing, area_opening) from skimage.measure import label, regionprops, regionprops_table
渲染图像
plt.figure(figsize=(6,6)) painting = imread("E:/Project/for_annotation/Gupi Gain0032.jpg") plt.imshow(painting); plt.figure(figsize=(6,6))
二值化图像
gray_painting = rgb2gray(painting) binarized = gray_painting<0.55 plt.imshow(binarized);
4.Declaring 内核
square = np.array([[1,1,1],
[1,1,1],
[1,1,1]])
膨胀函数
def multi_dil(im, num, element=square): for i in range(num): im = dilation(im, element) return im
侵蚀函数
def multi_ero(im, num, element=square): for i in range(num): im = erosion(im, element) return im
应用的函数
plt.figure(figsize=(6,6)) multi_dilated = multi_dil(binarized, 7) area_closed = area_closing(multi_dilated, 50000) multi_eroded = multi_ero(area_closed, 7) opened = opening(multi_eroded) plt.imshow(opened);
标签函数
plt.figure(figsize=(6,6)) label_im = label(opened) regions = regionprops(label_im) plt.imshow(label_im);
提取特征
properties = ['area','convex_area','bbox_area', 'extent', 'mean_intensity','solidity', 'eccentricity', 'orientation'] pd.DataFrame(regionprops_table(label_im, gray_painting, properties=properties))
过滤区域
masks = [] bbox = [] list_of_index = [] for num, x in enumerate(regions): area = x.area convex_area = x.convex_area if (num!=0 and (area>100) and (convex_area/area <1.05) and (convex_area/area >0.95)): masks.append(regions[num].convex_image) bbox.append(regions[num].bbox) list_of_index.append(num) count = len(masks)
提取图像
fig, ax = plt.subplots(2, int(count/2), figsize=(15,8)) for axis, box, mask in zip(ax.flatten(), bbox, masks): red = painting[:,:,0][box[0]:box[2], box[1]:box[3]] * mask green = painting[:,:,1][box[0]:box[2], box[1]:box[3]] * mask blue = painting[:,:,2][box[0]:box[2], box[1]:box[3]] * mask image = np.dstack([red,green,blue]) axis.imshow(image) plt.tight_layout() plt.figure(figsize=(6,6)) rgb_mask = np.zeros_like(label_im) for x in list_of_index: rgb_mask += (label_im==x+1).astype(int) red = painting[:,:,0] * rgb_mask green = painting[:,:,1] * rgb_mask blue = painting[:,:,2] * rgb_mask image = np.dstack([red,green,blue]) plt.imshow(image);
我收到一个错误。
ValueError: Number of columns must be a positive integer, not 0
有一种可能的方法与您尝试的方法相差不大。假设背景像素被分配标签 0,对象像素被分配值 1。
逐行扫描图像;
当遇到像素1时,设置一个新的label并进行flood fill操作,将1替换为新的label。
洪水填充可以很简单地实现:
将起始像素设置为新标签;
递归填充八个邻居,如果它们有一个 1。
https://en.wikipedia.org/wiki/Flood_fill
这个版本的代码非常简单。但是您会注意到它很容易溢出堆栈,因为待处理的填充数可能与图像大小一样大。
def FloodFill(X, Y, Label):
I[X,Y]= Label
for all 8-way neighbors (X'=X±1, Y'=Y±1, inside image):
if I[X',Y'] == 1:
FloodFill(X', Y', Label)
def CCL(Image I):
Label= 1
for Y in range(I.Height):
for X in range(I.Width):
if I[X, Y] == 1:
Label+= 1
FloodFill(X, Y, Label)
所以我会推荐扫描线版本,它涉及更多。