Цепочки пикселей из кодирования длин серий
-
20-09-2019 - |
Вопрос
Я долго ломал голову над этим
Я занимаюсь визуализацией.До сих пор я бинаризовал свои изображения, то есть из изображения в оттенках серого удалялся каждый пиксель ниже определенного значения.Это дает мне только некоторые области исходного изображения с множеством «нулевых пикселей» вокруг этих областей.
Затем я закодировал длину своих регионов в «капли».Прогоны — это метод сжатия данных.Например, предположим, что вы бинаризовали квадрат, и у вас будет всего несколько прогонов, описывающих все изображение.Прогоны определяются координатами x,y и длиной.
При воссоздании изображения для каждого прогона перейдите к координате x,y и добавьте пиксели по оси x для длины прогона.
Теперь мне предстоит взять прогоны и создать из них цепочку, которая будет описывать контур региона.Я не знаю, как это сделать.
У меня есть несколько участков x,y,длины, и мне приходится «перемещаться» по краям, чтобы сформировать цепь.Обычно при создании изображений этот процесс выполняется с использованием исходного изображения, но я больше не могу использовать здесь исходное изображение, поэтому мне приходится вычислять его с помощью прогонов.
Я знаю, что это похоже на большую стену текста, но я не знаю, как лучше задать этот вопрос.
Любые подсказки или указатели на идентичную реализацию были бы потрясающими.
РЕДАКТИРОВАТЬ
спасибо, что расслабились, я свяжу несколько изображений:
(источник: tudelft.nl)
В этом примере изображение B преобразуется в контур C (который я называю цепочкой).Однако я хотел бы создать контур из D, длины пробега.
Решение 3
Ну, я потерял этот контракт, но ответ заключался в том, чтобы использовать Техника цепного кодирования Фримена
Тот факт, что это кодирование длин серий, не имеет ничего общего с алгоритмом, в отличие от того, что я думал ранее.
Другие советы
На первый взгляд я не вижу для этого практического алгоритма.Решением для бедняка было бы расширять исходное изображение из закодированного по длине.Итак, если ваши строки выглядят так:
A 3B 10A C 8D
C 4D 3A 6C 9A
где символы возвращают фактическое значение пикселя (например,А = 0, В = 127,...).Вы можете записать значения пикселей в двумерный массив (или другую структуру данных по вашему выбору). Это выглядит следующим образом:
ABBBAAAAAAAAAACDDDDDDDD
CDDDDAAACCCCCCAAAAAAAAA
После этого создайте свою цепочку, удалите массив и сохраните информацию о цепочке.Конечно, это дорого, поэтому может быть вы можете сделать это перед кодированием длины исходного изображения.
Вот совершенно простое и практичное решение (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;
}
}
}
Это работает путем перебора прогонов, проверки левой и правой конечных точек на предмет направления, в котором они переходят, и добавления соответствующего количества элементов цепочки к двум векторам:один в прямом порядке для правой стороны и один в обратном порядке для левой.Затем он соединяет две цепочки, добавляя соответствующее количество звеньев для последней строки сканирования, затем переворачивает левую боковую цепочку и добавляет ее к правой, создавая окончательную цепочку.
Надеюсь, это то, что вы ищете!