将遵循方向的点集组合在一起的算法
image
image-processing
matlab
python
5
0

注意:我将这个问题同时放在MATLAB和Python标记中,因为我最精通这些语言。但是,我欢迎使用任何语言的解决方案。


问题序言

我用鱼眼镜头拍摄了图像。此图像由带有一堆方形对象的图案组成。我要对该图像进行的操作是检测每个正方形的质心,然后使用这些点对图像进行不失真-具体来说,我正在寻找正确的失真模型参数。应该注意的是,并非所有正方形都需要被检测到。只要他们中的大多数都可以,那完全没问题.....但这不是本文的重点。我已经编写了参数估计算法,但是问题在于它需要在图像中显示共线的点。

我想问的基本问题是这些点,将它们组合在一起以使每个组由一条水平线或一条垂直线组成的最佳方法是什么?

我的问题的背景

对于我要问的问题,这并不是很重要,但是如果您想知道我从哪里获得数据并进一步了解我要问的问题,请阅读。如果您不感兴趣,则可以直接跳到下面的“ 问题设置”部分。


我正在处理的图像示例如下所示:

在此处输入图片说明

它是960 x 960的图像。该图像原本的分辨率更高,但是我对图像进行了二次采样,以加快处理时间。如您所见,图像中散布了一堆正方形图案。另外,我计算出的质心是相对于上面的子采样图像。

我设置的用于检索质心的管道如下:

  1. 执行Canny Edge检测
  2. 专注于将误报率降至最低的目标区域。感兴趣的区域基本上是正方形,没有覆盖其一侧的黑色胶带。
  3. 查找所有不同的闭合轮廓
  4. 对于每个不同的闭合轮廓...

    一个。执行哈里斯角点检测

    b。确定结果是否有4个角点

    C。如果是这样,则此轮廓属于一个正方形并找到该形状的质心

    d。如果不是,则跳过此形状

  5. 将步骤4中所有检测到的质心放入矩阵中以进行进一步检查。

这是上面图像的示例结果。每个检测到的正方形都有四个点,根据其相对于正方形本身的位置进行颜色编码。对于我检测到的每个质心,我都会在图像本身中的那个质心的右边写一个ID。

在此处输入图片说明

在上面的图像中,检测到了37个正方形。

问题设定

假设我有一些图像像素点存储在N x 3矩阵中。前两列是x (水平)和y (垂直)坐标,其中在图像坐标空间中, y坐标是倒置的 ,这意味着正y向下移动。第三列是与该点关联的ID。

这是一些用MATLAB编写的代码,它们采用这些点,将它们绘制到2D网格上,并用矩阵的第三列标记每个点。如果您阅读了以上背景知识,这些就是上面概述的算法所检测到的点。

data = [ 475.  ,  605.75,    1.;
       571.  ,  586.5 ,    2.;
       233.  ,  558.5 ,    3.;
       669.5 ,  562.75,    4.;
       291.25,  546.25,    5.;
       759.  ,  536.25,    6.;
       362.5 ,  531.5 ,    7.;
       448.  ,  513.5 ,    8.;
       834.5 ,  510.  ,    9.;
       897.25,  486.  ,   10.;
       545.5 ,  491.25,   11.;
       214.5 ,  481.25,   12.;
       271.25,  463.  ,   13.;
       646.5 ,  466.75,   14.;
       739.  ,  442.75,   15.;
       340.5 ,  441.5 ,   16.;
       817.75,  421.5 ,   17.;
       423.75,  417.75,   18.;
       202.5 ,  406.  ,   19.;
       519.25,  392.25,   20.;
       257.5 ,  382.  ,   21.;
       619.25,  368.5 ,   22.;
       148.  ,  359.75,   23.;
       324.5 ,  356.  ,   24.;
       713.  ,  347.75,   25.;
       195.  ,  335.  ,   26.;
       793.5 ,  332.5 ,   27.;
       403.75,  328.  ,   28.;
       249.25,  308.  ,   29.;
       495.5 ,  300.75,   30.;
       314.  ,  279.  ,   31.;
       764.25,  249.5 ,   32.;
       389.5 ,  249.5 ,   33.;
       475.  ,  221.5 ,   34.;
       565.75,  199.  ,   35.;
       802.75,  173.75,   36.;
       733.  ,  176.25,   37.];

