NCF参数化建筑论坛

标题: 提取图片颜色灰度,以孔的形式表现图片(c#代码) [打印本页]

作者: wangjunxiong    时间: 2017-4-7 18:58
标题: 提取图片颜色灰度,以孔的形式表现图片(c#代码)
本帖最后由 wangjunxiong 于 2017-4-7 19:14 编辑

       利用穿孔的办法把图片的内容显示出来,在铝板行业似乎有点神秘感。GH中的Image sampler 倒是可以做到,但总感觉不能随心控制,另外也想知道这里面的工作原理,所以整理了一个代码实现这一功能。本帖子主要是想说明c#怎么提取图片颜色的灰度值。
       也许大伙都被我说懵了,先上图:
图片效果:
[attach]47019[/attach]

利用孔显示的效果:
    [attach]47020[/attach]   



图片效果:
[attach]47021[/attach]

利用孔显示的效果:
[attach]47022[/attach]

图片效果:
[attach]47023[/attach]

利用孔显示的效果:
[attach]47024[/attach]


以上实现的思路是依据灰度值的大小影响孔径大小。以下讲解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());


至此,代码已完成。
输入参数如下图:
[attach]47032[/attach]

上个美女的图片结束这个帖子:
图片
[attach]47033[/attach]

排孔图:
[attach]47034[/attach]

放大局部:
[attach]47035[/attach]


ps:做这个代码的时候,一直卡在循环环节,孔直径和孔数量对应不上,主要是把循环次数的对象搞错。
       另外,我自己做了个UI,所以没依附在GH中,但原理是一样的。



作者: 月之眼    时间: 2017-4-7 23:29
好久没看到这么经典的帖子了
作者: skywoolf    时间: 2017-4-8 10:40
赞!好久不见果然是厚积薄发!
作者: 抓蝴蝶    时间: 2017-4-8 18:40
好好学习下,孔太密集电脑玩不动
作者: 建筑师哈哈    时间: 2017-4-10 16:07
确实很好的一股清流~
作者: JACK...    时间: 2017-5-19 14:06
nice biancheng
作者: Horseedow    时间: 2017-6-29 18:59
66666666666
作者: archsamxian    时间: 2017-8-18 18:12
代码是一直的痛处,希望大大们能给予学习之路的指导~
作者: wangjunxiong    时间: 2017-8-19 12:06
archsamxian 发表于 2017-8-18 18:12
代码是一直的痛处,希望大大们能给予学习之路的指导~

耐得住寂寞,沉得住气,端起书看c#基础,然后.......... 先把这步做了,否则就没有然后了......
作者: 展颜    时间: 2017-10-6 18:22
大佬好!请问这个代码怎么用啊?是rhinoscript,还是grasshopper 的电池?
作者: wangjunxiong    时间: 2017-10-15 19:09
展颜 发表于 2017-10-6 18:22
大佬好!请问这个代码怎么用啊?是rhinoscript,还是grasshopper 的电池?

可以用GH中的C#实现。rhinoscript是VB言语,不能搞混了哦。
作者: 展颜    时间: 2017-10-23 20:07
wangjunxiong 发表于 2017-10-15 19:09
可以用GH中的C#实现。rhinoscript是VB言语,不能搞混了哦。

谢谢!帖子里的那种用户界面,应该没有贴出来代码吧?贴出来的是核心运算代码
作者: wangjunxiong    时间: 2017-11-9 09:10
展颜 发表于 2017-10-23 20:07
谢谢!帖子里的那种用户界面,应该没有贴出来代码吧?贴出来的是核心运算代码

用户界面是一堆类文件。
作者: 浪迹    时间: 2018-4-16 11:47
怎么样呀,可不可以操作一下
作者: 浪迹    时间: 2018-4-16 15:20
怎么样可以联系你!急急急

作者: 浪迹    时间: 2018-4-27 16:15
今天我有来了,还是同一个问题!
作者: wx_guu4Uuq0    时间: 2018-4-28 09:48
太好了,非常值得学习
作者: 丰成_zlkH9    时间: 2018-4-28 10:12
感谢大神的分享

作者: 浪迹    时间: 2018-4-28 10:29
可不可以教教我!
作者: 浪迹    时间: 2018-4-29 08:43
求教!求教!求教!求教!!!!!!!!!!!!!
作者: 浪迹    时间: 2018-4-30 13:38
{:19:
作者: 浪迹    时间: 2018-5-6 15:06
天天过来看看,看一下你什么时候会过来
作者: haoryh    时间: 2018-5-7 11:13
这个代码要怎么能才使用呢?
作者: haoryh    时间: 2018-5-7 11:14
楼主图片上那个工具是什么来的呀?能不能共享一下?付费也可以。
作者: haoryh    时间: 2018-5-7 11:27
要怎么才能联系到楼主呀,能不能留个联系方式?
作者: pan969998pan    时间: 2018-8-11 16:56
我自己用犀牛的gh做的 C+真心不错但是需要学习一段时间才能编写!还是gh台阶稍微低点吧!
作者: 人在江湖飘    时间: 2018-9-7 18:50
神贴,看不懂,但感觉等我学到后面的时候有帮助
作者: wuch1    时间: 2019-2-25 13:13
神贴,看不懂,但感觉等我学到后面的时候有帮助
作者: huz888888888    时间: 2019-6-11 11:15
太牛了。
作者: mayunyun    时间: 2019-6-11 19:23
展颜 发表于 2017-10-23 20:07
谢谢!帖子里的那种用户界面,应该没有贴出来代码吧?贴出来的是核心运算代码

牛钗,好好学习
作者: 天地正气    时间: 2019-12-10 21:08
pan969998pan 发表于 2018-8-11 16:56
我自己用犀牛的gh做的 C+真心不错但是需要学习一段时间才能编写!还是gh台阶稍微低点吧!

中间那三个是什么电池?
作者: 天地正气    时间: 2019-12-10 21:08
pan969998pan 发表于 2018-8-11 16:56
我自己用犀牛的gh做的 C+真心不错但是需要学习一段时间才能编写!还是gh台阶稍微低点吧!

确实更简便,佩服
作者: pan969998pan    时间: 2020-4-9 14:23
天地正气 发表于 2019-12-10 21:08
确实更简便,佩服

算法打包的!看上去就没那么乱了!




欢迎光临 NCF参数化建筑论坛 (http://www.ncf-china.com/) Powered by Discuz! X3.2