我在这个问题上已经敲了很长时间
我在做影像。到目前为止,我已经对我的图像进行了二值化,这意味着从灰度图像中,某个值下的每个像素都会被丢弃。这只给了我原始图像中的一些区域,这些区域周围有很多“零像素”。
接下来,我将我的区域编码为“blob”。运行是一种压缩数据的方法。例如,假设您已经二进制化了一个正方形,您将只有几个描述整个图像的运行。 运行由x,y坐标和长度定义。
重新创建图像时,对于每次运行,转到x,y坐标,并在x轴上添加运行长度的像素。
现在我必须进行运行并创建一个描述该区域轮廓的链。 我不知道该怎么做。
我有一堆x,y,长度的运行,我必须在边缘“导航”以形成chain。通常在成像过程中,这个过程是用原始图像完成的,但是我不能再使用原始图像了,所以我必须用运行来计算它。
我知道这看起来像是一堵大墙,但我不知道如何更好地提出这个问题。
关于相同实现的任何提示或指示都会很棒。
修改
感谢放松,Ill链接了几张图片:
alt text http://www.ph.tn.tudelft.nl/Courses/FIP/images/fip83.gif
在这个例子中,他们将图像B处理成轮廓C(我称之为链)。但是我想从D,运行长度
生成轮廓答案 0 :(得分:0)
乍一看,我没有看到一个实用的算法。 一个穷人的解决方案是扩展来自长度编码的原始图像。 所以,如果你的行看起来像这样:
A 3B 10A C 8D
C 4D 3A 6C 9A
其中字符返回实际像素值(例如A = 0,B = 127,......)。 您可以将像素值写入二维数组(或您选择的其他数据结构)。它看起来像这样:
ABBBAAAAAAAAAACDDDDDDDD
CDDDDAAACCCCCCAAAAAAAAA
然后生成您的链,删除数组并保留链信息。 当然这很贵,所以也许你可以在对原始图片进行长度编码之前做到这一点。
答案 1 :(得分: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;
}
}
}
这通过遍历运行,测试左端点和右端点以及它们跳转到的方向,并将适当数量的链元素添加到两个向量来实现:一个是向前顺序,一个是右侧,另一个是向右以相反的顺序,左边。然后通过为最后一条扫描线添加适当数量的链接来连接两条链,然后反转左侧链并将其附加到右侧链以生成最终链。
希望这就是你要找的东西!
答案 2 :(得分:0)
我丢失了合同,但答案是使用Freeman Chain Coding technique
运行长度编码这一事实与算法无关,与我之前的想法不同。