zoukankan      html  css  js  c++  java
  • "废物利用"也抄袭——“完全”DIY"绘图仪"<三、上位机程序设计>

            上位机的程序主要是解析图片和生成较好的代码,现在实现的功能有灰度打印,二值打印,轮廓打印,骨骼打印。当然,必不可少的是打印大小的控制。测试了一些图片,总体来说,打印速度依次加快,因为打印的内容依次减少。但是还有一些不太满意的地方,例如用轮廓和骨骼打印来打印文字时,东一块西一块,还没有空闲写行识别之后的排序。其实思路挺简单,膨胀文字或腐蚀背景使一行变为位置相邻的点集,然后在外包矩形内进行按x递增排序就可以了。

            上位机总体功能分为三部分:

    1、与下位机通讯,这部分建议先写好,才更利于后面的测试。

    2、图片处理——灰度、二值、边缘、骨骼。

    3、灰度、二值、边缘、骨骼点数组转命令。

    一、图片处理

           我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函数来完成内存数据置零。

    二、点数组转命令

            

        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轴方向移动,还解释了象限角分线方向的动——它们非常容易实现,因为只需转动一个电机。这样做的好处就是仅斜向相连的点不会被解释为两次动作——除非通过更复杂的代码形成更多的指令(关闭并迅速开启激光器或抬起并落下舵机)才能使绘制的图像不比原图多出某些拐角。

    三、与下位机通讯

            

        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里面,剩下就是确定当前使用的是否发生了变化来确定使用哪一个了。

    最近几天偷闲完善了一下上位机的程序,界面如下:

    红色的部分是已经打印的部分,随着打印进行,红色的部分同步增长,这比进度条看起来更好一些。然后做了一下文字打印,主要是针对在一定的范围内打印一定的行数:

     

    点击确定之后,得到的图像如下:

     

    这就可以方便的打印一些文字咯。。。

  • 相关阅读:
    区别Lua模式匹配中 %a+ 与 .-
    将硬件规定的通信协议用Lua实现(涉及到很多Lua通信的数据转换)
    Lua库-string库
    Unity3d
    Unity3d
    Unity3d
    Unity3d
    Unity3d
    Unity3d
    Unity3d
  • 原文地址:https://www.cnblogs.com/zcsor/p/9058133.html
Copyright © 2011-2022 走看看