啧啧 都看看 Go 都干了些啥| 🏆 技术专题第二期

Go 语言都能做些什么呢

大家好,我是好家伙,漫画 Go 语言小册的作者。这次我要给大家带来一些关于Go语言的一些分享。作为一个程序员,身处这个时代,掌握一门技术,就如同修得一身好武功一样,不仅要经过不断地实战经验,还要有足够的热情,循序渐进才能到达高手的境界。在众多开发语言中,如何才能找到一个适合自己修炼的武功秘籍。那就得对这个语言有所了解。知道它的威力,才能更好的掌握,成为高手就指日可待。

Go 语言作为一门后端语言,到底能够有多大威力,具体能够做些什么,到底能够发出什么样的招式才能够吸引你学习它?那么接下来就简单露几招,还望各位大佬们指教!

gocv 计算机视觉

OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。实现了图像处理和计算机视觉方面的很多通用算法。 OpenCV用C++语言编写,它具有C ++,Python,Java和MATLAB接口,并支持Windows,Linux,Android和Mac OS,OpenCV主要倾向于实时视觉应用, 如今也提供对于C#、Ch、Ruby,GO的支持也就是gocv。https://gocv.io/

  • 安装 gocv go get -u -d gocv.io/x/gocv
  • 安装 MinGW-W64 https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/7.3.0/
  • 安装CMake https://cmake.org/download/
  • 安装编译gocv
    chdir %GOPATH%\src\gocv.io\x\gocv
    win_build_opencv.cmd
    

gocv将图片二值化

package main

import (
	"gocv.io/x/gocv"
)

//测试示例
func main() {
	filename := "test.png"
	window := gocv.NewWindow("Hello")
	img := gocv.IMRead(filename, gocv.IMReadColor)
	destImage := gocv.NewMat()
	//二值化 转为灰度图
	gocv.CvtColor(img, &destImage, gocv.ColorBGRToGray)

	for {
		window.IMShow(destImage)
		if window.WaitKey(1) >= 0 {
			break
		}
	}
}

gocv 人脸检测

package main

import (
	"fmt"
	"image"
	"image/color"
	"os"

	"gocv.io/x/gocv"
)

func main() {
	if len(os.Args) < 3 {
		fmt.Println("How to run:\n\tfacedetect [camera ID] [classifier XML file]")
		return
	}

	// parse args
	deviceID := os.Args[1]
	xmlFile := os.Args[2]

	// open webcam
	webcam, err := gocv.OpenVideoCapture(deviceID)
	if err != nil {
		fmt.Printf("error opening video capture device: %v\n", deviceID)
		return
	}
	defer webcam.Close()

	// open display window
	window := gocv.NewWindow("Face Detect")
	defer window.Close()

	// prepare image matrix
	img := gocv.NewMat()
	defer img.Close()

	// color for the rect when faces detected
	blue := color.RGBA{0, 0, 255, 0}

	// load classifier to recognize faces
	classifier := gocv.NewCascadeClassifier()
	defer classifier.Close()

	if !classifier.Load(xmlFile) {
		fmt.Printf("Error reading cascade file: %v\n", xmlFile)
		return
	}

	fmt.Printf("Start reading device: %v\n", deviceID)
	for {
		if ok := webcam.Read(&img); !ok {
			fmt.Printf("Device closed: %v\n", deviceID)
			return
		}
		if img.Empty() {
			continue
		}

		// detect faces
		rects := classifier.DetectMultiScale(img)
		fmt.Printf("found %d faces\n", len(rects))

		// draw a rectangle around each face on the original image,
		// along with text identifing as "Human"
		for _, r := range rects {
			gocv.Rectangle(&img, r, blue, 3)

			size := gocv.GetTextSize("Human", gocv.FontHersheyPlain, 1.2, 2)
			pt := image.Pt(r.Min.X+(r.Min.X/2)-(size.X/2), r.Min.Y-2)
			gocv.PutText(&img, "Human", pt, gocv.FontHersheyPlain, 1.2, blue, 2)
		}

		// show the image in the window, and wait 1 millisecond
		window.IMShow(img)
		if window.WaitKey(1) >= 0 {
			break
		}
	}
}

gobot 机器人

gobot 是一个使用Go语言编写的适用于机器人,无人机和物联网的IoT框架。https://gobot.io/

  • 支持35不同平台。
  • 支持输入/输出(GPIO)通讯的设备。
  • 模拟I / O(AIO)驱动程序。
  • I2C驱动程序。
  • SPI驱动器。

树莓派

