半全局块匹配(Semi-Global Block Matching)算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了半全局块匹配(Semi-Global Block Matching)算法相关的知识,希望对你有一定的参考价值。

参考技术A

最近在做双目视差估计算法,在OpenCV里有一些算法,其中半全局块匹配(Semi-Global Block Matching,SGBM)算法具有视差效果好速度快的特点,因此常常被广泛应用。本文主要讨论的就是SGBM算法。OpenCV的SGBM算法主要参考了《Stereo Processing by Semiglobal Matching and Mutual Information》这篇论文。

原论文使用的方法是利用互信息熵,而OpenCV使用的是Birchfield和Tomasi的方法(参照《Depth Discontinuities by Pixel-to-Pixel Stereo》)。这里我们分别介绍一下。

所谓的熵,是用来表示随机变量的不确定性,熵的值越大,信息的不确定性也越大。熵H和互信息MI的定义分别如下:

其中,P I 代表某个点i的概率分布,也就是灰度直方图为i的点出现的概率;对应地,P I 1 ,I 2 就是两个图对应点i 1 和i 2 的联合概率分布,也就是:

Kim等人将上式做了一个改进:利用泰勒展开把H I 1 ,I 2 的计算转化为求和问题(参见论文《Visual Correspondence Using Energy Minimization and Mutual Information》)。

其中圈中带叉表示卷积运算,g(i,k)为高斯卷积核。

相应地,边缘熵以及边缘概率的计算如下:

这样的话,互信息的定义为:

MI匹配代价C MI 为:

其中 q 是点 p 在视差为d的情况下的对应校正点。

原作者使用分层互信息(HMI)进行计算,每一层尺寸减少一半。单次计算的时间复杂度是O(WHD),即width×height×disparity range,所以上次迭代将会是当前迭代速度的1/8。

这里1/16 3 要乘3的原因是小尺寸的随机视差图不靠谱,需要迭代3次。我们可以看到,相比于后文的BT方法仅仅慢了14%

对于一个匹配序列M,其代价函数γ(M)表示匹配结果 准确的程度,其值越小越好。

其中,κ occ 表示未匹配的惩罚项(constant occlusion penalty),κ r 表示匹配的奖励项,N occ 和N r 分别表示未匹配和匹配的点数。

我们为视差设置一个能量函数E(D)

其中P 1 和P 2 分别表示视差差值为1和视差差值大于1的惩罚系数,一般P 1 <P 2 。添加两个正则化项一是为了保持视差图平滑,二是为了保持边缘。我们要做的是找到D使得能量函数E(D)最小,但是不幸的是,在二维图像的这个问题是一个NP-完全问题。为了解决这个问题,原文选择沿着一圈8个或者16个方向进行优化。

选取使代价聚合最小的视差值min d S[e mb ( q ,d),d]即可。

我们看一下stereoSGBM类的参数。

简单地试了一下:

表单主题 - 在n block_name匹配时添加代码

我有一个前面的symfony应用程序,它从API获取序列化的symfony表单,解析它并最终呈现它。

这个应用程序应该是愚蠢的,不应该以任何方式了解任何远程应用程序的逻辑。它只需要json格式,并在解析后显示它。

序列化表单中的字段具有自定义(远程应用程序定义)块名称,然后在前端应用程序的表单主题中使用这些名称来构建字段结构。

所述字段示例:

"field_1": {
    "options": {
        "block_name": "block_name_example",
        "label": "Example",
        "required": true,
        "disabled": false,
        "choices": {
            "Choice 1": "1",
            "Choice 2": "2"
        },
        "help_description": "",
        "attr": {
            "name": "field_name_1",
            "short_name": "fieldName1"
        }
    },
    "type": "Symfony\Component\Form\Extension\Core\Type\ChoiceType"
}

我想在form_theme块中添加“第一次匹配此块名称”(例如),而不在远程应用程序端添加任何逻辑,例如:

{% block _form_block_name_example %}
    {% if match_occurrence = 1 %}
        {# do something here #}
    {% endif %}
    {{ form_widget(form) }}
{% endblock %}

我知道有很多方法(表单字段额外选项,将其包装到集合类型字段......)通过远程应用程序代码编辑来解决这个问题,但我不希望出于各种原因,主要是避免任何远程应用程序代码的额外复杂性。

找不到一个干净的方法来解决这个问题。你会成为我的英雄吗?

答案

我只是在一个非常干净的方式来处理这个在前端应用程序。从不相关的代码中剥离最大类并重命名一些东西,使其尽可能通用。

我通过表单扩展为我的字段添加了一个新的额外first_of_type选项,我在表单生成时设置了该选项。然后我将它用作我的表单主题块中的随意选项。代码如下。

表格扩展名:

class ExtraOptionsExtension extends AbstractTypeExtension
{
    /**
     * Add the width option.
     *
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefined([
            /* ... */
            'first_of_type'
        ]);
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        /* ... */
        $view->vars['first_of_type'] = false;
        if (!empty($options['first_of_type'])) {
            $view->vars['first_of_type'] = true;
        }
    }

    /**
     * Returns the name of the type being extended.
     *
     * @return string The name of the type being extended
     */
    public function getExtendedType()
    {
        return FormType::class;
    }
}

FormType:

abstract class AbstractType extends BaseAbstractType
{
    /* ... */

    /**
     * {@inheritdoc}
     *
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $blockNames = [];
        if (is_array($this->fields)) {
            foreach ($this->fields as $property => $data) {
                $type = $data['type'] ?? null;
                $opts = $data['options'] ?? [];
                if (!in_array($type, $this::TYPES_WITHOUT_EXTRA) &&
                    isset($data['options']['block_name']) &&
                    !in_array($data['options']['block_name'], $blockNames)) {
                    $blockNames[] = $data['options']['block_name'];
                    $opts['first_of_type'] = true;
                }
                $builder->add($property, $type, $opts);
            }
        }
    }

    /* ... */
}

表单主题块:

{% block custom_block %}
    <div class="form-group form-inline {% if not first_of_type %} hide {% else %}">
        {{ form_label(form, null, {'label_attr': {'class': 'control-label'}}) }}
        {{ form_widget(form) }}
    </div>
{% endblock %}

仍然可以进行改进,以提供有关元素位置的更多信息(不仅仅是它的第一个事实)。

以上是关于半全局块匹配(Semi-Global Block Matching)算法的主要内容,如果未能解决你的问题,请参考以下文章

iOS学习之代码块(Block)

论文速递Remote Sensing2021 : 通过半全局匹配法的SAR立体图像DSM生成以及惩罚方程的评估

SGM 视差亚像素估计 - 如何?

在 Param (...) 块之间匹配 [STRING]

表单主题 - 在n block_name匹配时添加代码

CUDA 中的块间同步