【问题标题】:How to apply watershed on grayscale image with opencv and python?如何使用opencv和python在灰度图像上应用分水岭?
【发布时间】:2018-03-07 05:55:22
【问题描述】:

根据我在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 灰度图像上应用分水岭和/或尽可能限制操作次数。

【问题讨论】:

标签: python opencv image-segmentation grayscale watershed


【解决方案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)

【讨论】:

    【解决方案2】:

    您可以尝试使用将图像帧灰色更改为 BGR 颜色空间

    cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)

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

    【讨论】:

    • 感谢您的建议,但这样做与在我的尝试(创建的测试变量)中从 2D 创建 3D 数组的效果相同,可能是因为您没有足够的信息来返回RGB。
    • 您不需要更多信息来转向 RGB,它只会将值复制到每个 RGB 通道。我的猜测是您呈现给分水岭函数的格式不正确。
    • 你猜对了。分水岭中的第一个参数没有正确的格式。该错误与灰度图像的尺寸无关。
    猜你喜欢
    • 1970-01-01
    • 2020-05-14
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 2020-07-27
    • 2014-09-12
    • 1970-01-01
    相关资源
    最近更新 更多