Raspberry Pi 中文名为树莓派,简写为RPi 只有信用卡大小的微型电脑,其系统基于Linux,它是一款基于ARM的微型电脑主板。可连接键盘、鼠标和网线,具备PC的基本功能。最新版本的树莓派4B,拥有4G内存,引入USB 3.0,支持双屏4K输出,CPU和GPU的速度也更快。

运行在树莓派上的Go程序实现坦克机器人。

package drivers

// import "fmt"

type Motor struct {
	PWMA   int
	AIN1   int
	AIN2   int
	BIN1   int
	BIN2   int
	PWMB   int
	Driver *PCA9685Driver
	Debug  bool
}

type MotorPosition int

const (
	MotorPosition_Left  MotorPosition = 0
	MotorPosition_Right MotorPosition = 1
	MotorPosition_All   MotorPosition = -1
)

type MotorDirection int

const (
	MotorDirection_Forward  MotorDirection = 1
	MotorDirection_Backward MotorDirection = -1
)

func NewMotor(driver *PCA9685Driver) *Motor {
	motor := &Motor{
		PWMA:   0,
		AIN1:   1,
		AIN2:   2,
		BIN1:   3,
		BIN2:   4,
		PWMB:   5,
		Driver: driver,
		Debug:  false,
	}
	var PWM float32 = 125
	// fmt.Println("设置电机PWM速率:", PWM)
	driver.SetPWMFreq(PWM)
	return motor
}

// 前进
func (this *Motor) Forward(speed int) {
	this.Run(MotorPosition_All, MotorDirection_Forward, speed)
}

//后退
func (this *Motor) Backward(speed int) {
	this.Run(MotorPosition_All, MotorDirection_Backward, speed)
}

//左转,原地转向
func (this *Motor) Left(speed int) {
	this.Run(MotorPosition_Left, MotorDirection_Backward, speed)
	this.Run(MotorPosition_Right, MotorDirection_Forward, speed)
}

//右转,原地转向
func (this *Motor) Right(speed int) {
	this.Run(MotorPosition_Right, MotorDirection_Backward, speed)
	this.Run(MotorPosition_Left, MotorDirection_Forward, speed)
}

//直接操作电机运转
func (this *Motor) Run(motor MotorPosition, direction MotorDirection, speed int) {
	if speed > 100 {
		speed = 100
	}
	//同时操作所有电机
	if motor == MotorPosition_All {
		this.Run(MotorPosition_Left, direction, speed)
		this.Run(MotorPosition_Right, direction, speed)
		return
	}
	//设置默认PWM调速通道为电机a的调速通道
	pwmChannel := this.PWMA
	//设置默认操作电机为A
	PIN1 := this.AIN1
	PIN2 := this.AIN2
	//根据参数设置操作电机和调速通道为电机B
	if motor == MotorPosition_Right {
		pwmChannel = this.PWMB
		PIN1 = this.BIN1
		PIN2 = this.BIN2
	}

	//如果参数为后退,翻转PIN1和PIN2的位置
	if direction == MotorDirection_Backward {
		PIN1, PIN2 = PIN2, PIN1
	}
	// fmt.Println("pwmChannel:", pwmChannel, ",speed:", speed, ",PIN1:", PIN1, ",PIN2:", PIN2)
	//设置速度
	this.Driver.SetPWM(pwmChannel, 0, uint16(speed*(4096/100)))

	//设置正电极
	this.Driver.SetPWM(PIN1, 0, 4095)

	//设置负电极
	this.Driver.SetPWM(PIN2, 0, 0)

}

// func (this *Motor) SetPWM(channel int, on uint16, off uint16) (err error) {
// 	this.Driver
// 	if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_ON_L + 4*channel), byte(on), byte(on >> 8), byte(off), byte(off >> 8)}); err != nil {
// 		return err
// 	}

// 	return
// }

func (this *Motor) MotorStop(motor MotorPosition) {
	if motor == MotorPosition_All {
		this.MotorStop(MotorPosition_Left)
		this.MotorStop(MotorPosition_Right)
		return
	}
	//设置默认PWM调速通道为电机a的调速通道
	pwmChannel := this.PWMA
	if motor == MotorPosition_Right {
		pwmChannel = this.PWMB
	}
	//设置速度
	this.Driver.SetPWM(pwmChannel, 0, 0)
}
	
package core

import (
	"fmt"
	"gobot.io/x/gobot"
	"airobot/robot/drivers"
	"gobot.io/x/gobot/platforms/raspi"
)

//机器人主结构,存储gobot实例和各个初始化的驱动以及操作器
type Robot struct {
	//gobot实例
	gobot *gobot.Robot
	//主板适配器
	adaptor *raspi.Adaptor
	//电机操作板驱动
	motorDriver *drivers.PCA9685Driver
	//电机操作器
	motor *drivers.Motor
	//电机操作指令列队
	motorCmds chan (*CMDData)
}

