我正在研究一个挤出功能,在给定2D纹理及其厚度的情况下创建网格。
示例:
通过简单地查找靠近边缘或接近透明的像素,我已经找到了纹理的轮廓。它甚至对于凹形(圆环形)形状也很有效,但现在我留下了一系列轮廓像素。
结果如下:
问题是这些值是从左上角到右下角排序的,它们不适合构建实际的3D轮廓。
我目前的想法如下:
第1步。
从索引[0],在右侧查看与起点不同的最近的连续点。
如果找到,请将其移至另一个阵列。
如果没有,请查看底部。继续,直到达到起点。
Step2。
从阵列中剩余的像素中选择另一个像素(如果有)。
从Step1重复。
在我看来,这会起作用,但效果似乎很低。研究,我发现了摩尔 - 邻居跟踪算法,但我找不到任何一个与凸形状一起工作的例子。
有什么想法吗?
答案 0 :(得分:0)
算法循环使用像素,我们只检查每个像素一次,跳过空单元格,并将其存储在列表中,因为不存在重复项。
isEmpty 实现取决于您的情况下透明度的工作方式,如果某种颜色被视为透明,则下面是我们拥有Alpha通道的情况。
阈值是Alpha级别,表示要将单元格视为非空的最低可见性。
isBorder 将检查Moore邻居是否为空,在这种情况下它是一个边框单元格,否则不是因为它被填充的单元格包围。
isEmpty(x,y): image[x,y].alpha <= threshold
isBorder(x,y)
: if isEmpty(x , y-1): return true
: if isEmpty(x , y+1): return true
: if isEmpty(x-1, y ): return true
: if isEmpty(x+1, y ): return true
: if isEmpty(x-1, y-1): return true
: if isEmpty(x-1, y+1): return true
: if isEmpty(x+1, y-1): return true
: if isEmpty(x+1, y+1): return true
: otherwise: return false
getBorderCellList()
: l = empty-list
: for x in 0..image.width
: : for y in 0..image.height
: : : if !isEmpty(x,y)
: : : : if isBorder(x,y)
: : : : : l.add(x,y)
: return l
优化您可以通过预先计算boolean e[image.width][image.height]
来e[x,y] = 1
image[x,y]
如果isBorder(x,y): e[x-1,y] | e[x+1,y] | .. | e[x+1,y+1]
不为空来优化此项,然后直接使用它进行检查,比如init()
: for x in 0..image.width
: : for y in 0..image.height
: : : e[x,y] = isEmpty(x,y)
isEmpty(x,y): image[x,y].alpha <= threshold
isBorder(x,y): e[x-1,y] | e[x+1,y] | .. | e[x+1,y+1]
getBorderCellList()
: l = empty-list
: for x in 0..image.width
: : for y in 0..image.height
: : : if not e[x,y]
: : : : if isBorder(x,y)
: : : : : l.add(x,y)
: return l
。
show databases
答案 1 :(得分:0)
最后,我找到了自己的答案,所以我想在此分享:
找到给定图像的轮廓(使用每个像素的alpha值)后,像素将按行排序,适合绘制它们但不适合构建网格。
因此,下一步是找到连续的行。这是通过首先检查找到的像素的任何邻居是否优先于顶部/左/右/底部(否则它将跳过角落)来完成。
继续前进,直到原始数组中没有像素。
这是实际的实现(对于Babylon.js,但这个想法适用于任何其他引擎):
游乐场:https://www.babylonjs-playground.com/#9GPMUY#11
var GetTextureOutline = function (data, keepOutline, keepOtherPixels) {
var not_outline = [];
var pixels_list = [];
for (var j = 0; j < data.length; j = j + 4) {
var alpha = data[j + 3];
var current_alpha_index = j + 3;
// Not Invisible
if (alpha != 0) {
var top_alpha = data[current_alpha_index - (canvasWidth * 4)];
var bottom_alpha = data[current_alpha_index + (canvasWidth * 4)];
var left_alpha = data[current_alpha_index - 4];
var right_alpha = data[current_alpha_index + 4];
if ((top_alpha === undefined || top_alpha == 0) ||
(bottom_alpha === undefined || bottom_alpha == 0) ||
(left_alpha === undefined || left_alpha == 0) ||
(right_alpha === undefined || right_alpha == 0)) {
pixels_list.push({
x: (j / 4) % canvasWidth,
y: parseInt((j / 4) / canvasWidth),
color: new BABYLON.Color3(data[j] / 255, data[j + 1] / 255, data[j + 2] / 255),
alpha: data[j + 3] / 255
});
if (!keepOutline) {
data[j] = 255;
data[j + 1] = 0;
data[j + 2] = 255;
}
} else if (!keepOtherPixels) {
not_outline.push(j);
}
}
}
// Remove not-outline pixels
for (var i = 0; i < not_outline.length; i++) {
if (!keepOtherPixels) {
data[not_outline[i]] = 0;
data[not_outline[i] + 1] = 0;
data[not_outline[i] + 2] = 0;
data[not_outline[i] + 3] = 0;
}
}
return pixels_list;
}
var ExtractLinesFromPixelsList = function (pixelsList, sortPixels) {
if (sortPixels) {
// Sort pixelsList
function sortY(a, b) {
if (a.y == b.y) return a.x - b.x;
return a.y - b.y;
}
pixelsList.sort(sortY);
}
var lines = [];
var line = [];
var pixelAdded = true;
var skipDiagonals = true;
line.push(pixelsList[0]);
pixelsList.splice(0, 1);
var countPixels = 0;
while (pixelsList.length != 0) {
if (!pixelAdded && !skipDiagonals) {
lines.push(line);
line = [];
line.push(pixelsList[0]);
pixelsList.splice(0, 1);
} else if (!pixelAdded) {
skipDiagonals = false;
}
pixelAdded = false;
for (var i = 0; i < pixelsList.length; i++) {
if ((skipDiagonals && (
line[line.length - 1].x + 1 == pixelsList[i].x && line[line.length - 1].y == pixelsList[i].y ||
line[line.length - 1].x - 1 == pixelsList[i].x && line[line.length - 1].y == pixelsList[i].y ||
line[line.length - 1].x == pixelsList[i].x && line[line.length - 1].y + 1 == pixelsList[i].y ||
line[line.length - 1].x == pixelsList[i].x && line[line.length - 1].y - 1 == pixelsList[i].y)) || (!skipDiagonals && (
line[line.length - 1].x + 1 == pixelsList[i].x && line[line.length - 1].y + 1 == pixelsList[i].y ||
line[line.length - 1].x + 1 == pixelsList[i].x && line[line.length - 1].y - 1 == pixelsList[i].y ||
line[line.length - 1].x - 1 == pixelsList[i].x && line[line.length - 1].y + 1 == pixelsList[i].y ||
line[line.length - 1].x - 1 == pixelsList[i].x && line[line.length - 1].y - 1 == pixelsList[i].y
))) {
line.push(pixelsList[i]);
pixelsList.splice(i, 1);
i--;
pixelAdded = true;
skipDiagonals = true;
}
}
}
lines.push(line);
return lines;
}