ПЕРЕСМОТРЕННЫЙ ОТВЕТ для новой информации.
Для этого ответа определение подключенных пикселей немного больше, чем определение, используемое для обработки изображения. Здесь пиксели считаются связанными, если они имеют общую сторону как {x,y}
и {x+1,y}
или {x,y}
и {x,y+1}
или касаются в углу как {x,y}
и {x+1,y+1}
. Возможно, что другие пакеты (такие как igraph
) могут быть более эффективными для этой задачи, но EBImage
может выполнять работу с инструментами для визуализации или дальнейшей обработки результатов.
Функция bwlabel
в пакете EBImage
используется здесь для поиска связанных групп пикселей. Как описывают авторы:
bwlabel
находит каждый связанный набор пикселей, кроме фона, и перемаркирует эти наборы уникальным возрастающим целым числом
Это частьпакета Bioconductor EBImage , который представляет собой набор инструментов для обработки и анализа изображений для R . Это немного большой. Следующий код проверяет доступность и при необходимости пытается загрузить и установить пакет:
# EBImage needed through Bioconductor, which uses BiocManager
if (!require(EBImage)) {
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("EBImage")
require(EBImage)
}
Инструменты EBImage
позволяют извлекать связанные пиксели из двоичных изображений (рассматриваемых объектов) и количественно определять или визуализироватьих. С извинениями за любое превышение, вот ответ REPLACED с более обширным примером, включающим нерегулярные объекты для демонстрации решения.
Как правило, 0 используется для отсутствия данных при обработке изображений, поэтомуданные в примере используют 0 для не данных и 1 для данных.
# Sample data with 1 as data, 0 as non-data
dat <- c(0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,
0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,1,1,
0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,1,1,
0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,
0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,1,1,0,
0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,0,1,0,
0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,1,1,0,
0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,
0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,
0,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,
0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
# convert to 20x20 pixel image object
x <- Image(dat, dim = c(20, 20)) # use 1 for data, 0 for non-data
# plotting with base graphics allows the use of other R tools
plot(x, interp = FALSE) # interpolate = FALSE option preserves pixels
Представление изображения двоичного массива 20 x 20 в dat
.
![image representation of data](https://i.stack.imgur.com/ZFjfh.png)
# bwlabel() extracts connected pixels from a binary image
# and labels the connected objects in a new Image object
xm <- bwlabel(x)
xm # show the first 5 rows, first 6 columns of "objects" identified by bwlabel
> Image
> colorMode : Grayscale
> storage.mode : integer
> dim : 20 20
> frames.total : 1
> frames.render: 1
>
> imageData(object)[1:5,1:6]
> [,1] [,2] [,3] [,4] [,5] [,6]
> [1,] 0 0 0 0 0 0
> [2,] 0 0 0 0 0 0
> [3,] 0 0 0 0 4 4
> [4,] 1 1 0 0 4 4
> [5,] 1 1 0 0 4 4
Количество объектов(найденные пиксели) - это просто максимальное значение в объекте, возвращаемое bwlabel
. Размер каждого объекта (подключенных пикселей) легко получить с помощью функции table
. Эта информация может быть извлечена и использована для подготовки маркированного изображения. Этот пример включает в себя объект с отверстием.
# total number of objects found
max(xm)
> 9
# size of each object (leaving out background or value = 0 pixels)
table(xm[xm > 0])
> 1 2 3 4 5 6 7 8 9
> 8 13 21 36 15 8 4 6 21
# plot results with labels
iy <- (seq_along(x) - 1) %/% dim(x)[1] + 1
ix <- (seq_along(x) - 1) %% dim(x)[1] + 1
plot(xm, interp = FALSE)
text(ix, iy, ifelse(xm==0, "", xm)) # label each pixel with object group
![labeled objects](https://i.stack.imgur.com/STAYK.png)
Пять объектов окружены «цепочкой» связанных фоновых пикселей: # 3, № 4, № 6, № 7 и № 9. Объект № 6 включен, хотя у него есть отверстие. Логика может быть скорректирована, чтобы исключить объекты с отверстиями. Объекты № 1 и № 2 должны быть исключены, потому что они граничат с краем. Объекты № 5 и № 8 должны быть исключены, потому что они касаются в углу. Если это точно соответствует задаче, EBImage
все еще может помочь с логикой, перечисленной ниже. Вкратце, граница вокруг каждого объекта будет создана и определена, если она охватывает только пустые (или не имеющие границы) пиксели в исходном изображении.
- Извлечение каждого найденного объекта с помощью
bwlabel
как отдельногоimage (xobj
) - Добавление границы черного (нулевого) пикселя к каждому объекту в
xobj
- Расширение каждого объекта в
xobj
на один пиксель с помощью EBImage::dilate
(xdil
) - Создание маски разности с помощью
xor
(xmask
) - Добавление ненулевой границы к исходному изображению (
x2
) - Объединение
xmask
и x2
для определения границ, имеющих непустые пиксели - Удаление объектов, указанных выше
# Extract each object found by bwlabel() as a separate image
xobj <- lapply(seq_len(max(xm)), function(i) xm == i)
# Add a border of black (zero) pixels to each object in `xobj`
xobj <- lapply(xobj, function(v) cbind(0, rbind(0, v, 0), 0))
xobj <- lapply(xobj, as.Image)
xobj <- combine(xobj) # combine as multi-dimensional array
# Dilate each object in `xobj` by one pixel
br <- makeBrush(3, shape = "box") # 3 x 3 structuring element
xdil <- dilate(xobj, br)
# Create difference mask with xor()
xmask <- xor(xdil, xobj) # difference is the border
# Add a non-zero border to the original image
x2 <- Image(cbind(1, rbind(1, x, 1), 1))
# Identify borders that have non-blank pixels
target <- Image(x2, dim = dim(xmask)) # replicate x2
sel <- which(apply(xmask & target, 3, any) == TRUE)
# Remove objects identified above (keeping original numbers)
found <- rmObjects(xm, sel, reenumerate = FALSE)
# Show the found objects
table(found[found > 0])
> 3 4 6 7 9
> 21 36 8 4 21
Каждый из объектов можно исследовать путем построения графика. Многомерные изображения, такие как xobj
, xdil
и xmask
, могут быть нанесены с помощью plot(xobj, all = TRUE, interp = FALSE)
для просмотра промежуточных результатов. Здесь отфильтрованные (найденные) объекты переназначаются с исходными номерами объектов
plot(found, interp = FALSE)
text(ix, iy, ifelse(found==0, "", found)) # label each pixel group no.
![found objects](https://i.stack.imgur.com/vRLKx.png)
Чтобы узнать больше о EBImage см. На упаковке виньетка .