前几日,在百度Mma吧里,有朋友问了个问题:
怎么平滑手画线里的锯齿。
如果是想选绘图软件的话,建议:PhotoShop或几何画板之类的;如果是已经绘制好的图片,那么处理起来并不太简单,这里简单说一下如何用Mma处理。为了简单起见,只考虑简单封闭曲线,代码如下:


pts = Position[ImageData[Thinning[ColorNegate@Binarize[g]]],
x_ /; x > 0.5] // DeleteDuplicates;
(*坐标;
Binarize:将图像化为二值图像;
ColorNegate:反色;
Thinning:瘦化曲线;
ImageData:将图像转为矩阵;
Position:获取曲线每个像素的坐标;
*)
n = Length[pts];
t = 0.01;(*平滑参数,0-1之间,越大越平滑*)means = Floor[t n] + 1;
Do[ls = Total[Abs[#]] & /@ (# – pts[[k – 1]] & /@ pts[[k ;;]]);
p = Position[ls, Min[ls]][[1, 1]] + k – 1;
If[p > k, s = pts[[p]];
pts[[p]] = pts[[k]];
pts[[k]] = s;], {k, 2, n – 1}]
Rotate[Graphics[{BSplineCurve[pts[[1 ;; -1 ;; means]],
SplineClosed -> True]}], -Pi/2]
处理后的效果图:

★ 如果你也是Mma爱好者,请将完善此功能。即,可以处理非封闭曲线和交叉曲线等。此外,还可以考虑处理拍摄的照片。
★ 注:例子中的图片是使用Mma中的绘图工具画的。
★ 注:BSplineCurve 是样条曲线函数
也是一个技术帝啊
嘻嘻,正往技术流发展中……
楼主的方法略醉哈,表示从Do开始就看不懂了、我回头弄个通俗点的,应该还可以处理不封闭的情况,但交叉情况,估计不行。。可以想想,两条叉线优化后应该是两条新的交叉线呢还是两条双曲线?这个似乎不可控
实际上封闭和交叉的情况都是可以处理的。
比如,当你看到两条相交的直线时,一般来说你一眼就能识别出其中任何一条直线,即可以判断原直线的走向。原因是两个角恰好摆成两条相交直线的情况很少出现。
即使对于曲线来说,基本上也是一样的,除非它在相交处拐了很大一个弯,这种情况出现也不太多。
对了,后面的可以略加些注释么,想看懂一下,前面的都懂,都有注释,后面的都不懂,反而没注释,不科学哈~
Do那段程序的目的是:
对于手绘线上的每一点,需要需要找到下一下与之相邻的点。
pts中点的顺序并不正确,需要调整。
如果只是顺序的话可以试试FindCurvePath。
不知道有这个函数啊。
其实我觉得FindCurvePath这个函数不太中用的
看帮助里写例子貌似还可以,不过有时候也挺不给力的。比如这个很直观的曲线,就出问题了,不但把曲线分成了好几段,而且也不怎么连续。
+ 0.6 Sin[10 x]}, {x, 0, 2 Pi, 0.051}];
da = Table[{x, Sin
or = FindCurvePath[da];
Show[{ListLinePlot[da[[#]] & /@ or], ListPlot[da]}, PlotRange -> All]
Show[{ListLinePlot[da[[Flatten[or]]]], ListPlot[da]},
PlotRange -> All]
话说我来了这么多次了 都不知道怎么称呼你好。。。野鹤 你怎么看?
“野鹤”就挺好的嘛。
昨晚花了一个小时看懂了你的代码,收获良多^_^
今天想到,如果反其道而行,先膨化再瘦化呢,于是有了下面的代码:
Nest[ColorNegate@Thinning@ColorNegate@Binarize@Blur[#, 10] &, Binarize@g, 3]
膨化再瘦化后过于尖锐的地方会出现岔线,于是通过再膨化再锐化的方式来解决……效果比你的差远了
from: 用Mma平滑手画线2 | 闲云谷 - 数理版