//初始化机器人监听
func (this *Robot) Start() {
	this.motorCmds = make(chan (*CMDData), 100)
	go this.listenMotorCmds()
}

func (this *Robot) listenMotorCmds() {
	m := NewMotor(this)
wait:
	cmd := <-this.motorCmds
	m.execute(cmd)
	goto wait
}

//机器人状态通道,用于通知webapi启动,启动过程中通道会压入0,启动完成后压入1.
var RobotState = make(chan int, 1)

//机器人操作指令主通道,通过websocket接收指令并压入此通道
var RobotCMD = make(chan *CMD, 100)

//全局机器人实例
var bot *Robot

//机器人启动方法
func StartRobot() {

	bot = &Robot{}

	fmt.Println("机器人开始启动.")
	RobotState <- 0
	fmt.Println("初始化主板适配器.")
	bot.adaptor = raspi.NewAdaptor()
	fmt.Println("初始化电机驱动.")
	bot.motorDriver = drivers.NewPCA9685Driver(bot.adaptor)
	bot.Start()
	work := func() {
		fmt.Println("初始化电机操作器.")
		bot.motor = drivers.NewMotor(bot.motorDriver)
		// var PWM float32 = 125
		// fmt.Println("设置电机PWM速率:", PWM)
		// bot.motorDriver.SetPWMFreq(PWM)
		fmt.Println("机器人启动完成.")
		fmt.Println("机器人开始等待指令.")
		RobotState <- 1
	begin:
		cmd := <-RobotCMD
		// fmt.Println("接收到指令:", cmd)

		switch cmd.Channel {
		case "motor":
			bot.motorCmds <- &cmd.Data
			break
		}
		goto begin
	}

	robot := gobot.NewRobot("tankBot",
		[]gobot.Connection{bot.adaptor},
		[]gobot.Device{bot.motorDriver},
		work,
	)
	robot.Start()
}

视频直播服务

livego 使用纯 go 语言写的一款简单高效的直播服务器。https://github.com/gwuhaolin/livego

  • 支持的传输协议 RTMP, AMF,HLS,HTTP-FLV
  • 支持的容器格式 FLV,TS
  • 支持的编码格式 H264,AAC, MP3

使用

  • 1 启动服务:执行 livego 二进制文件启动 livego 服务;
  • 2 访问 http://localhost:8090/control/get?room=movie 获取一个房间的channelkey(channelkey用于推流,movie用于播放).
  • 3 推流: 通过RTMP协议推送视频流到地址 rtmp://localhost:1935/{appname}/{channelkey} (appname默认是live)

例如: 使用 ffmpeg -re -i demo.flv -c copy -f flv

rtmp://localhost:1935/{appname}/{channelkey} 推流(下载demo flv);

播放: 支持多种播放协议,播放地址如下: RTMP:rtmp://localhost:1935/{appname}/movie FLV:http://127.0.0.1:7001/{appname}/movie.flv HLS:http://127.0.0.1:7002/{appname}/movie.m3u8

//ffmpeg命令 推流
ffmpeg -re -i demo.flv -c copy -f flv rtmp://localhost:1935/{appname}/{channelkey}

文档地址:https://github.com/gwuhaolin/livego/blob/master/README_cn.md

CRON 定时任务

go语言支持cron定时任务 https://github.com/jakecoffman/cron

package main

import (
	"fmt"

	"github.com/jakecoffman/cron"
)

func main() {
	c := cron.New()
	//每天早上6点执行Testfun函数
	c.AddFunc("0 0 6 * * ? ", Testfunc, "定时任务")
	c.Start()
}

func Testfunc() {
	fmt.Println("定时任务")
	//TODO 处理逻辑....
}

Excelize 一个 Go 语言版本的 Excel 文档 API

Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的电子表格文档。支持 XLSX / XLSM / XLTM 等多种文档格式,高度兼容带有样式、图片(表)、透视表、切片器等复杂组件的文档,并提供流式读写 API

  • 文档地址:https://xuri.me/excelize/zh-hans/
  • 项目地址:https://github.com/360EntSecGroup-Skylar/excelize
package main

import (
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
)

func main() {
	f := excelize.NewFile()
	// 创建一个 sheet
	index := f.NewSheet("Sheet1")
	// 设置值
	f.SetCellValue("Sheet2", "A2", "Hello world.")
	f.SetCellValue("Sheet1", "B2", 100)
	// 设置工作簿的活动工作表。
	f.SetActiveSheet(index)
	// 保存excel
	if err := f.SaveAs("Book1.xlsx"); err != nil {
		fmt.Println(err)
	}
}

🏆 技术专题第二期 | 我与 Go 的那些事......