7

閉じた非自己交差ポリゴンがあります。その頂点は2つのベクトルXとYに保存されます。最後に、XとYの値は0と22の間にバインドされます。

サイズ22x22のマトリックスを作成し、ポリゴンの一部がそのビンと重なる場合は各ビンの値をtrueに設定し、それ以外の場合はfalseに設定します。

私の最初の考えは、で定義されたポイントのグリッドを生成し[a, b] = meshgrid(1:22)、それを使用inpolygonしてグリッドのどのポイントがポリゴン内にあるかを判別することでした。

[a b] = meshgrid(1:22);
inPoly1 = inpolygon(a,b,X,Y);

ただし、これは、ビンの中心がポリゴンに含まれている場合、つまり下の画像で赤い形状を返す場合にのみtrueを返します。ただし、必要なのは緑色の線に沿ったものです(ただし、まだ不完全な解決策です)。

緑のブロブを取得するために、を4回呼び出しましたinpolygon。比較するたびに、ポイントのグリッドをNE、NW、SE、またはSWのいずれかで1/2シフトしました。これは、ビンのコーナーがポリゴン内にあるかどうかをテストするのと同じです。

inPoly2 = inpolygon(a-.5,b-.5,X,Y) | inpolygon(a+.5,b-.5,X,Y) | inpolygon(a-.5,b+5,X,Y) | inpolygon(a+.5,b+.5,X,Y);

これは部分的な解決策を提供しますが、頂点がビンに含まれているが、ビンのコーナーが含まれていない場合は失敗します。

この問題を攻撃するためのより直接的な方法はありますか?できれば、より読みやすいコードを生成するソリューションがありますか?

ここに画像の説明を入力してください

このプロットは次のように描かれています。

