pydensecrf的使用

参考:https://github.com/lucasb-eyer/pydensecrf

1.使用

对于图像来说,最简单的使用该库的方法是使用DenseCRF2D类:

import numpy as np
import pydensecrf.densecrf as dcrf

d = dcrf.DenseCRF2D(640, 480, 5)  # width, height, nlabels

 2.一元势 Unary potential

你可以使用下面的方法设置固定的一元势

U = np.array(...)     # Get the unary in some way.
print(U.shape)        # -> (5, 480, 640)
print(U.dtype)        # -> dtype('float32')
U = U.reshape((5,-1)) # Needs to be flat.
d.setUnaryEnergy(U)

# Or alternatively: d.setUnary(ConstUnary(U))

记住U应该是负的log概率,所以如果你用概率py,别忘了执行U = -np.log(py)

需要在一元势上进行reshape是我想要修复的API缺陷,但是如果不引入对numpy的显式依赖,我不知道如何解决这个问题。

注意,nlabel维度是这里reshape之前的第一个维度;如果不是这样的话,你可能需要在reshape之前把nlabel移到前面,即U.shape的结果应该为(5, 480, 640),就像这样:

print(U.shape)  # -> (480, 640, 5)
U = U.transpose(2, 0, 1).reshape((5,-1))

1)Getting a Unary

得到 unary potentials有两种常见的方法:
1)由人类或其他过程产生的硬标签。该方法由from pydensecrf.utils import unary_from_labels实现
2)由概率分布计算得到,例如深度网络的softmax输出。对此,请参阅from pydensecrf.utils import unary_from_softmax

要使用这两种方法,请参考它们的文档或查看示例(https://github.com/lucasb-eyer/pydensecrf/blob/master/examples/inference.py)。

3.Pairwise potentials(二元势)

二维情况下,增加最常见的二元势有两种实用方法:

# This adds the color-independent term, features are the locations only.
d.addPairwiseGaussian(sxy=(3,3), compat=3, kernel=dcrf.DIAG_KERNEL, normalization=dcrf.NORMALIZE_SYMMETRIC)

# This adds the color-dependent term, i.e. features are (x,y,r,g,b).
# im is an image-array, e.g. im.dtype == np.uint8 and im.shape == (640,480,3)
d.addPairwiseBilateral(sxy=(80,80), srgb=(13,13,13), rgbim=im, compat=10, kernel=dcrf.DIAG_KERNEL, normalization=dcrf.NORMALIZE_SYMMETRIC)

这两种方法都有快捷方式和默认参数,因此最常见的用例可以简化为:

d.addPairwiseGaussian(sxy=3, compat=3)
d.addPairwiseBilateral(sxy=80, srgb=13, rgbim=im, compat=10)

im即image

参数映射到本文中的参数如下:高斯情况下的sxy为$\theta_{\gamma}$(即Θγ),双边情况下,sxy和srgb分别映射到$\theta_{\alpha}$(即Θα)和$\theta_{\beta}$(即ΘΒ)。names是“x/y标准偏差”(x/y standard-deviation,sxy)和“rgb标准偏差”(rgb standard-deviation,srgb)的简写,公式为:

 1)Non-RGB bilateral

一个重要的警告是,addPairwiseBilateral只适用于RGB图像,即三个通道。如果您的数据与这个简单但常见的情况不同,则需要使用util .create_pairwise_bilateral函数计算你自己的二元能源;有关详细信息,请参阅 generic non-2D case案例。

在examples文件夹中以笔记本的形式提供了一个example of working with Non-RGB data例子。

 可见Example of DenseCRF with non-RGB data

 

2)Compatibilities

compat参数可以是以下任何一种:

  • 一个数字,然后使用PottsCompatibility。
  • 一个一维数组,然后使用对角兼容性。
  • 一个二维数组,然后使用矩阵兼容性。

这些是label-compatibilites µ(xi, xj)的参数可能学到的东西。例如,他们可以指出把鸟的像素误认为天空并不像把猫误认为天空那么糟糕。数组应该有nlabel或(nlabel,nlabel)作为shape和一个float32数据类型。

3)Kernels

kenel参数的可能值有:

  • CONST_KERNEL
  • DIAG_KERNEL (the default)
  • FULL_KERNEL
该参数指定内核的precision-matrixΛ(m),这可能是习得的。这些表示特征类型之间的相关性,默认值表示没有相关性。同样,这也是可以学习  learned的。
 

4)Normalizations

normalization参数可能的值为:
  • NO_NORMALIZATION
  • NORMALIZE_BEFORE
  • NORMALIZE_AFTER
  • NORMALIZE_SYMMETRIC (the default)

5)Kernel weight权重

到目前为止,我还没有找到设置内核权值w(m)的方法。根据本文,w(2)被设置为1,w(1)被交叉验证,但从未指定。
通过查看Philip的代码(包括在  pydensecrf/densecrf中),我没有找到这样显式的权重,我猜它们因此被硬编码为1。
 

4.Inference推理

 用5次迭代进行推理最简单的方法是:
Q = d.inference(5)

然后MAP预测是:

map = np.argmax(Q, axis=0).reshape((640,480))

如果你对类概率Q感兴趣,你会注意到Q是一个包装好的特征矩阵。本项目的特征包装器实现缓冲接口,可以简单地转换为numpy数组,如下:

proba = np.array(Q)

5.Step-by-step inference一步步推理

如果出于某种原因,你想手动运行推理循环,你可以这样做:

Q, tmp1, tmp2 = d.startInference()
for i in range(5):
    print("KL-divergence at {}: {}".format(i, d.klDivergence(Q)))
    d.stepInference(Q, tmp1, tmp2)

6.Generic non-2D

DenseCRF类可用于一般(非2d)密集CRFs。它的用法与上面完全一样,只是缺少了特定于2d的二元势addPairwiseGaussian和addPairwiseBilateral。

相反,您需要使用通用的addPairwiseEnergy方法,如下所示:

d = dcrf.DenseCRF(100, 5)  # npoints, nlabels

feats = np.array(...)  # Get the pairwise features from somewhere.
print(feats.shape)     # -> (7, 100) = (feature dimensionality, npoints)
print(feats.dtype)     # -> dtype('float32')

dcrf.addPairwiseEnergy(feats)

此外,你还可以传递兼容性、内核参数和标准化参数,就像在二维高斯和双边情况下一样。

势函数计算为w*exp(-0.5 * |f_i - f_j|^2)。

1)Pairwise potentials for N-D

用户@markusnagel编写了几个numpy函数,将两个经典的二维图像二元势(高斯和双边)推广到任意维数:create_pairwise_gaussian和create_pairwise_bilateral。

你可以从from pydensecrf.utils import create_pairwise_gaussian访问它们,然后查看它们的文档去了解如何使用它们。

 

7.Learning

 学习还没有完全结束。如果你需要它,联系或或者更好是去包装它并提交一个拉请求!

这里有一个供初学者参考的指针:第24期。我们需要包装梯度和获取/设置参数。但是,我们还需要对这些做一些事情,最有可能的是从optimization.cpp调用minimizeLBFGS。遵循原始代码中包含的学习示例应该相对简单。
 
 

猜你喜欢

转载自www.cnblogs.com/wanghui-garcia/p/10761612.html