Как применить водораздел на изображении в градациях серого с помощью opencv и python?

Основано на решении, которое я прочитал в разделе Как определить маркеры для Watershed в OpenCV? Я пытаюсь применить водораздел к данным в градациях серого (не очень заметным, но не всем черным), извлеченным из netcdf (данные об осадках).

Вот черно-белая версия данных (порог 0), чтобы вам было легче видеть, и маркеры, которые я хочу использовать для определения различных бассейнов (в основном просто еще один порог, где осадки более интенсивны).

Код, который я запускаю, выглядит следующим образом:

import os,sys,string
from netCDF4 import Dataset as nc
import cv2
import numpy as np
import matplotlib.pyplot as mpl
import scipy.ndimage as ndimage
import scipy.spatial as spatial
from skimage import filter
from skimage.morphology import watershed
from scipy import ndimage

filename=["Cmorph-1999_01_03.nc"]

nc_data=nc(filename[0])
data=nc_data.variables["CMORPH"][23,0:250,250:750]
new_data=np.flipud(data)
ma_data=np.ma.masked_where(new_data<=0,new_data)
ma_conv=np.ma.masked_where(new_data<=2,new_data)

## Borders
tmp_data=ma_data.filled(0)
tmp_data[np.where(tmp_data!=0)]=255
bw_data=tmp_data.astype(np.uint8)
border = cv2.dilate(bw_data, None, iterations=5)
border = border - cv2.erode(border, None)

## Markers
tmp_conv=ma_conv.filled(0)
tmp_conv[np.where(tmp_conv!=0)]=255
bw_conv=tmp_conv.astype(np.uint8)
lbl, ncc = ndimage.label(bw_conv)
lbl = lbl * (255/ncc)
lbl[border == 255] = 255
lbl = lbl.astype(np.int32)

## Apply watershed
cv2.watershed(ma_data, lbl)

lbl[lbl == -1] = 0
lbl = lbl.astype(np.uint8)
result = 255 - lbl

У меня есть следующая ошибка для водораздела в opencv-2.4.11/modules/imgproc/src/segmentation.cpp:

error: (-210) Only 8-bit, 3-channel input images are supported in function cvWatershed

Для того, что я видел в интернете, это связано с тем, что данные в градациях серого являются 2D-изображением, а водоразделу необходимо 3D-изображение (из RGB). Действительно, я попробовал сценарий с изображением JPG, и я работал отлично. Эта проблема упоминается здесь, но данный ответ был окончательно отклонен. И я не могу найти более свежую ссылку, отвечающую на вопрос.

Чтобы попытаться решить эту проблему, я создал трехмерный массив из 2D new_data:

new_data = new_data[..., np.newaxis]
test=np.append(new_data, new_data, axis=2)
test=np.append(new_data, test, axis=2)

Но, как и ожидалось, это не решило проблему (то же сообщение об ошибке).

Я также попытался сохранить график из matplotlib для получения данных RGB:

fig = mpl.figure()
fig.add_subplot(111)
fig.tight_layout(pad=0)
mpl.contourf(ma_data,levels=np.arange(0,255.1,0.1))
fig.canvas.draw()
test_data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
test_data = test_data.reshape(fig.canvas.get_width_height()[::-1] + (3,))

Но размер созданной test_data отличается от ma_data (+ я не могу избавиться от меток).

Итак, я застрял здесь. В идеале я хочу применить водораздел непосредственно к 2D-изображению в градациях серого и / или максимально ограничить количество операций.

2 ответа

Решение

Как упоминал yapws87, действительно была проблема с форматом, который я представлял функции водораздела. дела try_data=ma_data.astype(np.uint8) убрал сообщение об ошибке.

Вот минимальный пример, который работает сейчас:

import os,sys
from netCDF4 import Dataset as nc
import cv2
import numpy as np
import scipy.ndimage as ndimage
from skimage.morphology import watershed
from scipy import ndimage

basename="/home/dcop696/Data/CMORPH/precip/CMORPH_V1.0/CRT/8km-30min/1999/"
filename=["Cmorph-1999_01_03.nc"]
fileslm=["/home/dcop696/Data/LSM/Cmorph_slm_8km.nc"]

nc_data=nc(basename+filename[0])
data=nc_data.variables["CMORPH"][23,0:250,250:750]
new_data=np.flipud(data)
ma_data=np.ma.masked_where(new_data<=0,new_data)
try_data=ma_data.astype(np.uint8)  

## Building threshold
tmp_data=ma_data.filled(0)
tmp_data[np.where(tmp_data!=0)]=255
bw_data=tmp_data.astype(np.uint8)

## Building markers
ma_conv=np.ma.masked_where(new_data<=2,new_data)
tmp_conv=ma_conv.filled(0)
tmp_conv[np.where(tmp_conv!=0)]=255
bw_conv=tmp_conv.astype(np.uint8)
markers = ndimage.label(bw_conv)[0]

## Watershed
labels = watershed(-try_data, markers, mask=bw_data)

Вы можете попробовать изменить изображение с серого на цветовое пространство BGR, используя

cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)

перед передачей вашего изображения в алгоритм водораздела

Другие вопросы по тегам