figure; hold on;
axis ij;
scatter(data(:,1), data(:,2),40, 'r.');
text(data(:,1)+10, data(:,2)+10, num2str(data(:,3)));

同样在Python中,使用numpymatplotlib ,我们有:

import numpy as np
import matplotlib.pyplot as plt

data = np.array([[ 475.  ,  605.75,    1.  ],
   [ 571.  ,  586.5 ,    2.  ],
   [ 233.  ,  558.5 ,    3.  ],
   [ 669.5 ,  562.75,    4.  ],
   [ 291.25,  546.25,    5.  ],
   [ 759.  ,  536.25,    6.  ],
   [ 362.5 ,  531.5 ,    7.  ],
   [ 448.  ,  513.5 ,    8.  ],
   [ 834.5 ,  510.  ,    9.  ],
   [ 897.25,  486.  ,   10.  ],
   [ 545.5 ,  491.25,   11.  ],
   [ 214.5 ,  481.25,   12.  ],
   [ 271.25,  463.  ,   13.  ],
   [ 646.5 ,  466.75,   14.  ],
   [ 739.  ,  442.75,   15.  ],
   [ 340.5 ,  441.5 ,   16.  ],
   [ 817.75,  421.5 ,   17.  ],
   [ 423.75,  417.75,   18.  ],
   [ 202.5 ,  406.  ,   19.  ],
   [ 519.25,  392.25,   20.  ],
   [ 257.5 ,  382.  ,   21.  ],
   [ 619.25,  368.5 ,   22.  ],
   [ 148.  ,  359.75,   23.  ],
   [ 324.5 ,  356.  ,   24.  ],
   [ 713.  ,  347.75,   25.  ],
   [ 195.  ,  335.  ,   26.  ],
   [ 793.5 ,  332.5 ,   27.  ],
   [ 403.75,  328.  ,   28.  ],
   [ 249.25,  308.  ,   29.  ],
   [ 495.5 ,  300.75,   30.  ],
   [ 314.  ,  279.  ,   31.  ],
   [ 764.25,  249.5 ,   32.  ],
   [ 389.5 ,  249.5 ,   33.  ],
   [ 475.  ,  221.5 ,   34.  ],
   [ 565.75,  199.  ,   35.  ],
   [ 802.75,  173.75,   36.  ],
   [ 733.  ,  176.25,   37.  ]])

plt.figure()
plt.gca().invert_yaxis()

plt.plot(data[:,0], data[:,1], 'r.', markersize=14)

for idx in np.arange(data.shape[0]):
    plt.text(data[idx,0]+10, data[idx,1]+10, str(int(data[idx,2])), size='large')

plt.show()

我们得到:

在此处输入图片说明


回到问题

如您所见,这些点或多或少呈网格状,您可以看到我们可以在这些点之间形成线。具体来说,您会看到有些线可以水平和垂直形成。

例如,如果您在问题的背景部分中引用图像,则可以看到可以水平排列的5组点。例如,点23、26、29、31、33、34、35、37和36组成一组。点19、21、24、28、30和32组成另一个组,依此类推。在垂直方向上类似,我们可以看到点26、19、12和3组成一组,点29、21、13和5组成另一组,依此类推。


要问的问题

我的问题是:有什么方法可以成功地将水平分组和垂直分组中的点分别进行分组(假设这些点可以处于任何方向)?

条件

  1. 每行必须至少有三个点。如果小于此值,则不属于细分。因此,点36和10不能视为垂直线,类似地,孤立点23也不应视为垂直线,但是它是第一水平分组的一部分。

  2. 上面的校准图案可以处于任何方向。但是,对于我正在处理的问题,您可以获得的最糟糕的指导是您在背景部分中看到的内容。


预期产量

输出将是一对列表,其中第一个列表包含元素,每个元素为您提供一系列形成水平线的点ID。同样,第二个列表具有元素,其中每个元素为您提供形成垂直线的一系列点ID。

因此,水平序列的预期输出将如下所示:

的MATLAB

horiz_list = {[23, 26, 29, 31, 33, 34, 35, 37, 36], [19, 21, 24, 28, 30, 32], ...};
vert_list = {[26, 19, 12, 3], [29, 21, 13, 5], ....};

蟒蛇

