OpenResty 是一个强大的 Web 应用服务器,Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,更主要的是在性能方面,OpenResty可以 快速构造出足以胜任 10K 以上并发连接响应的超高性能 Web 应用系统。

1.安装依赖包

sudo apt-get install gcc g++ make libpcre3 libpcre3-dev zlib1g-dev openssl libssl-dev

2.下载源码

我们需要分别下载nginx,luajit以及lua-nginx-module

#nginx 1.14.2,LuaJIT 2.0.5,lua-nginx-module 0.10.13
mkdir temp && cd temp/
wget http://nginx.org/download/nginx-1.14.2.tar.gz
wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz
wget https://github.com/openresty/lua-nginx-module/archive/v0.10.13.tar.gz
tar xfvz nginx-1.14.2.tar.gz
tar xfvz LuaJIT-2.0.5.tar.gz
tar xfvz v0.10.13.tar.gz

3.编译Nginx

cd LuaJIT-2.0.5/
make && make install
cd ../nginx-1.14.2/
#指定luajit目录
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.0
#新建一个文件夹,这将作为安装目录
mkdir /etc/nginx
#配置模块
./configure --prefix=/etc/nginx --add-module=../lua-nginx-module-0.10.13 --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module
make -j2 && make install

4.配置使用

打开/etc/nginx/conf/nginx.conf加入:

location /lua {
  default_type 'text/plain';
  content_by_lua 'ngx.say("hello")';
}

然后运行nginx:

/etc/nginx/sbin/nginx

测试!

curl http://localhost/lua
hello

人脸检测

实现请看上一篇文章:我 是 链 接

算法API

在Opencv中,一共有三种自带的识别算法:
Eigenface,FisherFace和LBPH。

#会产生0-20000的可信度评分,一般低于4000-5000都视为不错的识别结果
#Eigenface(特征脸)
cv2.face.EigenFaceRecognizer_create()
#FisherFace(LDA线性判别分析)
cv2.face.FisherFaceRecognizer_create()
#一般高于80都为不可信的识别,低于50都是不错的识别
#LBPH()
cv2.face.LBPHFaceRecognizer_create()

测试例子

face_get.py 用于截取人脸,注意新建目录face_img

#coding=utf-8
import cv2
name = raw_input("Name >")
i = 1
face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
camera = cv2.VideoCapture(0)
while True:
    ret, frame = camera.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    for (x,y,w,h) in faces:
        #cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
        face_img = cv2.resize(gray[y:y+h,x:x+w],(200,200))
        print face_img
        print '--------------------------'
        cv2.imwrite('./face_img/' + name + '-' + str(i) + '.pgm',face_img)
        print x,y,w,h
        i = i + 1
    #cv2.imshow("camera", frame)
    #if cv2.waitKey(1000 / 12) & 0xff == ord("q"):
    #    break
camera.release()
#cv2.destroyAllWindows()

face_eig.py Eigenface算法示例

#coding=utf-8
import os
import cv2
import numpy as np
def load_face(path): #加载人脸数据
    X,Y,N = [],[],[]
    for r,d,f in os.walk(path):
        for file in f:
            if file.endswith("pgm"):
                img = cv2.imread(path + "/" + file,cv2.IMREAD_GRAYSCALE)
                print file
                #img = cv2.resize(img,(200,200))
            buf = file.split("-")
            N.append(buf[0])
                X.append(np.asarray(img,dtype=np.uint8))
                Y.append(int(buf[1].split(".")[0]))
    return X,Y,N #人脸数据数组,ID,名称

def face_eig(path):
    [X,Y,N] = load_face(path)
    Y = np.asarray(Y,dtype=np.int32) #将ID转为numpy数组,使其与人脸数据一一对应
    model = cv2.face.createEigenFaceRecognizer() #加载算法
    model.train(np.asarray(X),np.asarray(Y)) #导入数据
    face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
    camera = cv2.VideoCapture(0)
    while True:
        ret, frame = camera.read()
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)
        for (x,y,w,h) in faces:
            img = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
            face = gray[x:x+w,y:y+h] #得到人脸区域
            try:
                face = cv2.resize(face,(200,200),interpolation=cv2.INTER_LINEAR) #调整尺寸,方便使用Eigenface算法
                [id,value] = model.predict(face) #检测,返回上面对应的ID和可信度评分,Eigenface算法会产生0到0-20000 的值,一般低于4000-5000的识别都算是比较精准的
                print "ID:",id,"Value:",value,"Name:",N[id]
            except:
                continue