imagesc(inPoly1 + inPoly2); hold on;
line(a, b, 'w.');
line(X, Y, 'y); 
4

6 に答える 6

5

1つの提案は、polybool関数を使用することです(2008b以前では使用できません)。2つのポリゴンの交点を検出し、結果の頂点(または頂点が存在しない場合は空のベクトル)を返します。ここで使用するには、グリッド内のすべての正方形を反復処理して(arrayfunを使用して)、polyboolへの出力引数が空(オーバーラップなしなど)であるかどうかを確認します。

N=22;
sqX = repmat([1:N]',1,N);
sqX = sqX(:);
sqY = repmat(1:N,N,1);
sqY = sqY(:);

intersects = arrayfun((@(xs,ys) ...
      (~isempty(polybool('intersection',X,Y,[xs-1 xs-1 xs xs],[ys-1 ys ys ys-1])))),...
      sqX,sqY);

intersects = reshape(intersects,22,22);

結果の画像は次のとおりです。

ここに画像の説明を入力してください

プロットのコード:

imagesc(.5:1:N-.5,.5:1:N-.5,intersects');
hold on;
plot(X,Y,'w');
for x = 1:N
    plot([0 N],[x x],'-k');
    plot([x x],[0 N],'-k');
end
hold off;
于 2012-09-04T19:07:29.463 に答える
1

この擬似コードアルゴリズムはどうですか?

For each pair of points p1=p(i), p2=p(i+1), i = 1..n-1
    Find the line passing through p1 and p2
    Find every tile this line intersects // See note
    Add intersecting tiles to the list of contained tiles

Find the red area using the centers of each tile, and add these to the list of contained tiles

注:この行の実装には少し手間がかかりますが、かなり単純でよく知られたアルゴリズムがあると思います。

また、.NETを使用している場合は、各グリッドタイルに対応する長方形を定義し、どのグリッドタイルがポリゴンと交差するかを確認します。ただし、Matlabで交差点を確認するのが簡単かどうかはわかりません。

于 2012-08-31T23:36:39.910 に答える
1

私はpoly2mask、画像処理ツールボックスで使用することをお勧めします。それは、多かれ少なかれあなたが望むことを行い、また多かれ少なかれあなた自身とサランが提案したことを行います。

于 2012-09-05T12:52:31.253 に答える
1

わずかな改善

まず、「部分的な解決策」を単純化するために、あなたがしているのはただ隅を見ているだけです。ポイントの22x22グリッドを考慮する代わりに、コーナーの23x23グリッドを考慮することができます(小さいグリッドから(-0.5、-0.5)オフセットされます)。それができたら、22x22グリッドにポイントをマークできます。ポリゴンに少なくとも1つのコーナーがあります。

完全な解決策

ただし、実際に探しているのは、ポリゴンが各ピクセルを囲む1x1ボックスと交差するかどうかです。これには必ずしもコーナーが含まれている必要はありませんがポリゴンがボックスの4つの側面の1つと交差している必要があります。

ポリゴンが収容ボックスと交差するピクセルを見つける1つの方法は、次のアルゴリズムを使用することです。

For each pair of adjacent points in the polygon, calling them pA and pB:
    Calculate rounded Y-values: Round(pA.y) and Round(pB.y)
    For each horizontal pixel edge between these two values:
        * Solve the simple linear equation to find out at what X-coordinate
          the line between pA and pB crosses this edge
        * Round the X-coordinate
        * Use the rounded X-coordinate to mark the pixels above and below
          where it crosses the edge
    Do a similar thing for the other axis

したがって、たとえば、とを調べているpA = (1, 1)としpB = (2, 3)ます。

  • まず、丸められたY値1と3を計算しました。
  • 次に、これらの値の間のピクセルエッジを確認します。y = 1.5およびy = 2.5(ピクセルエッジはピクセルから半分オフセットされています
  • これらのそれぞれについて、線形方程式を解いて、pA->pBエッジと交差する場所を見つけます。これにより、、、x = 1.25, y = 1.5およびが得られx = 1.75, y = 2.5ます。
  • これらの交差のそれぞれについて、丸められたX値を取得し、それを使用してエッジの両側のピクセルをマークします。
    • x = 1.251に丸められます(エッジの場合y = 1.5)。したがって、セットの一部としてピクセル(1, 1)をマークできます。(1, 2)
    • x = 1.752に丸められます(エッジの場合y = 2.5)。したがって、(2, 2)とでピクセルをマークでき(2, 3)ます。

これが水平方向のエッジの処理です。次に、垂直方向のものを見てみましょう。

  • まず、丸められたX値を計算します:1と2
  • 次に、ピクセルのエッジを確認します。ここでは、1つだけありますx = 1.5
  • このエッジの場合、線と交わる場所を見つけますpA-> pB。これは私たちに与えx = 1.5, y = 2ます。
  • この交差点では、丸められたY値を取得し、それを使用してエッジの両側のピクセルをマークします。
    • y = 2は2に丸められます。したがって、(1, 2)およびでピクセルをマークでき(2, 2)ます。

終わり!

まあ、ある種。これによりエッジが得られますが、ポリゴンの本体は塗りつぶされません。ただし、これらを以前の(赤の)結果と組み合わせるだけで、完全なセットを取得できます。

于 2012-09-05T13:32:49.593 に答える
0

まあ、厳密に言えば、バウンティタイムは明日まででしたが、私は遅れていると思います;)。しかし、ここに私の試みがあります。まず、ポイントを含む/ポイントに触れるセルをマークする関数。間隔がlx、lyの構造化グリッド、および座標(Xp、Yp)のポイントのセットが与えられた場合、セルを含むセットは次のようになります。

function cells = mark_cells(lx, ly, Xp, Yp, cells)

% Find cell numbers to which points belong.
% Search by subtracting point coordinates from
% grid coordinates and observing the sign of the result.
% Points lying on edges/grid points are assumed
% to belong to all surrounding cells.

sx=sign(bsxfun(@minus, lx, Xp'));
sy=sign(bsxfun(@minus, ly, Yp'));
cx=diff(sx, 1, 2);
cy=diff(sy, 1, 2);

% for every point, mark the surrounding cells
for i=1:size(cy, 1)
    cells(find(cx(i,:)), find(cy(i,:)))=1;
end
end

さて、残りのコード。ポリゴン内のすべてのセグメント(セグメントを1つずつウォークスルーする必要があります)について、セグメントをグリッド線と交差させます。交差は慎重に行われ、水平線と垂直線は別々に、数値の不正確さを避けるために指定されたグリッドポイント座標を使用します。見つかった交点について、mark_cellsを呼び出して、周囲のセルを1にマークします。

% example grid
nx=21;
ny=51;
lx = linspace(0, 1, nx);
ly = linspace(0, 1, ny);
dx=1/(nx-1);
dy=1/(ny-1);
cells = zeros(nx-1, ny-1);

% for every line in the polygon...
% Xp and Yp contain start-end points of a single segment
Xp = [0.15 0.61];
Yp = [0.1 0.78];

% line equation
slope = diff(Yp)/diff(Xp);
inter = Yp(1) - (slope*Xp(1));

if isinf(slope)
    % SPECIAL CASE: vertical polygon segments
    % intersect horizontal grid lines
    ymax = 1+floor(max(Yp)/dy);
    ymin = 1+ceil(min(Yp)/dy);
    x=repmat(Xp(1), 1, ymax-ymin+1);
    y=ly(ymin:ymax);
    cells = mark_cells(lx, ly, x, y, cells);
else
    % SPECIAL CASE: not horizontal polygon segments
    if slope ~= 0
        % intersect horizontal grid lines
        ymax = 1+floor(max(Yp)/dy);
        ymin = 1+ceil(min(Yp)/dy);
        xmax = (ly(ymax)-inter)/slope;
        xmin = (ly(ymin)-inter)/slope;
        % interpolate in x...
        x=linspace(xmin, xmax, ymax-ymin+1);
        % use exact grid point y-coordinates!
        y=ly(ymin:ymax); 
        cells = mark_cells(lx, ly, x, y, cells);
    end

    % intersect vertical grid lines
    xmax = 1+floor(max(Xp)/dx);
    xmin = 1+ceil(min(Xp)/dx);
    % interpolate in y...
    ymax = inter+slope*lx(xmax);
    ymin = inter+slope*lx(xmin);
    % use exact grid point x-coordinates!
    x=lx(xmin:xmax); 
    y=linspace(ymin, ymax, xmax-xmin+1);
    cells = mark_cells(lx, ly, x, y, cells);
end

メッシュ/セグメントの例の出力: 出力

すべてのポリゴンセグメントをウォークスルーすると、ポリゴン「ハロー」が得られます。最後に、ポリゴンの内部は、標準のポリゴン関数を使用して取得されます。コードの詳細が必要な場合はお知らせください。

于 2012-09-10T22:12:42.673 に答える
0

まず、この例では低解像度の円を定義します

X=11+cos(linspace(0,2*pi,10))*5;
Y=11+sin(linspace(0,2.01*pi,10))*5;

あなたの例のように、それは〜22ユニットのグリッドに収まります。次に、リードに従って、メッシュグリッドを宣言し、ポイントがポリゴン内にあるかどうかを確認します。

stepSize=0.1;
[a b] = meshgrid(1:stepSize:22);
inPoly1 = inpolygon(a,b,X,Y);

唯一の違いは、元のソリューションが1ステップを実行した場合、このグリッドはより小さなステップを実行できることです。そして最後に、正方形の「エッジ」内に何かを含めること

inPolyFull=unique( round([a(inPoly1) b(inPoly1)]) ,'rows');

単純にround高解像度グリッドを取得し、ポイントを最も近い低解像度の同等物に適切に丸めます。unique次に、'rows'修飾子を使用して呼び出すことにより、ベクトルスタイルまたはペアワイズ方式ですべての重複を削除します。以上です

結果を表示するには、

[aOrig bOrig] = meshgrid(1:22);
imagesc(1:stepSize:22,1:stepSize:22,inPoly1); hold on;
plot(X,Y,'y');
plot(aOrig,bOrig,'k.');
plot(inPolyFull(:,1),inPolyFull(:,2),'w.'); hold off;

ポリゴンの例

を変更するstepSizeと、速度とメモリを犠牲にして結果を改善するという期待される効果があります。

例のinPoly2と同じ形式の結果が必要な場合は、次を使用できます。

inPoly2=zeros(22);
inPoly2(inPolyFull(:,1),inPolyFull(:,2))=1

お役に立てば幸いです。私はそれについて他のいくつかの方法を考えることができますが、これは最も簡単なようです。

于 2012-09-04T15:12:51.837 に答える