horiz_list = [[23, 26, 29, 31, 33, 34, 35, 37, 36], [19, 21, 24, 28, 30, 32], ....]
vert_list = [[26, 19, 12, 3], [29, 21, 13, 5], ...]

我尝试过的

从算法上讲,我尝试过的是消除在这些点上经历的旋转。我已经进行了主成分分析,并尝试将点相对于计算出的正交基向量进行投影,以使这些点或多或少地位于直的矩形网格上。

一旦有了这些信息,只需进行一些扫描线处理即可,您可以根据水平或垂直坐标上的差异变化对点进行分组。您可以按xy值对坐标进行排序,然后检查这些排序的坐标并寻找较大的变化。遇到此更改后,您可以将更改之间的点分组在一起以形成线条。对每个维度执行此操作将为您提供水平或垂直分组。

关于PCA,这是我在MATLAB和Python中所做的:

的MATLAB

%# Step #1 - Get just the data - no IDs
data_raw = data(:,1:2);

%# Decentralize mean
data_nomean = bsxfun(@minus, data_raw, mean(data_raw,1));

%# Step #2 - Determine covariance matrix
%# This already decentralizes the mean
cov_data = cov(data_raw);

%# Step #3 - Determine right singular vectors
[~,~,V] = svd(cov_data);

%# Step #4 - Transform data with respect to basis
F = V.'*data_nomean.';

%# Visualize both the original data points and transformed data
figure;
plot(F(1,:), F(2,:), 'b.', 'MarkerSize', 14);
axis ij;
hold on;
plot(data(:,1), data(:,2), 'r.', 'MarkerSize', 14);

蟒蛇

import numpy as np
import numpy.linalg as la

# Step #1 and Step #2 - Decentralize mean
centroids_raw = data[:,:2]
mean_data = np.mean(centroids_raw, axis=0)

# Transpose for covariance calculation
data_nomean = (centroids_raw - mean_data).T

# Step #3 - Determine covariance matrix
# Doesn't matter if you do this on the decentralized result
# or the normal result - cov subtracts the mean off anyway
cov_data = np.cov(data_nomean)

# Step #4 - Determine right singular vectors via SVD
# Note - This is already V^T, so there's no need to transpose
_,_,V = la.svd(cov_data)

# Step #5 - Transform data with respect to basis
data_transform = np.dot(V, data_nomean).T

plt.figure()
plt.gca().invert_yaxis()

plt.plot(data[:,0], data[:,1], 'b.', markersize=14)
plt.plot(data_transform[:,0], data_transform[:,1], 'r.', markersize=14)

plt.show()

上面的代码不仅可以重新投影数据,还可以将原始点和投影点一起绘制在一个图中。但是,当我尝试重新投影数据时,这是我得到的图:

在此处输入图片说明

红色的点是原始图像坐标,而蓝色的点被重新投影到基本矢量上以尝试消除旋转。它仍然不能完全胜任这项工作。关于这些点仍然有一些方向,因此,如果我尝试执行扫描线算法,则会不经意地将下面的行(用于水平跟踪)或指向侧面的点(用于垂直跟踪)进行分组,这是不正确的。


也许我想得太过分了,但是您对此有任何见解将不胜感激。如果答案确实是极好的,我将倾向于悬赏,因为我在这个问题上已经停留了很长时间了。

我希望这个问题不会很快就解决。如果您不知道如何解决此问题,那么无论如何,感谢您在阅读我的问题时所付出的时间。

期待您可能有任何见解。非常感谢!

参考资料:
Stack Overflow
收藏
评论
共 3 个回答
高赞 时间 活跃

尽管我不能建议一种比您已经尝试过的方法更好的方法来对给定的质心点列表进行分组,但是我希望以下想法可以对您有所帮助:

由于您对图像的内容非常具体(包含一个正方形区域),我想知道您是否实际上需要根据problem setup提供的数据对质心点进行分组,还是可以使用“ Background to the problem描述的数据Background to the problem 。由于您已经确定了每个检测到的正方形的角以及它们在该给定正方形中的位置,在我看来,通过比较角坐标来确定给定正方形的邻居将非常准确。

因此,为找到任何正方形的右邻域的任何候选者,我建议您比较该正方形的右上角和右下角与任何其他正方形(或一定距离内的任何正方形)的左上角和左下角。允许只小型立式差异,稍大水平的差异,你可以在“匹配”两个正方形,如果同时其对应的角点足够接近。