if __name__ == "__main__":
    face_eig("./face_img")

老物搬运。
画面比在Linux桌面运行的流畅很多,也许是Opencv的cv2.imshow()会不断产生新窗口导致的卡顿,因为我关不掉窗口,它会一直产生新的。

Camera.py

#coding=utf-8
import cv2
class Camera():
    def __init__(self,Camera_id):
        self.video = cv2.VideoCapture(Camera_id)
        self.face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
    def __del__(self):
        self.video.release()
    def get_img(self):
        success,image = self.video.read()
        gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
        faces = self.face_cascade.detectMultiScale(gray, 1.3, 5)
        for (x,y,w,h) in faces:
            cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,0),2)
        ret,jpeg = cv2.imencode('.jpg', image) #将image对象转为jpeg格式
        return jpeg.tobytes() #转字节

main.py

from flask import Flask,Response
from Camera import Camera
app = Flask(__name__)
@app.route('/')
def index():
    return '<h3 style="text-align:center"><img src="/video" width="60%"></h3>'

def Video_stream(camera):
    while True:
        img = camera.get_img()
        yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + img + b'\r\n\r\n') #生成器

@app.route('/video')
def video():
    return Response(Video_stream(Camera(0)), mimetype='multipart/x-mixed-replace; boundary=frame') #合成响应,返回一个自定义标头和图片数据

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=80)

一个微小的例子,检测摄像头中出现的人脸并框出来。

环境部署

sudo apt-get install python-opencv

在Opencv的项目上下载用于检测人脸的级联:

https://github.com/opencv/opencv/blob/master/data/haarcascades/
下载 haarcascade_frontalface_default.xml
(这里面还有用于检测其他的级联文件,比如眼睛)

一个示例

人脸识别中找人脸很重要,只有检测到人脸,再进行算法比对数据库中的人脸。

#coding=utf-8
import cv2
#加载级联文件,返回一个级联分类器
face_cascade = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')
#打开摄像头
camera = cv2.VideoCapture(0)
while True:
    #读一帧
    ret, frame = camera.read()
    #转为灰度图,人脸检测需要灰度图
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    #人脸检测,返回坐标
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    #参数:gray 灰度图像 scaleFactor 检测过程中每次迭代时图像的压缩率 minNeighbors 每个人脸矩形保留近邻数目的最小值
    for (x,y,w,h) in faces:
        #在原图像上画矩形
        cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
    #将其显示出来
    cv2.imshow("camera", frame)
    if cv2.waitKey(1000 / 12) & 0xff == ord("q"):
        break
#关闭摄像头,销毁所有窗口
camera.release()
cv2.destroyAllWindows()

测试结果

2019-02-13-200940_1920x1080_scrot.png

性能

不得不说的是C++的性能比Python快至少一半,但我觉得由于现在计算机性能并不像以前那么弱,所以C++与Python没有什么区别,当然,像嵌入式设备这种性能不强的还是用C++比较好。

去网上查了一圈资料后,还是觉的os好用。

权限表

常量名权限
os.O_RDONLY只读
os.O_WRONLY只写
os.O_RDWR读写
os.O_APPEND追加
os.O_CREATE不存在时创建文件
os.O_TRUNC打开时截断文件

写文件

package main
import ("fmt"
        "os")
func checkerr(err error){
        if err != nil{
                fmt.Println(err)
                os.Exit(1)
        }
}
func main(){
        f,err := os.OpenFile("test.txt",os.O_RDWR|os.O_APPEND|os.O_CREATE,0644) //注意文件权限
        checkerr(err)
        defer f.Close()
        data := []byte("-1s -1s -1s\n") //转字节
        bytesw,err := f.Write(data) //写操作
        checkerr(err)
        fmt.Println("bytes:",bytesw)
}

读文件

package main
import ("fmt"
        "os")
func checkerr(err error){
        if err != nil{
                fmt.Println(err)
                os.Exit(1)
        }
}
func main(){
        f,err := os.Open("test.txt") //使用这种方式为只读
        //f,err := os.OpenFile("test.txt",os.O_RDONLY,0644)
        checkerr(err)
        defer f.Close()
        b := make([]byte,6) //读取6个字节,如果要读取全部,要用ioutil.ReadAll(fileObj)
        br,err := f.Read(b)
        checkerr(err)
        fmt.Println("bytes:",br)
        fmt.Println("data:",b)
        fmt.Println("str:",string(b))
}


