给定许多矩形,按行分组的最佳方法是什么
Given many rectangles, whats the best approach to group by line
TLDR:如何找到水平排列的盒子
假设我有这样一张图片的数据:
我们可以直观地看到我们有两行:
Tare: 11700 kg 10:40:58 am 16-May
Gross: 21300 kg 12:49:34 pm 9-Aug
图中显示的每个蓝色框的数据是:
Top
Left
Width
Height
- 盒子每个角的坐标(
X
、Y
)
我的主要想法是从我的 "grid" 的顶部开始循环遍历 y 的每个值,然后将它们共享最多匹配 "y" 值的框分组,但是它对于看似简单的东西来说似乎太过分了。
不确定从这里到哪里去
我能够使用这段代码(在 JavaScript 中)让盒子排列起来,它基本上找到第一个 "most top left" 盒子,然后找到任何 "intersect"从第一个框的中间开始有一条线
我们不关心箱子的顺序,所以只要我们从任何一行最左边的箱子开始,我们就是黄金。
function getMostTopLeftBox(boxes) {
const sorted = boxes.slice()
.sort(
(a, b) => {
if (a.Left === b.Left) {
return a.Top < b.Top ? -1 : 1;
}
return a.Left < b.Left ? -1 : 1;
}
);
return sorted[0];
}
function getAlignedBoxesFromSet(boxes) {
const mostTopLeftBox = getMostTopLeftBox(boxes);
const line = mostTopLeftBox.Top + (mostTopLeftBox.Height / 2);
return boxes
.filter(({ Top, Height }) => Top < line && (Top + Height) > line)
.sort(({ Left: a }, { Left: b }) => a < b ? -1 : 1)
}
function getAlignedBoxes(boxes) {
let remaining = boxes;
const lines = [];
const next = () => {
const line = getAlignedBoxesFromSet(remaining);
lines.push(line);
remaining = remaining.filter(box => line.indexOf(box) === -1);
if (!remaining.length) {
return;
}
return next();
};
next();
return lines;
}
上面的代码和上面提供的数据集给了我们 this result
但是,它不考虑盒子上的小角度,例如这张图片:
另一个不同盒子的例子,删除了敏感信息:
从上面可以看出,下面的值应该被认为是在同一行上:
Product: [type]
Num Of [type]: 0
[value]: [value]
我可能会为此提出一个新问题,但对此的部分答案是找出一条线的实际曲线,而不是仅仅假设所有线的中线角度都是实际的 "curve" 的线,所以如果我从最左边的框开始,然后前进到第二个框,现在我有两条不同的线,我想找到平滑曲线,然后我会用它来找到下一条框,当我找到每个框时,我想调整这条曲线以找到完整的线,我将进一步调查这个,如果有人有任何提示,请务必提及。
我已经设法解决了这个问题,使用问题中发布的代码变体。
这是解决方案的代码沙箱,我将对此进行完整的描述,但现在是这样的:https://codesandbox.io/s/102xnl7on3
这里是一个根据所有水平线的角度计算出的斜线对框进行分组的示例,如果所有框都是直的,那么结果也会是直线,所以它应该可以工作在所有情况下。
这里还有一个直线的例子:
您可以在与下一个框相交之前看到框内的线条,它每次都这样做,直到找到完整的框线(直到没有更多的线),这比使用平均值更好来自整个数据集的角度。
我希望能够为已经找到的盒子生成一条数学曲线,并应用它来找到下一个盒子,但现在,使用前一个盒子作为锚点效果很好。
TLDR:如何找到水平排列的盒子
假设我有这样一张图片的数据:
我们可以直观地看到我们有两行:
Tare: 11700 kg 10:40:58 am 16-May
Gross: 21300 kg 12:49:34 pm 9-Aug
图中显示的每个蓝色框的数据是:
Top
Left
Width
Height
- 盒子每个角的坐标(
X
、Y
)
我的主要想法是从我的 "grid" 的顶部开始循环遍历 y 的每个值,然后将它们共享最多匹配 "y" 值的框分组,但是它对于看似简单的东西来说似乎太过分了。
不确定从这里到哪里去
我能够使用这段代码(在 JavaScript 中)让盒子排列起来,它基本上找到第一个 "most top left" 盒子,然后找到任何 "intersect"从第一个框的中间开始有一条线
我们不关心箱子的顺序,所以只要我们从任何一行最左边的箱子开始,我们就是黄金。
function getMostTopLeftBox(boxes) {
const sorted = boxes.slice()
.sort(
(a, b) => {
if (a.Left === b.Left) {
return a.Top < b.Top ? -1 : 1;
}
return a.Left < b.Left ? -1 : 1;
}
);
return sorted[0];
}
function getAlignedBoxesFromSet(boxes) {
const mostTopLeftBox = getMostTopLeftBox(boxes);
const line = mostTopLeftBox.Top + (mostTopLeftBox.Height / 2);
return boxes
.filter(({ Top, Height }) => Top < line && (Top + Height) > line)
.sort(({ Left: a }, { Left: b }) => a < b ? -1 : 1)
}
function getAlignedBoxes(boxes) {
let remaining = boxes;
const lines = [];
const next = () => {
const line = getAlignedBoxesFromSet(remaining);
lines.push(line);
remaining = remaining.filter(box => line.indexOf(box) === -1);
if (!remaining.length) {
return;
}
return next();
};
next();
return lines;
}
上面的代码和上面提供的数据集给了我们 this result
但是,它不考虑盒子上的小角度,例如这张图片:
另一个不同盒子的例子,删除了敏感信息:
从上面可以看出,下面的值应该被认为是在同一行上:
Product: [type]
Num Of [type]: 0
[value]: [value]
我可能会为此提出一个新问题,但对此的部分答案是找出一条线的实际曲线,而不是仅仅假设所有线的中线角度都是实际的 "curve" 的线,所以如果我从最左边的框开始,然后前进到第二个框,现在我有两条不同的线,我想找到平滑曲线,然后我会用它来找到下一条框,当我找到每个框时,我想调整这条曲线以找到完整的线,我将进一步调查这个,如果有人有任何提示,请务必提及。
我已经设法解决了这个问题,使用问题中发布的代码变体。
这是解决方案的代码沙箱,我将对此进行完整的描述,但现在是这样的:https://codesandbox.io/s/102xnl7on3
这里是一个根据所有水平线的角度计算出的斜线对框进行分组的示例,如果所有框都是直的,那么结果也会是直线,所以它应该可以工作在所有情况下。
这里还有一个直线的例子:
您可以在与下一个框相交之前看到框内的线条,它每次都这样做,直到找到完整的框线(直到没有更多的线),这比使用平均值更好来自整个数据集的角度。
我希望能够为已经找到的盒子生成一条数学曲线,并应用它来找到下一个盒子,但现在,使用前一个盒子作为锚点效果很好。