通过对拐角之间允许的垂直/水平差使用上限,您甚至可以只将这些边界内的最佳匹配正方形指定为邻居

一个问题可能是您没有检测到所有正方形,因此正方形30和32之间有一个相当大的空间。由于您说每行至少需要3个正方形,因此忽略掉可能是可行的在该水平线上的正方形32。如果这不是您的选择,则可以尝试匹配尽可能多的正方形,然后使用先前计算的数据将“缺失”正方形分配给网格中的一个点:

在关于正方形32的示例中,您将检测到它具有上下相邻的27和37。此外,您还应该能够确定正方形27位于第1行中,而37位于第3行中,因此您可以分配正方形到“最佳匹配”行之间的第32行,在这种情况下显然为2。

这种通用方法基本上是您已经尝试过的方法,但是由于您现在正在比较两条线的方向和距离,而不是简单地比较网格中两个点的位置,因此希望它应该更加准确。

另外,作为以前尝试的边节点-您可以使用黑色边角线稍微校正图像的初始旋转吗?这可能会使进一步的失真算法(例如您在注释中与knedlsepp讨论的那些算法)更加准确。 (编辑:我刚才确实读过Parag的注释-通过线的角度比较点当然与预先旋转Image基本相同)

收藏
评论

我正在使用发布图像的裁剪版本作为输入。在这里,我仅讨论网格的方向可以视为接近水平/垂直方向的情况。这可能无法完全解决您的问题,但我认为它可以为您提供一些指导。

在此处输入图片说明

对图像进行二值化处理,以便填充变形的正方形。在这里,我使用一个简单的Otsu阈值。然后对该二进制图像进行距离变换。

在此处输入图片说明

在距离变换的图像中,我们将正方形之间的间隙视为峰值。

要获得水平方向的线,请获取距离图像各的局部最大值,然后找到连接的分量。

要获得垂直方向的线,请获取距离图像各的局部最大值,然后找到连接的分量。

下图显示了以角点为圆找到的水平和垂直线。

水平线和角

垂直线和角

对于较长连接的零部件,您可以拟合曲线(直线或多项式),然后对角点进行分类,例如,基于到曲线的距离,该点在曲线的哪一侧等。

我是在Matlab中完成的。我没有尝试曲线拟合和分类部分。

clear all;
close all;

im = imread('0RqUd-1.jpg');
gr = rgb2gray(im);
% any preprocessing to get a binary image that fills the distorted squares
bw = ~im2bw(gr, graythresh(gr));

di = bwdist(bw);                % distance transform
di2 = imdilate(di, ones(3));    % propagate max

corners = corner(gr);           % simple corners

% find regional max for each column of dist image
regmxh = zeros(size(di2));
for c = 1:size(di2, 2)
    regmxh(:, c) = imregionalmax(di2(:, c));
end
% label connected components
ccomph = bwlabel(regmxh, 8);

% find regional max for each row of dist image
regmxv = zeros(size(di2));
for r = 1:size(di2, 1)
    regmxv(r, :) = imregionalmax(di2(r, :));
end
% label connected components
ccompv = bwlabel(regmxv, 8);

figure, imshow(gr, [])
hold on
plot(corners(:, 1), corners(:, 2), 'ro')
figure, imshow(di, [])
figure, imshow(label2rgb(ccomph), [])
hold on
plot(corners(:, 1), corners(:, 2), 'ro')
figure, imshow(label2rgb(ccompv), [])
hold on
plot(corners(:, 1), corners(:, 2), 'ro')

要获得这些线以用于任意定向的网格,可以将距离图像视为图形并找到最佳路径。请参阅此处,以获得基于图的不错方法。

收藏
评论

注意1:它有许多设置->可能需要更改其他图像以获得想要的结果,您可以看到%设置-使用这些值进行播放

注意2:找不到所需的所有行->而是起点。

要调用此函数,请在命令提示符下调用它:

>> [h, v] = testLines;

我们得到:

>> celldisp(h)

h{1} =
     1     2     4     6     9    10
h{2} =
     3     5     7     8    11    14    15    17
h{3} =
     1     2     4     6     9    10
h{4} =
     3     5     7     8    11    14    15    17
