8

私は5000x5000のグリッドを持っており、MATLABで癌の分裂の単純なモデルを実装しようとしています。最初に、ランダムな点(x、y)を選択し、そのセルを癌細胞にします。最初の反復では、分割されます。親セルはその場所にとどまり、娘セルは隣接するセルにランダムに割り当てられます。
これまでのところ簡単です。

私の問題はこれです:連続した反復で、娘細胞はしばしばすでに癌細胞を持っている細胞に割り当てられます。この場合、娘細胞に代わって、すでにそこにある細胞を隣接する細胞に「バンプ」させたいと思います。その隣接するセルが空の場合、そのセルは埋められ、プロセスは停止します。そうでない場合は、最後のセルが空のスペースを見つけてプロセスが停止するまで、その場所にすでにあるセルがバンプされます。

これは単純なはずですが、どのようにコーディングするのか、どのようなループを使用するのかわかりません。
私はプログラマーというよりは物理科学者なので、私を単純な人のように扱ってください!

4

2 に答える 2

4

これは、あなたが提供した仕様をほぼ満たしている、一緒にハッキングした機能です。

がん細胞の数が多くなるにつれて、私は遅くなります。

plate基本的に、いくつかの変数、セル位置のグリッドを表す NxN 行列があります (グリッドは既存の matlab 関数の名前であるため、これを a と呼びます)

すばやく反復処理できる点のベクトル。シード位置を選択し、グリッドがいっぱいになるまで while ループを実行します。

ループの反復ごとに、各セルに対して次のことを実行します。

  • 乱数を生成して、その細胞が分裂するかどうかを決定します
  • 分割するランダムな方向を生成します
  • その方向で最初に開いたプレートの位置を見つける
  • その位置に入力します

私はそれを広範囲にテストしていませんが、うまくいくようです。

function simulateCancer(plateSize, pDivide)

plate = zeros(plateSize, plateSize);
nCells = 1;
cellLocations = zeros(plateSize*plateSize,2);

initX = randi(plateSize);
initY = randi(plateSize);

cellLocations(nCells,:) = [initX, initY];

plate(initX, initY) = 1;

f = figure;
a = axes('Parent', f);
im = imagesc(plate, 'Parent', a);


while(nCells < (plateSize * plateSize))
    currentGeneration = currentGeneration+1;
    for i = 1:nCells
        divide = rand();
        if divide <= pDivide
            divideLocation = cellLocations(i,:);
            divideDir = randi(4);
            [x, y, v] = findNewLocation(divideLocation(1), divideLocation(2), plate, divideDir);
            if (v==1)
                nCells = nCells+1;
                plate(x,y) = 1;
                cellLocations(nCells,:) = [x,y];
            end
        end
    end
    set(im,'CData', plate);
    pause(.1);
end

end

function [x,y, valid] = findNewLocation(xin, yin, plate, direction)   
    x = xin;
    y = yin;
    valid = 1;
    % keep looking for new spot if current spot is occupied
    while( plate(x, y) == 1)
       switch direction
            case 1 % divide up
                y = y-1;
            case 2 % divide down
                y = y+1;
            case 3 % divide left
                x = x-1;
            case 4 % divide down
                x = x+1;
            otherwise
            warning('Invalid direction')
            x = xin;
            y = yin;
        return;
       end

       %if there has been a collision with a wall then just quit
       if y==0 || y==size(plate,2)+1 || x==0 || x==size(plate,1)+1 % hit the top
           x = xin; %return original values to say no division happend
           y = yin;
           valid = 0;
           return;
       end

    end


end

注:セルをプッシュすることを考える代わりに、セルを現在の場所に残し、行/列の最後に新しいセルを作成する方法でこれをコーディングしました。意味的には異なりますが、世代を気にしない限り、論理的には同じ最終結果になります。

于 2012-06-22T14:38:33.710 に答える
2

別の質問に触発されて、画像処理技術を使用してこのシミュレーションを実装することを考えました。具体的には、形態学的拡張を使用して癌細胞を拡散させることができます。

アイデアは、次のような構造化要素を使用して各ピクセルを拡張することです。

1 0 0
0 1 0
0 0 0

中央は固定され、もう一方1は残りの 8 つの位置のいずれかにランダムに配置されます。これにより、ピクセルがその方向に効果的に拡張されます。

膨張が実行される方法は、1 つのピクセル セットのみを使用して空白の画像を作成し、単純な OR 演算を使用してすべての結果を累積することです。

処理を高速化するために、すべてのピクセルを考慮する必要はなく、がん細胞のクラスターによって形成された現在のブロックの周囲にあるピクセルのみを考慮する必要があります。内側のピクセルはすでにがん細胞に囲まれており、拡張しても影響はありません。

さらに高速化するために、1 回の呼び出しで同じ方向に拡張するように選択されたすべてのピクセルに対して膨張を実行します。したがって、反復ごとに、最大 8 回の拡張操作を実行します。

これにより、コードは比較的高速になりました (1000x1000 グリッドまでテストしました)。また、すべての反復で同じタイミングを維持します (グリッドがいっぱいになり始めても遅くなりません)。

これが私の実装です:

%# initial grid
img = false(500,500);

%# pick 10 random cells, and set them as cancerous
img(randi(numel(img),[10 1])) = true;

%# show initial image
hImg = imshow(img, 'Border','tight', 'InitialMag',100);

%# build all possible structing elements
%# each one dilates in one of the 8 possible directions
SE = repmat([0 0 0; 0 1 0; 0 0 0],[1 1 8]);
SE([1:4 6:9] + 9*(0:7)) = 1;

%# run simulation until all cells have cancer
BW = false(size(img));
while ~all(img(:)) && ishandle(hImg)
    %# find pixels on the perimeter of all "blocks"
    on = find(bwperim(img,8));

    %# percentage chance of division
    on = on( rand(size(on)) > 0.5 );    %# 50% probability of cell division
    if isempty(on), continue; end

    %# decide on a direction for each pixel
    d = randi(size(SE,3),[numel(on) 1]);

    %# group pixels according to direction chosen
    dd = accumarray(d, on, [8 1], @(x){x});

    %# dilate each group of pixels in the chosen directions
    %# to speed up, we perform one dilation for all pixels with same direction
    for i=1:8
        %# start with an image with only those pixels set
        BW(:) = false;
        BW(dd{i}) = true;

        %# dilate in the specified direction
        BW = imdilate(BW, SE(:,:,i));

        %# add results to final image
        img = img | BW;
    end

    %# show new image
    set(hImg, 'CData',img)
    drawnow
end

また、500x500 のグリッド上に 10 個のランダムな初期がん細胞を含むシミュレーションのアニメーションを作成しました (警告: .gif 画像のサイズは約 1 MB であるため、接続によっては読み込みに時間がかかる場合があります)。

シミュレーション_アニメーション

于 2012-06-23T01:09:44.917 に答える