如何使用opencv和python在灰度图像上应用分水岭?

时间:2017-11-14 03:34:07

标签: python opencv image-segmentation grayscale watershed

根据我在How to define the markers for Watershed in OpenCV?阅读的解决方案,我正尝试将分水岭应用于grayscale data (not very visible but not all black),从netcdf(降水数据)中提取。

这是一个black and white version of the data(阈值为0),这样你就可以更容易地看到,markers我想用它来定义不同的盆地(基本上只是降水更强烈的另一个门槛) )。

我正在运行的代码如下:

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图像尝试了脚本,我工作得很好。 提到这个问题是here,但给出的答案最终被拒绝了。我无法找到回答这个问题的最新链接。

为了解决这个问题,我从2D new_data创建了一个3D数组:

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 个答案:

答案 0 :(得分:1)

正如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)

答案 1 :(得分:0)

您可以尝试使用

将图像格式更改为BGR色彩空间

cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)

在将图像传递给分水岭算法之前