"廢物利用"也抄襲——「徹底」DIY"繪圖儀"<3、上位機程序設計>

        上位機的程序主要是解析圖片和生成較好的代碼,如今實現的功能有灰度打印,二值打印,輪廓打印,骨骼打印。固然,必不可少的是打印大小的控制。測試了一些圖片,整體來講,打印速度依次加快,由於打印的內容依次減小。可是還有一些不太滿意的地方,例如用輪廓和骨骼打印來打印文字時,東一塊西一塊,尚未空閒寫行識別以後的排序。其實思路挺簡單,膨脹文字或腐蝕背景使一行變爲位置相鄰的點集,而後在外包矩形內進行按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裏面,剩下就是肯定當前使用的是否發生了變化來肯定使用哪個了。

最近幾天偷閒完善了一下上位機的程序,界面以下:

 

 

紅色的部分是已經打印的部分,隨着打印進行,紅色的部分同步增加,這比進度條看起來更好一些。而後作了一下文字打印,主要是針對在必定的範圍內打印必定的行數:

 

點擊肯定以後,獲得的圖像以下:

 

 

這就能夠方便的打印一些文字咯。。。

相關文章
相關標籤/搜索