本帖最后由 wangjunxiong 于 2017-4-7 19:14 编辑
利用穿孔的办法把图片的内容显示出来,在铝板行业似乎有点神秘感。GH中的Image sampler 倒是可以做到,但总感觉不能随心控制,另外也想知道这里面的工作原理,所以整理了一个代码实现这一功能。本帖子主要是想说明c#怎么提取图片颜色的灰度值。
也许大伙都被我说懵了,先上图:
图片效果:
利用孔显示的效果:
图片效果:
利用孔显示的效果:
图片效果:
利用孔显示的效果:
以上实现的思路是依据灰度值的大小影响孔径大小。以下讲解C#代码是怎么实现的:
为使图片不失真,排孔的范围应该和图片的长宽相对应,也就是等比例缩放。
C#获取灰度图像的方法 第一种,直接调用GetPixel/SetPixel方法。 我们都知道,图像在计算机中的存在形式是位图,也即一个矩形点阵,每一个点被称为一个像素。在这种方法中,我们通过GDI+中提供的GetPixel方法来读取像素的颜色,并加以计算,然后再使用SetPixel方法将计算后的颜色值应用到相应的像素上去,这样便可以得到灰度图像。 上边提到的“计算”便是指得到灰度图像的计算,其公式是: r = (像素点的红色分量 + 像素点的绿色分量 + 像素点的蓝色分量) / 3 最后得到的r便是需要应用到原像素点的值。具体的编程实现也非常的简单,只需要遍历位图的每一个像素点,然后使用SetPixel方法将上边计算得到的值应用回去即可。
以上文字源自度娘。
如果图片是800*800大小,我们可以把排孔的Rectangle设置为4000*4000 (放大5倍或者其它倍数),另外考虑到铝板本身需要一个无孔偏移,可以设定到孔的边缘为20mm,那么实际大小为4020*4020 ,这个就是铝板的尺寸,而排孔的尺寸仍然是4000*4000 ;那为什么需要放大呢,因为像素相对而言是很小的,也可以理解为一个挨着一个无间隙排列的,放大的目的是拉开像素点之间的距离,使之有间隙。800*800的像数可以理解为长度方向和宽度方向各有800个像素点,4000/800=5 ,这个就是间隙,如果间隙过小,而又不想放大倍数,那么只能考虑多个像素点跳选,或是2的倍数或是3的倍数,当倍数越大排孔显示越模糊。
代码:
double imageWidth = (double)imageForPunching.Width;
double imageHeight = (double)imageForPunching.Height;
Rhino.Geometry.Rectangle3d rec = new Rectangle3d(new Plane(localPoint, Vector3d.XAxis, Vector3d.YAxis), imageWidth * zoom + offSet * 2, imageHeight * zoom + offSet * 2);
Rhino.Geometry.Rectangle3d inRec = new Rectangle3d(new Plane(new Point3d(localPoint.X + offSet, localPoint.Y + offSet, 0), Vector3d.XAxis, Vector3d.YAxis), imageWidth * zoom, imageHeight * zoom);
Line lineX = new Line(new Point3d(localPoint.X + offSet, localPoint.Y + offSet + imageHeight * zoom, 0), Vector3d.XAxis, imageWidth * zoom);//等分点使用用曲线
Line lineY = new Line(new Point3d(localPoint.X + offSet, localPoint.Y + offSet + imageHeight * zoom, 0), -Vector3d.YAxis, imageHeight * zoom);//等分点使用用曲线
outCurveList.Add(rec.ToNurbsCurve());
outCurveList.Add(inRec.ToNurbsCurve());
double lineXLength = lineX.Length;
double lineYLength = lineY.Length;
int xCount = (int)(lineXLength / hDist);//X方向的数量计算
int yCount = (int)(lineYLength / vDist);//Y方向的数量计算
double imageWidthDist = imageWidth / (xCount + 1);//也就是通过x方向的数量求得ImageWidth的间隔。
double imageHeightDist = imageHeight / (yCount + 1);//也就是通过Y方向的数量求得ImageHeight的间隔。
List<double> varRadList = new List<double>();
List<Point3d> endPointList = new List<Point3d>();
Color currentColor;
int r;
double db;
Bitmap currentBitmap = new Bitmap(imageForPunching);//图片转换
for (int i = 0; i < xCount + 1; i++) //循环取值,注意使用长度对象
{
for (int j = 0; j < yCount + 1; j++)
{
int xint, yint;
xint = (int)(i * imageWidthDist);//像素为整数,但是间隔的倍数不一定是整数,所以要转换。
yint = (int)(j * imageHeightDist);
if (xint > imageForPunching.Width)//做一个判断。
{
xint = imageForPunching.Width;
}
if (yint > imageForPunching.Width)
{
yint = imageForPunching.Height;
}
currentColor = currentBitmap.GetPixel(xint, yint);//颜色取值的核心函数
r =(currentColor.R + currentColor.G + currentColor.B) / 3;//取灰度
db = maxiRad / 255 * r;//颜色取值为0到255,转换为相应的直径值。
if (db < miniRad)
{
varRadList.Add(miniRad);//转换为直径
}
else
{
varRadList.Add(maxiRad / 255 * r);//转换为直径
}
}
}//得到直径集合。
Point3d[] outPointX;
Rhino.Geometry.LineCurve lineCurveX = new LineCurve(lineX);
lineCurveX.DivideByCount(xCount, true, out outPointX);//X方向等分返回点
foreach (Point3d point in outPointX)
{
Rhino.Geometry.Line line = new Rhino.Geometry.Line(point, -Vector3d.YAxis, lineYLength);
Rhino.Geometry.LineCurve lineCurve = new Rhino.Geometry.LineCurve(line);
Point3d[] outPoints;
lineCurve.DivideByCount(yCount, true, out outPoints); //Y方向等分返回点
foreach (Point3d outPoint in outPoints)
{
endPointList.Add(outPoint);//输出点收集
}
}
if (endPointList.Count != varRadList.Count)
{
RhinoApp.WriteLine(endPointList.Count.ToString());
RhinoApp.WriteLine(varRadList.Count.ToString());
Rhino.RhinoApp.WriteLine("半径的数量和画圆的数量对不上!");
circleList.Clear();
return;
}//做一个判断,理论上不会出现的。
for (int i = 0; i < endPointList.Count; i++)
{
Rhino.Geometry.Circle circle = new Circle(Plane.WorldXY, endPointList, varRadList / 2);
circleList.Add(circle);
endDisplay.AddCircle(circle, System.Drawing.Color.Aqua);
}
endDisplay.AddCurve(rec.ToNurbsCurve());
endDisplay.AddCurve(inRec.ToNurbsCurve());
至此,代码已完成。
输入参数如下图:
上个美女的图片结束这个帖子:
图片:
排孔图:
放大局部:
ps:做这个代码的时候,一直卡在循环环节,孔直径和孔数量对应不上,主要是把循环次数的对象搞错。
另外,我自己做了个UI,所以没依附在GH中,但原理是一样的。
|