我需要知道如何计算ISO/IEC 18004:2000 Annex E 表中定义的 QR 码对齐模式的位置。
我不明白它是如何计算的。例如,如果您采用版本 16,则使用 {6,26,50,74} 计算位置,点之间的距离为 {20,24,24}。如果点之间的距离 {22,24,22} 分布更均匀,为什么不是 {6,28,52,74}?
我想知道如何在程序上生成它。
我需要知道如何计算ISO/IEC 18004:2000 Annex E 表中定义的 QR 码对齐模式的位置。
我不明白它是如何计算的。例如,如果您采用版本 16,则使用 {6,26,50,74} 计算位置,点之间的距离为 {20,24,24}。如果点之间的距离 {22,24,22} 分布更均匀,为什么不是 {6,28,52,74}?
我想知道如何在程序上生成它。
虽然规范确实提供了对齐表,但这是一个合理的问题(我发现自己有一个:-)) - 以程序方式生成位置的可能性有其优点(更容易错字的代码,更小的代码占用空间,知道位置的模式/属性)。
我很高兴地报告,是的,存在一个程序(而且它甚至相当简单)。规范本身说明了大部分内容:
[对齐模式] 在时序模式和符号的另一侧之间尽可能均匀地间隔,在时序模式和符号内部的第一个对齐模式之间容纳任何不均匀的间距。
也就是说,只有第一和第二坐标之间的间隔可以不同于其余的间隔。其余的必须相等。当然,另一个重要的一点是,为了让 AP 与时序模式达成一致,间隔必须是均匀的。剩下的棘手的一点就是正确地四舍五入。
无论如何 - 这是打印对齐位置表的代码:
def size_for_version(version):
return 17 + 4 * version
def alignment_coord_list(version):
if version == 1:
return []
divs = 2 + version // 7
size = size_for_version(version)
total_dist = size - 7 - 6
divisor = 2 * (divs - 1)
# Step must be even, for alignment patterns to agree with timing patterns
step = (total_dist + divisor // 2 + 1) // divisor * 2 # Get the rounding right
coords = [6]
for i in range(divs - 2, -1, -1): # divs-2 down to 0, inclusive
coords.append(size - 7 - i * step)
return coords
for version in range(1, 40 + 1): # 1 to 40 inclusive
print("V%d: %s" % (version, alignment_coord_list(version)))
这是一个 Python 解决方案,它基本上等同于@jgosar 发布的 C# 解决方案,除了它更正了版本 32 与thonky.com 表的偏差(其他解决方案报告倒数第二个位置为 110,而链接表显示 112 ):
def get_alignment_positions(version):
positions = []
if version > 1:
n_patterns = version // 7 + 2
first_pos = 6
positions.append(first_pos)
matrix_width = 17 + 4 * version
last_pos = matrix_width - 1 - first_pos
second_last_pos = (
(first_pos + last_pos * (n_patterns - 2) # Interpolate end points to get point
+ (n_patterns - 1) // 2) # Round to nearest int by adding half
# of divisor before division
// (n_patterns - 1) # Floor-divide by number of intervals
# to complete interpolation
) & -2 # Round down to even integer
pos_step = last_pos - second_last_pos
second_pos = last_pos - (n_patterns - 2) * pos_step
positions.extend(range(second_pos, last_pos + 1, pos_step))
return positions
校正包括首先将倒数第二个位置(向上或向下)舍入到最接近的整数,然后向下舍入到最接近的偶数(而不是直接向下舍入到最接近的偶数)。
免责声明:与@jgosar 一样,我不知道thonky.com 表是否正确(我不会购买规格来找出答案)。我只是验证了(通过将表格粘贴到上述函数周围的合适包装器中)我的解决方案与当前版本中的表格匹配。
对评分最高的答案有一些评论表明它不是 100% 准确的,所以我也在贡献我的解决方案。
我的解决方案是用 C# 编写的。将其翻译成您选择的语言应该很容易。
private static int[] getAlignmentCoords(int version)
{
if (version <= 1)
{
return new int[0];
}
int num = (version / 7) + 2;//number of coordinates to return
int[] result = new int[num];
result[0] = 6;
if (num == 1)
{
return result;
}
result[num - 1] = 4 * version + 10;
if (num == 2)
{
return result;
}
result[num - 2] = 2 * ((result[0] + result[num - 1] * (num - 2)) / ((num - 1) * 2)); //leave these brackets alone, because of integer division they ensure you get a number that's divisible by 2
if (num == 3)
{
return result;
}
int step = result[num - 1] - result[num - 2];
for (int i = num - 3; i > 0; i--)
{
result[i] = result[i + 1] - step;
}
return result;
}
我得到的值与此处显示的值相同:http ://www.thonky.com/qr-code-tutorial/alignment-pattern-locations/
总结起来,第一个坐标总是6。
最后一个坐标总是比图像大小小 7。图像大小计算为 4*version+17,因此最后一个坐标为 4*version+10。
如果坐标精确均匀分布,则最后一个坐标之前的位置将是 (first_coordinate+(num-2) * last_coordinate)/(num-1),其中 num 是所有坐标的数量。但是坐标不是均匀分布的,所以这个位置必须减少到偶数。
其余坐标中的每一个与下一个坐标之间的距离与最后两个坐标之间的距离相同。
免责声明:我没有阅读任何文档,我只是编写了一些代码来生成与我链接到的表中相同的数字序列。
对不起我的英语。我希望这可以帮助你,而不是以后回复。首先,标准忘记了一个重要的事情是左上角是用(0,0)定义的。{ 6, 26, 50, 74 } 表示对齐点的行坐标和 col 坐标,我不知道他们为什么这样做,也许是为了节省空间。但我们结合所有值,例如:
{ 6, 26, 50, 74 }
我们得到:
{ 6 , 6 } ---> ( the x coordinate is 6, and the y is 6, from top/left )
{ 6 , 26 }
{ 6 , 50 }
{ 6 , 74 }
{ 26, 26 }
{ 26, 50 }
{ 26, 74 }
{ 50, 50 }
{ 50, 74 }
{ 74, 74 }
这些点是对齐模式中心的实际坐标。Ps:如果一个位置有位置检测模式,我们会忽略输出对齐,比如位置(6, 6)。
我以前也有这个问题,但是现在我解决了,希望你也能解决。
祝你好运~
我不知道这是否是一个有用的问题。它就是这样,如果它是 {22,24,22} 并不重要。你问来干什么?我猜它的间距应该是 4 个模块的倍数。
从@ericsoe 的回答开始,并注意到它对于 v36 和 v39 是不正确的(感谢@Ana 的评论),我开发了一个返回正确序列的函数。请原谅 JavaScript(虽然很容易翻译成其他语言):
function getAlignmentCoordinates(version) {
if (version === 1) {
return [];
}
const intervals = Math.floor(version / 7) + 1;
const distance = 4 * version + 4; // between first and last alignment pattern
const step = Math.ceil(distance / intervals / 2) * 2; // To get the next even number
return [6].concat(Array.from(
{ length: intervals },
(_, index) => distance + 6 - (intervals - 1 - index) * step)
);
}