一步一步实现自己机器视觉软件中工具的制作和运作,从简单开始(以抓取矩形(gaugeRect)工具为demo,工具组项间协作,四)
我们的gaugeRectform制作完成,在工具组里边双击,秀出来:
代码如下:
RectGaugeForm gaugeRectFr;//202006010712连线工作未做,正在添加roi的四角感知能力
以上鼠标响应双击事件,显示一个form:
if (ispointInRect(pfme, toolitemRect.m_RoiBase1.rcWin))//双击在toolitemRect的矩形框里
{
gaugeRectFr.ShowDialog();
}
没有图像传入,图像传入需要有这样的动作:
很显然,图像输入和这个工具间的连线有巨大关系,是的,我们把这个连线做出来(visionpro能有的,我们也能有):
其实没什么大不了,就是两个工具间画了三条线嘛!怎么画这三条线,代码如下(mouseup事件响应):
endPt.X = e.X;//toolitemgrab指imagesource
endPt.Y = e.Y;//toolitemline指gaugeline
//以下是grab到gaugerect 连线
if (ispointInRect(startPt, toolitemgrab.m_RoiBase1.rcWin) && ispointInRect(endPt, toolitemRect.m_RoiBase1.rcWin))
{//以上可以替换使用ispointinrect201612050822
if (!toolitemRect.已存在图像输入)
{
toolitemRect.已存在图像输入 = true;
grab传递Rect = true;//新增201709230811
float tempy = (float)(toolitemgrab.m_RoiBase1.rcWin.Top / 2.0 + toolitemgrab.m_RoiBase1.rcWin.Bottom / 2.0 + 5);
float tempy1 = (float)(toolitemRect.m_RoiBase1.rcWin.Top / 2.0 + toolitemRect.m_RoiBase1.rcWin.Bottom / 2.0 - 5);
listPtca.Add(new PointF(toolitemgrab.m_RoiBase1.rcWin.Right, tempy));
Random ran = new Random();
int Rn = ran.Next(100, 200);//起点,终点固定,中间连个转折点随机产生,一共四点,三线
listPtca.Add(new PointF(toolitemgrab.m_RoiBase1.rcWin.Right + Rn, tempy));
listPtca.Add(new PointF(toolitemgrab.m_RoiBase1.rcWin.Right + Rn, tempy1));
listPtca.Add(new PointF(toolitemRect.m_RoiBase1.rcWin.Right, tempy1));
globarraypointfg2rc = listPtca.ToArray();//四个点三条线存入数组
listPtca.Clear();//临时变量
}
}
其中, PointF[] globarraypointfg2rc = null;//grab到rect的点序列
好,在paint函数中把这三条线显示出来,代码如下:
if (globarraypointfg2rc != null)
{//再使用一把随机函数,让三条连线颜色的产生也是随机的
Random ran = new Random();
int Rn = ran.Next(100, 200);
int Rx = ran.Next(100, 200);
g.DrawLines(new Pen(Color.FromArgb(Rn, Rx, Rn), 3), globarraypointfg2rc);
}
本节的关键是图像传入,完成工具间的协作,图像及参数在工具间传递起桥梁作用,下面解决图像传入:
第一,我们的相机界面,有鼠标右键响应,一个是保存实时图像,一个是把实时图像发送给工具组,通过消息WmCopydata。
第二,我们在 protected override void DefWndProc(ref System.Windows.Forms.Message m)消息响应函数中接受实时图像,如下:
1, 声明: public struct COPYDATASTRUCT
{
public IntPtr DwData;
public int CbData;
// [MarshalAs(UnmanagedType.LPStr)]
public byte[] LpData;
public Bitmap tempbmp;
}
const int WmCopydata = 0x04AA;
2,在DefWndProc函数中:
switch (m.Msg)
{
case WmCopydata://此处仅有500万图像//已经更改为80万,200万,500万。20161212
{
var mybytes = new COPYDATASTRUCT();
Type mytype = mybytes.GetType();
mybytes = (COPYDATASTRUCT)m.GetLParam(mytype);//mybytes.cbdata// string str = mybytes.LpData;
int tempW= mybytes.tempbmp.Width;
int tempH = mybytes.tempbmp.Height;
glob_buffer8 = new byte[tempW * tempH];
for (int j = 0; j < tempH; j++)
{
for (int i = 0; i < tempW; i = i + 1)
{
int nn = j * tempW + i;
glob_buffer8[nn] = mybytes.LpData[nn];//mybytes.DwData
}
}
realtimeImage = mybytes.tempbmp;
3,传给grab,接着上边:
if (m_bAddgrab)//如果添加了grabitem工具
{
testimagesource.init(tempW, tempH);
testimagesource.IS_orgImg = glob_buffer8; //原来这样可以哦201612091526
//测试是ok的,201612121004
Bitmap tempBmp = realtimeImage;
testimagesource.ISbmp = tempBmp;
testimagesource.mgUpdate();
}
4,传递给gaugerectItem,接着上边:
if (m_bAdd_Rc)//如果添加了gaugerect工具项
{
if (grab传递Rect)//如果两个工具项之间存在连线,则把图像数组给gaugerectform
{
gaugeRectFr.init(tempW, tempH);
gaugeRectFr.GL_orgImg = glob_buffer8;
Bitmap tempBmp = realtimeImage;
gaugeRectFr.GLbmp = tempBmp;
gaugeRectFr.mgUpdate();
}
}
}
break;
default:
base.DefWndProc(ref m);
break;
}
然我们再看一看简单demo的运作过程:
既然能添加,当然也需要能删除,你也可以一试。
删除之后,再添加rectgaugeitem,你可以考虑标定后的图像给rectgaugeform(cali传递rect),即你可以通过删除再添加,改变图像和参数的传递路线,存在时,输入输出,一一对应,要不就乱套了。我们有两个bool值专门来进行限制, toolitemRect.已存在图像输入和 grab传递Rect。
你看到图上有一个坐标系初始化后未用,他可以通过标定后的坐标系参数传递过来。这里是简单示范demo,所以就未示范参数的传递,主要有两种方法,一种是通过xml存储,然后加载传递,这种好处是,程序退出后,参数有存储,坏处是慢;另一种,就是使用全局变量来传递,他的坏处是,程序退出,参数就没了,比如径向畸变参数,坐标位置,以及匹配学习的参数等等,但是他速度快。
另外,还可以考虑如何添加两个rectgaugeitem在工具组界面?
随着工具的增加,问题级数一般增加,有时想,运行一万多行的程序(当初的unix也只有一万行),不崩溃,多么幸福!
机器视觉的宗旨,高效,稳定,准确,藏在心里,锲而不舍!