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

How to apply watershed on grayscale image with opencv and python?

基于我在 How to define the markers for Watershed in OpenCV?, I am trying apply watershed to grayscale data (not very visible but not all black) 上阅读的解决方案,从 netcdf(降水数据)中提取。

这里是 black and white version of the data (threshold at 0) so that you can see more easily, and the 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但是给出的答案最终被否决了。我找不到更多最近的 link 回答这个问题。

为了解决这个问题,我从 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 不同(+ 我无法摆脱标签)。

所以,我被困在这里了。理想情况下,我想直接在二维灰度图上应用分水岭and/or尽可能限制操作次数

您可以尝试使用

将图像帧灰色更改为 BGR 颜色space

cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)

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

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