Algorithm to group sets of points together that follow a direction

前端 未结 3 584
余生分开走
余生分开走 2020-12-04 12:35

Note: I am placing this question in both the MATLAB and Python tags as I am the most proficient in these languages. However, I welcome solutions in any language.

3条回答
  •  抹茶落季
    2020-12-04 13:11

    Note 1: It has a number of settings -> which for other images may need to altered to get the result you want see % Settings - play around with these values

    Note 2: It doesn't find all of the lines you want -> but its a starting point....

    To call this function, invoke this in the command prompt:

    >> [h, v] = testLines;
    

    We get:

    >> 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
    

    A figure is also generated that draws the lines through each proper set of points:

    enter image description here

    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)

提交回复
热议问题