上位机的程序主要是解析图片和生成较好的代码,如今实现的功能有灰度打印,二值打印,轮廓打印,骨骼打印。固然,必不可少的是打印大小的控制。测试了一些图片,整体来讲,打印速度依次加快,由于打印的内容依次减小。可是还有一些不太满意的地方,例如用轮廓和骨骼打印来打印文字时,东一块西一块,尚未空闲写行识别以后的排序。其实思路挺简单,膨胀文字或腐蚀背景使一行变为位置相邻的点集,而后在外包矩形内进行按x递增排序就能够了。数组
上位机整体功能分为三部分:ide
一、与下位机通信,这部分建议先写好,才更利于后面的测试。函数
二、图片处理——灰度、二值、边缘、骨骼。测试
三、灰度、二值、边缘、骨骼点数组转命令。线程
1、图片处理3d
我nuget了一个opencvsharp,因此不少基础代码都不用写了。只须要稍加封装使frm中的代码更简洁易易懂于维护就能够了。这里简单说一下mat类点的颜色设置:指针
ImgEdge = New Mat(ImgBinary.Size, MatType.CV_8U)
ImgEdge.Set(Of Byte)(p.Y, p.X, 0)
由于这是二值化的图像,因此用Byte写就能够了,0为黑色。固然,也能够直接操做内存指针:对象
For i As Integer = ImgEdge.DataStart To ImgEdge.DataEnd Marshal.WriteByte(i, 255) Next
这是我清理图片背景的代码。这样作很慢,你能够尝试用API函数来完成内存数据置零。blog
2、点数组转命令排序
Private Shared Function Info2Command(ps() As Point) As List(Of Command) Dim result As New List(Of Command) Dim dx, dy As Integer For i As Integer = 1 To ps.Count - 1 dx = ps(i).X - ps(i - 1).X dy = ps(i).Y - ps(i - 1).Y If dx = dy Then result.Add(New Command(Message.c_13Move, dx * 2)) ElseIf dx = -dy Then result.Add(New Command(Message.c_24Move, dy * 2)) Else If dx <> 0 Then result.Add(New Command(Message.c_xMove, dx)) End If If dy <> 0 Then result.Add(New Command(Message.c_yMove, dy)) End If End If Next Return result End Function
这是我解释一个连续点集的时候使用的代码,代码中将坐标转化为命令。与xy结构不一样,除了解释了x,y轴方向移动,还解释了象限角分线方向的动——它们很是容易实现,由于只需转动一个电机。这样作的好处就是仅斜向相连的点不会被解释为两次动做——除非经过更复杂的代码造成更多的指令(关闭并迅速开启激光器或抬起并落下舵机)才能使绘制的图像不比原图多出某些拐角。
3、与下位机通信
Private WithEvents mPort As SerialPort
这就是所使用的核心对象,它有几个颇有用的事件,其中DataReceived是咱们最关心的:
Private Sub mPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles mPort.DataReceived Dim inData As String = CType(sender, SerialPort).ReadLine.TrimEnd({CChar(vbCr), CChar(vbLf)}) If inData = (r_RequestData) Then RaiseEvent RequestData() ElseIf inData = (r_Ready) Then RaiseEvent Ready() ElseIf inData = (r_Interrupt) Then RaiseEvent Interrupt() ElseIf inData = r_RerequestData Then RaiseEvent RerequestData() ElseIf inData <> String.Empty Then Debug.Print("收到下位机的未知请求。[" & inData & "]") End If End Sub
这用于解释下位机的不一样请求。而发送数据也很是简单:
Protected Friend Sub SendCommand(cmd As Command) mPort.BaseStream.Flush() mPort.Write(cmd.Data, 0, 6) End Sub
OK,最后简单说一下获取COM口名称:
Dim WM_DEVICECHANGE As Integer = &H219 Dim DBT_DEVICEREMOVECOMPLETE As Integer = &H8004 Dim DBT_DEVICEARRIVAL As Integer = &H8000 Protected Overrides Sub WndProc(ByRef m As Message) MyBase.WndProc(m) If m.Msg = WM_DEVICECHANGE Then If m.WParam.ToInt32 = DBT_DEVICEARRIVAL Then 'usb插入 Timer1.Enabled = True ElseIf m.WParam.ToInt32 = DBT_DEVICEREMOVECOMPLETE Then Timer1.Enabled = True End If End If End Sub
实际上应该用单独线程来处理,可是实在是懒得写,就用定时器来处理了。
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick Dim b = New ManagementObjectSearcher("select * from Win32_PnPEntity").Get '检测即插即用设备 Dim lst As New List(Of String) Try For Each c In b Try If c.GetPropertyValue("Name").ToString.Contains("CH340") Then lst.Add(c.GetPropertyValue("Name")) End If Catch ex As Exception End Try Next Catch ex As Exception End Try
用WMI来获取,会获得不少设备名,而后都存在lst里面,剩下就是肯定当前使用的是否发生了变化来肯定使用哪个了。
最近几天偷闲完善了一下上位机的程序,界面以下:
红色的部分是已经打印的部分,随着打印进行,红色的部分同步增加,这比进度条看起来更好一些。而后作了一下文字打印,主要是针对在必定的范围内打印必定的行数:
点击肯定以后,获得的图像以下:
这就能够方便的打印一些文字咯。。。