h{5} =
     1     2     4     6     9    10
h{6} =
     3     5     7     8    11    14    15    17
h{7} =
     3     5     7     8    11    14    15    17
h{8} =
     1     2     4     6     9    10
h{9} =
     1     2     4     6     9    10
h{10} =
    12    13    16    18    20    22    25    27
h{11} =
    13    16    18    20    22    25    27
h{12} =
     3     5     7     8    11    14    15    17
h{13} =
     3     5     7     8    11    14    15
h{14} =
    12    13    16    18    20    22    25    27
h{15} =
     3     5     7     8    11    14    15    17
h{16} =
    12    13    16    18    20    22    25    27
h{17} =
    19    21    24    28    30
h{18} =
    21    24    28    30
h{19} =
    12    13    16    18    20    22    25    27
h{20} =
    19    21    24    28    30
h{21} =
    12    13    16    18    20    22    24    25
h{22} =
    12    13    16    18    20    22    24    25    27
h{23} =
    23    26    29    31    33    34    35
h{24} =
    23    26    29    31    33    34    35    37
h{25} =
    23    26    29    31    33    34    35    36    37
h{26} =
    33    34    35    37    36
h{27} =
    31    33    34    35    37

>> celldisp(v)
v{1} =
    33    28    18     8     1
v{2} =
    34    30    20    11     2
v{3} =
    26    19    12     3
v{4} =
    35    22    14     4
v{5} =
    29    21    13     5
v{6} =
    25    15     6
v{7} =
    31    24    16     7
v{8} =
    37    32    27    17     9

还将生成一个图形,该图形通过每个适当的点集绘制线:

在此处输入图片说明

function [horiz_list, vert_list] = testLines

global counter;
global colours; 
close all;

data = [ 475.  ,  605.75,    1.;
       571.  ,  586.5 ,    2.;
       233.  ,  558.5 ,    3.;
       669.5 ,  562.75,    4.;
       291.25,  546.25,    5.;
       759.  ,  536.25,    6.;
       362.5 ,  531.5 ,    7.;
       448.  ,  513.5 ,    8.;
       834.5 ,  510.  ,    9.;
       897.25,  486.  ,   10.;
       545.5 ,  491.25,   11.;
       214.5 ,  481.25,   12.;
       271.25,  463.  ,   13.;
       646.5 ,  466.75,   14.;
       739.  ,  442.75,   15.;
       340.5 ,  441.5 ,   16.;
       817.75,  421.5 ,   17.;
       423.75,  417.75,   18.;
       202.5 ,  406.  ,   19.;
       519.25,  392.25,   20.;
       257.5 ,  382.  ,   21.;
       619.25,  368.5 ,   22.;
       148.  ,  359.75,   23.;
       324.5 ,  356.  ,   24.;
       713.  ,  347.75,   25.;
       195.  ,  335.  ,   26.;
       793.5 ,  332.5 ,   27.;
       403.75,  328.  ,   28.;
       249.25,  308.  ,   29.;
       495.5 ,  300.75,   30.;
       314.  ,  279.  ,   31.;
       764.25,  249.5 ,   32.;
       389.5 ,  249.5 ,   33.;
       475.  ,  221.5 ,   34.;
       565.75,  199.  ,   35.;
       802.75,  173.75,   36.;
       733.  ,  176.25,   37.];

figure; hold on;
axis ij;

% Change due to Benoit_11
scatter(data(:,1), data(:,2),40, 'r.'); text(data(:,1)+10, data(:,2)+10, num2str(data(:,3)));
text(data(:,1)+10, data(:,2)+10, num2str(data(:,3)));

% Process your data as above then run the function below(note it has sub functions)
counter = 0;
colours = 'bgrcmy';
[horiz_list, vert_list] = findClosestPoints ( data(:,1), data(:,2) );


