Пиксельные цепочки из кодировки длин серий - PullRequest
3 голосов
/ 12 февраля 2010

Я долго бился об эту голову

Я делаю снимки. До сих пор я преобразовывал свои изображения в двоичную форму, что означает, что из изображения в градациях серого каждый пиксель под определенным значением отбрасывается. Это дает мне только некоторые области из исходного изображения с большим количеством «нулевых пикселей» вокруг этих областей.

Далее я запустил длину, закодировал мои регионы в «капли» Прогоны - это метод сжатия данных. Например, предположим, что вы оцифровали квадрат, у вас будет всего несколько прогонов, описывающих все изображение. Трассы определяются координатами x, y и длиной.

При воссоздании изображения для каждого прогона переходите к координатам x, y и добавляйте пиксели на оси x для длины прогона.

Теперь я должен взять пробежки и создать из них цепочку, которая будет описывать контур региона. Я не знаю, как это сделать.

У меня есть куча прогонов x, y, length, и мне нужно «перемещаться» по краям, чтобы сформировать цепочку . Обычно при обработке изображений этот процесс выполняется с исходным изображением, но я больше не могу использовать исходное изображение здесь, поэтому мне приходится вычислять его по прогонам.

Я знаю, что это похоже на большую стену текста, но я не знаю, как лучше задать этот вопрос.

Любые подсказки или указатели на идентичную реализацию были бы замечательными.

EDIT

благодаря раскрутке, я свяжу несколько изображений:

alt text
(источник: tudelft.nl )

В этом примере они обрабатывают изображение B в контур C (который я называю цепочкой). Однако я хотел бы создать контур из D, Длина пробега

Ответы [ 3 ]

0 голосов
/ 12 февраля 2010

Вот совершенно простое и практичное решение (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;
        }
    }

}

Это работает путем итерации по прогонам, проверки левой и правой конечных точек на предмет направления, к которому они переходят, и добавления соответствующего числа элементов цепочки к двум векторам: один в прямом порядке, для правой стороны и один в обратном порядке, слева. Затем он соединяет две цепочки, добавляя соответствующее количество ссылок для последней строки развертки, затем переворачивает левую боковую цепочку и добавляет ее к правой, чтобы получить окончательную цепочку.

Надеюсь, это то, что вы ищете!

0 голосов
/ 18 августа 2010

Ну, я потерял этот контракт, но ответом было использование техники кодирования цепочки Фримена

Тот факт, что это кодирование длин серий, не имеет ничего общего с алгоритмом, в отличие от того, что я думал ранее.

0 голосов
/ 12 февраля 2010

На первый взгляд я не вижу практического алгоритма для этого. Решением для бедного человека было бы развернуть исходное изображение от закодированной длины. Так что, если ваши строки выглядят так:

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

, где символы возвращают фактическое значение пикселя (например, A = 0, B = 127, ...). Вы можете записать значения пикселей в двумерный массив (или другую структуру данных по вашему выбору). Это выглядит так:

ABBBAAAAAAAAAACDDDDDDDD
CDDDDAAACCCCCCAAAAAAAAA

После этого создайте цепочку, удалите массив и сохраните информацию о цепочке. Конечно, это дорого, поэтому возможно вы можете сделать это до кодирования длины исходного изображения.

...