从网上查到有Go中有两个包可以读写文件,一个是os包,另一个是ioutil包。
我主要用的是ioutil包,用起来比较简单,当然os也是有他的优势的。

读取文件

package main
import ("fmt"
        "reflect"
        "io/ioutil")
func main(){
        data,err := ioutil.ReadFile("test.txt")
        if err != nil{
                fmt.Println(err)
        }
        fmt.Println("Type:",reflect.TypeOf(data))
        fmt.Println("Data",string(data))
}
//output:
Type: []uint8
Data China Mogic Association
Founded in 1926, near the Huangpu river.
//可以看到,读出的是uint8类型的切片

写文件

这会覆盖文件!

package main
import "io/ioutil"
func checkrerr(err error){
        if err != nil{
                panic(err)
        }
}
func main(){
        data := []byte("+1s +1s +1s") //转字节
        err := ioutil.WriteFile("test.txt",data,0644)//文件掩码:-rw-r--r--
        checkrerr(err)
}

ERROR

概念

除了panicrecover之外,Go中还有一个内置的错误接口类型,任何类型只要实现Error() string方法,都可以传递error接口 类型变量,Go语言处理错误的方式是将error作为函数最后一个返回值,在调用函数时,通过检查其返回的error值是否为nil来进 行错误处理。

type error interface{ //接口类型
    Error() string
}

Go语言提供了两个函数返回实现了error接口的具体类型实例,一般的错误可以使这两个函数进行封装,当然,遇到复杂的错误也可以 自定义错误类型,只要实现error接口即可:

func New(text string) error{
    return &errorString{text}
}

最佳实践

  1. 在多个返回值的函数中,error一般作为最后一个返回值
  2. 如果一个函数返回error类型的变量,则先判断是否为nil
  3. defer语句应该放到err判断后面,不然可能产生panic
  4. 在错误逐层向上传递的过程中,错误信息应该不断的丰富与完善,而不是简单的抛出下层调用的错误,便于分析错误

33_error_0.PNG

其他要说的

Golang全面深入系列之 Error:https://studygolang.com/articles/12625
Go 语言如何实现error的优雅处理:https://blog.csdn.net/baogang409/article/details/72604333

阶段性总结

学了有一段时间了,也写了一些Go,感觉执行速度挺快的,毕竟不像Python这种解释性语言。部分语法与Python也很相像,从Python转到Go也不觉的陌生,学Go主要是写网络方面的程序,看网上的评价说Go对于网络编程性能还不错,要不然会有ngrok这种内网穿透的东东出 现。最后,路还长着,一次只学一点,细嚼慢咽的学。

搞得这个MicroPython啊,亦可赛艇。
经过上一篇文章,已经配置好了WiFi连接和Webrepl,下面我们来尝试与ESP8266来通信,在GPIO2上我接入了一个DS18x20温度传感器,通过访问ESP8266的8267端口,来获得ESP8266上传感器的数值。

main.py:
(在ESP8266上的socket库叫usocket,json库叫ujson)

 from ds18020 import DS18020
 import usocket
 import ujson
 import esp
 host = '0.0.0.0'
 port = 8267

 ds = DS18020(2)
 ds_addr = ds.getaddr()

 s = usocket.socket()
 s.bind((host,port))
 s.listen(6)
 while True:
     client,addr = s.accept()
     print('Client IP:',addr[0])
     info = {}
     info['flash_size'] = str(esp.flash_size())
     info['flash_free'] = str(esp.freemem())
     info['flash_id'] = str(esp.flash_id())
     info['ds18x20_temp'] = str(ds.gettemp(ds_addr[0]))
     print(info)
     client.send(ujson.dumps(info))
     info = {}
     client.close()

ds18020.py
(很惭愧,只做了一点的微小工作)

 import onewire
 import ds18x20
 import time
 from machine import Pin
 class DS18020:
     def __init__(self,pin):
         self.pin = Pin(pin)
     def getaddr(self):
         ow = onewire.OneWire(self.pin)
         self.ds = ds18x20.DS18X20(ow)
         roms = self.ds.scan()
         return roms
     def gettemp(self,addr):
         self.ds.convert_temp()
         time.sleep_ms(450)
         return self.ds.read_temp(addr)

效果:
31_0.PNG
今天还是挺冷的。