function [horiz_list, vert_list] = findClosestPoints ( x, y )
  % calc length of points
  nX = length(x);
  % set up place holder flags
  modelledH = false(nX,1);
  modelledV = false(nX,1);
  horiz_list = {};
  vert_list = {};

  % loop for all points
  for p=1:nX
    % have we already modelled a horizontal line through these?
    % second last param - true - horizontal, false - vertical
    if modelledH(p)==false
      [modelledH, index] = ModelPoints ( p, x, y, modelledH, true, true );
      horiz_list = [horiz_list index];
    else
      [~, index] = ModelPoints ( p, x, y, modelledH, true, false );
      horiz_list = [horiz_list index];
    end

    % make a temp copy of the x and y and remove any of the points modelled 
    %  from the horizontal -> this  is to avoid them being found in the 
    %  second call.
    tempX = x;
    tempY = y;
    tempX(index) = NaN;
    tempY(index) = NaN;
    tempX(p) = x(p);
    tempY(p) = y(p);
    % Have we found a vertial line?
    if modelledV(p)==false
      [modelledV, index] = ModelPoints ( p, tempX, tempY, modelledV, false, true );
      vert_list = [vert_list index];
    end
  end
end
function [modelled, index] = ModelPoints ( p, x, y, modelled, method, fullRun )
  % p - row in your original data matrix
  % x - data(:,1)
  % y - data(:,2)
  % modelled - array of flags to whether rows have been modelled
  % method   - horizontal or vertical (used to calc graadients)
  % fullRun  - full calc or just to get indexes 
  %            this could be made better by storing the indexes of each horizontal in the method above

  % Settings - play around with these values 
  gradDelta = 0.2;  % find points where gradient is less than this value
  gradLimit = 0.45; % if mean gradient of line is above this ignore
  numberOfPointsToCheck = 7; % number of points to check when look along the line
                        % to find other points (this reduces chance of it
                        % finding other points far away
                        %  I optimised this for your example to be 7
                        %  Try varying it and you will see how it effect the result.

  % Find the index of points which are inline.
  [index, grad] = CalcIndex ( x, y, p, gradDelta, method );
  % check gradient of line
  if abs(mean(grad))>gradLimit
    index = [];
    return
  end
  % add point of interest to index
  index = [p index];

  % loop through all points found above to find any other points which are in
  %  line with these points (this allows for slight curvature
  combineIndex = [];
  for ii=2:length(index)
    % Find inedex of the points found above (find points on curve)
    [index2] = CalcIndex ( x, y, index(ii), gradDelta, method, numberOfPointsToCheck, grad(ii-1) );

    % Check that the point on this line are on the original (i.e. inline -> not at large angle
    if any(ismember(index,index2))
      % store points found
      combineIndex = unique([index2 combineIndex]);
    end
  end

  % copy to index
  index = combineIndex;
  if fullRun
    %  do some plotting
    %  TODO: here you would need to calculate your arrays to output.
    xx = x(index);
    [sX,sOrder] = sort(xx);
    % Check its found at least 3 points
    if length ( index(sOrder) ) > 2
      % flag the modelled on the points found
      modelled(index(sOrder)) = true;
      % plot the data
      plot ( x(index(sOrder)), y(index(sOrder)), colours(mod(counter,numel(colours)) + 1));
      counter = counter + 1;
    end
    index = index(sOrder);
  end
end  
function [index, gradCheck] = CalcIndex ( x, y, p, gradLimit, method, nPoints2Consider, refGrad )
  % x - data(:,1)
  % y - data(:,2)
  % p - point of interest
  % method (x/y) or (y\x)
  % nPoints2Consider - only look at N points (options)
  % refgrad          - rather than looking for gradient of closest point -> use this
  %                  - reference gradient to find similar points (finds points on curve)
  nX = length(x);
  % calculate gradient
  for g=1:nX
    if method
      grad(g) = (x(g)-x(p))\(y(g)-y(p));
    else
      grad(g) = (y(g)-y(p))\(x(g)-x(p));
    end
  end
  % find distance to all other points
  delta = sqrt ( (x-x(p)).^2 + (y-y(p)).^2 );
  % set its self = NaN
  delta(delta==min(delta)) = NaN;
  % find the closest points
  [m,order] = sort(delta);

  if nargin == 7
    % for finding along curve
    % set any far away points to be NaN
    grad(order(nPoints2Consider+1:end)) = NaN;
    % find the closest points to the reference gradient within the allowable limit
    index = find(abs(grad-refGrad)<gradLimit==1);
    % store output
    gradCheck = grad(index);
  else
    % find the points which are closes to the gradient of the closest point
    index = find(abs(grad-grad(order(1)))<gradLimit==1);
    % store gradients to output
    gradCheck = grad(index);
  end
end
end
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号