3

我已经在这个问题上敲了很长时间

我在做成像。到目前为止,我已经对图像进行了二值化,这意味着从灰度图像中,某个值以下的每个像素都会被丢弃。这给了我原始图像中的一些区域,这些区域周围有很多“零像素”。

接下来,我将运行长度编码为“blob”。运行是一种数据压缩方法。例如,假设您已经对一个正方形进行了二值化,那么您将只有几次运行来描述整个图像。游程由 x,y 坐标和长度定义。

重新创建图像时,对于每次运行,转到 x,y 坐标并在 x 轴上添加像素作为运行长度。

现在我必须运行并从中创建一条链来描述该区域的轮廓。我不知道该怎么做。

我有一堆 x,y,length 运行,我必须在边缘“导航”以形成一个chain。通常在成像中,这个过程是用原始图像完成的,但我不能再在这里使用原始图像,所以我必须用运行来计算它。

我知道这看起来像一堵大墙,但我不知道如何更好地提出这个问题。

任何关于相同实现的提示或指针都会很棒。

编辑

感谢 unwind,我会链接一些图片:

替代文字
(来源:tudelft.nl

在这个例子中,他们将图像 B 处理成轮廓 C(我称之为链)。但是我想从 D 生成轮廓,运行长度

4

3 回答 3

0

乍一看,我没有看到一个实用的算法。穷人的解决方案是从长度编码的图像中扩展原始图像。因此,如果您的线条如下所示:

A 3B 10A C 8D
C 4D 3A 6C 9A

其中字符返回实际像素值(例如 A = 0,B = 127,...)。您可以将像素值写入二维数组(或您选择的其他数据结构)。它看起来像这样:

ABBBAAAAAAAAAACDDDDDDDD
CDDDDAAACCCCCCAAAAAAAAA

之后生成你的链,删除数组并保留链信息。当然这很昂贵,所以也许你可以在对原始图片进行长度编码之前这样做。

于 2010-02-12T08:44:37.347 回答
0

这是一个非常简单实用的解决方案(C++):

#include <iostream>
#include <vector>

struct Run { int x, w; };
enum { EAST, NORTHEAST, NORTH, NORTHWEST, WEST, SOUTHWEST, SOUTH, SOUTHEAST };

int main() {

    const Run data[] = {
        { 7, 2 },
        { 5, 6 },
        { 5, 7 },
        { 5, 7 },
        { 6, 6 },
        { 0, 12 },
        { 0, 12 },
        { 0, 11 },
        { 1, 7 },
        { 3, 4 },
        { 3, 4 },
        { 3, 5 },
        { 3, 7 },
        { 3, 7 },
        { 5, 5 }
    };

    std::vector<Run> runs(data, data + 15);
    std::vector<int> before;
    std::vector<int> after;
    unsigned int i;
    int j;

    for (i = 0; i < runs.size() - 1; ++i) {

        if (runs[i].x < runs[i + 1].x) {

            for (j = 0; j < runs[i + 1].x - runs[i].x - 1; ++j)
                before.push_back(WEST);
            before.push_back(NORTHWEST);

        } else if (runs[i].x > runs[i + 1].x) {

            before.push_back(NORTHEAST);
            for (j = 0; j < runs[i].x - runs[i + 1].x - 1; ++j)
                before.push_back(EAST);

        } else {

            before.push_back(NORTH);

        }

        int first_right(runs[i].x + runs[i].w);
        int second_right(runs[i + 1].x + runs[i + 1].w);

        if (first_right < second_right) {

            after.push_back(SOUTHEAST);
            for (j = 0; j < second_right - first_right - 1; ++j)
                after.push_back(EAST);

        } else if (first_right > second_right) {

            for (j = 0; j < first_right - second_right - 1; ++j)
                after.push_back(WEST);
            after.push_back(SOUTHWEST);

        } else {

            after.push_back(SOUTH);

        }

    }

    for (j = 0; j < runs.back().w - 1; ++j)
        after.push_back(WEST);

    std::reverse(before.begin(), before.end());
    after.insert(after.end(), before.begin(), before.end());

    for (j = 0; j < int(after.size()); ++j) {
        switch (after[j]) {
        case EAST:      std::cout << "EAST\n";      break;
        case NORTHEAST: std::cout << "NORTHEAST\n"; break;
        case NORTH:     std::cout << "NORTH\n";     break;
        case NORTHWEST: std::cout << "NORTHWEST\n"; break;
        case WEST:      std::cout << "WEST\n";      break;
        case SOUTHWEST: std::cout << "SOUTHWEST\n"; break;
        case SOUTH:     std::cout << "SOUTH\n";     break;
        case SOUTHEAST: std::cout << "SOUTHEAST\n"; break;
        }
    }

}

这通过迭代运行,测试左右端点的跳转方向,并将适当数量的链元素添加到两个向量:一个正向,右侧,一个反向顺序, 对于左边。然后它通过为最后一条扫描线添加适当数量的链接来连接两条链,然后反转左侧链并将其附加到右侧以生成最终链。

希望这就是你要找的!

于 2010-02-12T09:15:21.033 回答
0

好吧,我失去了那份合同,但答案是使用弗里曼链编码技术

它是运行长度编码的事实与算法无关,这与我之前认为的不同。

于 2010-08-18T18:32:05.003 回答