@lwx228問如何創建生成圖像的公式。 我沒有一路到達底部(就像美麗的動畫一樣這裡),但我已經很接近了。
加載圖像並使用 Canny 濾鏡來查找明暗之間的一些界限。 越接近單個閉環,接下來的事情就越好。 下面的不連續性稍後會顯示偽像,但還不錯。
Original, left. Canny filtered, right.原圖,左邊。 坎尼過濾了,對。
//clear globals();// uncomment this if you change the picture 3 or 4 lines down to make it reload...
If( Try( Type( original ) != "Picture", 1 ), // set to 1 long enough to download once
original = Open(
//"https://i.stack.imgur.com/wtJoA.png", // this was an elephant...the loop closes nicely
// this fish does not close the loop...
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Malayan_fishes_%28PLATE_LXX%29_BHL46234933.jpg/800px-Malayan_fishes_%28PLATE_LXX%29_BHL46234933.jpg", // https://commons.wikimedia.org/wiki/File:Malayan_fishes_(PLATE_LXX)_BHL46234933.jpg
"png"
);
Beep();// comment out the clear globals to prevent re-loading the image over the internet each time
);
New Window( "Original Image", original );
bitmap = New Image( original );
bitmap << filter(
"canny", // TWEAK THESE for different images; you want a single loop for best results
largeThreshold( .5 )/*tracing begins when a large-value edge is found*/,
smallThreshold( .01 )/*tracing stops when the edge value gets too small*/,
radius( 2 )/*a blur-filter, use 0 for no blurring*/,
Repeat( 3 )/* number of repeats of a box-blur; 3 approximates a gaussian-blur filter */
);
New Window( "Original Edge Detection", bitmap );上面的代碼有一個帶註釋的clear globals(),它將重置保存圖像的變量,並在 try() 檢測到沒有圖像時重新加載它。 您可以切換到幾行後的大像圖像。 蜂鳴聲會提醒您重新註釋清晰的全局變量。 第一個 NewWindow() 顯示原始圖像。 然後從原始位圖複製並過濾位圖。 Canny 過濾器是一個邊緣查找器跟隨器,其參數必須針對每個圖像進行調整。 上面的兩張圖片都適用於這些設置(因為大象太簡單了。)最終的 newwindow() 顯示了輪廓。
不幸的是,輪廓是位圖中的。 下面的代碼需要一個形成連續循環的 x,y 坐標列表。
bitmap = bitmap << getpixels;
nr = N Rows( bitmap );
nc = N Cols( bitmap );
points = Loc( bitmap );
// see https://community.jmp.com/t5/JSL-Cookbook/Using-Loc-with-a-2D-Matrix/ta-p/195207
rowlocs = Floor( (points) / nc ) + 1; // nc is the number of columns in the 2D pixmat
collocs = Mod( (points), nc ) + 1; // rowlocs and collocs are 2D indexes (1-based)
// center and scale
rowlocs = rowlocs - Min( rowlocs );
rowlocs = rowlocs / Max( rowlocs );
rowlocs = rowlocs * 2 - 1;
collocs = collocs - Min( collocs );
collocs = collocs / Max( collocs );
collocs = collocs * 2 - 1;
上面,將像素放入名為 bitmap 的矩陣中,並將行數和列數放入 nr 和 nc 中。 使用 loc() 函數定位非零像素。 過濾後的圖片中黑色為 0,白色為 1。 Loc 返回有效的索引,但它們假設位圖是 nr*nc 的一列。 為了追踪輪廓,最好有 x,y 索引。 rowlocs 和 collocs 的計算公式如下:這裡。 繼續將索引縮放到 -1 到 1 的空間...它們不會用於索引,因為它們只指向位圖中的索引。 但它們將用於鄰居測試。
// extract the line-loop. crude, probably slow... first thing that comes to mind...
kdt = KDTable( rowlocs || collocs );
idxSort = J( N Rows( points ), 1, . );
idx = (kdt << K nearest rows( 1, [0, 0] ))[1][1];
idxSort[1] = idx;
For( i = 2, i <= N Rows( points ), i += 1,
kdt << removerows( idx ); // remove this point from the table so
idx = (kdt << K nearest rows( 1, idx ))[1][1]; // can find the next one
idxSort[i] = idx; // save a sorted list of the indexes
);
您可能可以想出其他方法來完成此代碼的功能,也許更快。 它構建一個 2D 坐標的最近鄰表,找到一個起始坐標(最接近 0,0,可能是其他任何位置),然後通過刪除找到的每個坐標並使用刪除的最近鄰鏈來記錄最近鄰鏈。協調尋找下一個。 它將根據需要跳過間隙。製作一個圖表來檢查一切是否正常。
Tracing the Canny outline追踪精明的輪廓
// put the row/col in connected order
rowlocs = rowlocs[idxSort];
collocs = collocs[idxsort];
dt = As Table( rowlocs || collocs );
dt << setdirty( 0 );
dt << Graph Builder(
Size( 514, 444 ),
Show Control Panel( 0 ),
Variables( X( :Col2 ), Y( :Col1 ) ),
Elements( Points( X, Y, Legend( 4 ) ) ),
SendToReport(
Dispatch( {}, "Col1", ScaleBox, {Min( 1.1 ), Max( -1.1 )} ),
Dispatch( {}, "graph title", TextEditBox, {Set Text( "Original Trace" )} ),
Dispatch( {}, "Graph Builder", FrameBox, {Marker Size( 0 )} )
)
);上面的前兩條語句使用之前保存的索引對 row 和 col 索引進行排序。 AsTable 從通過連接行索引和列索引構成的兩列矩陣創建一個數據表。 GraphBuilder 製作圖片。 使用表格按順序選擇點,並驗證圖中的循環是從頭到尾繪製的,而不是從上到下繪製的。
其餘的由一個我不太理解的公式和一堆顯示框組成。
// run the fft
{colx, coly} = FFT( {collocs} );
{rowx, rowy} = FFT( {rowlocs} );
//dt=astable(colx||rowx);dt<<SETDIRTY></SETDIRTY>有兩個 fft() 調用,一個用於 X 軸,一個用於 Y 軸。 rebuild() 函數正在重建 graphbox() line() 函數使用的一對矩陣。 nInterp 滑塊控制從 FFT 數據中插回多少個點,nKeep 滑塊確定為每個插值點保留多少個 fft 數據箱。
Lots of interpolated points make it smooth, but there is not enough data大量插值點使其平滑,但數據不足
Plenty of data, but not enough interpolated points數據很多,但插值點不夠
Seems about right, enough data and enough interpolation似乎是正確的,足夠的數據和足夠的插值
蠻好玩的! 如果有人想在 FFT 上發表更多內容並獲得那些漂亮的圓圈,那就太好了!