用 Go 和 ONNX 构建验证码识别系统

本项目介绍如何使用 Go 调用 ONNX 模型实现验证码识别系统。相比调用 Python,ONNX 推理更轻量、跨平台性更好,适合部署在微服务环境中。

一、项目结构

captcha-onnx-go/
├── model/
│ └── crnn.onnx # 导出的 ONNX 模型
├── service/
│ └── main.go # Go 服务入口
├── testdata/
│ └── sample.png # 待识别验证码图像
二、准备模型(使用 PyTorch 导出)
我们假设你已经用 PyTorch 训练好了一个 CRNN 模型,并将其导出为 ONNX 格式:
更多内容访问ttocr.com或联系1436423940
dummy_input = torch.randn(1, 3, 60, 160)
torch.onnx.export(model, dummy_input, "crnn.onnx", input_names=["input"], output_names=["output"], opset_version=11)
三、Go 实现服务

  1. 安装依赖
    使用 go modules:

go mod init captcha-onnx-go
go get github.com/yalue/onnxruntime-go
go get github.com/disintegration/imaging
go get github.com/gin-gonic/gin
2. 图像预处理函数
我们需要将图像转换为 [1, 3, 60, 160] 的 float32 Tensor:

func preprocessImage(path string) ([]float32, error) {
img, err := imaging.Open(path)
if err != nil {
return nil, err
}
resized := imaging.Resize(img, 160, 60, imaging.Lanczos)
bounds := resized.Bounds()
data := make([]float32, 3bounds.Dx()bounds.Dy())

for y := 0; y < bounds.Dy(); y++ {
	for x := 0; x < bounds.Dx(); x++ {
		r, g, b, _ := resized.At(x, y).RGBA()
		i := y*bounds.Dx() + x
		data[i] = (float32(r>>8)/255.0 - 0.5) / 0.5
		data[i+bounds.Dx()*bounds.Dy()] = (float32(g>>8)/255.0 - 0.5) / 0.5
		data[i+2*bounds.Dx()*bounds.Dy()] = (float32(b>>8)/255.0 - 0.5) / 0.5
	}
}
return data, nil

}
3. ONNX 推理与解码

var charset = []rune("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")

func decodeOutput(output []float32, width int) string {
result := ""
for t := 0; t < width; t++ {
maxVal := float32(-1e9)
maxIdx := 0
for c := 0; c < len(charset); c++ {
val := output[t*len(charset)+c]
if val > maxVal {
maxVal = val
maxIdx = c
}
}
result += string(charset[maxIdx])
}
return result
}
4. 完整服务实现

package main

import (
"github.com/gin-gonic/gin"
"github.com/yalue/onnxruntime-go"
"io/ioutil"
"net/http"
"os"
)

func main() {
session, err := onnx.NewSession("model/crnn.onnx")
if err != nil {
panic(err)
}
defer session.Close()

r := gin.Default()
r.POST("/predict", func(c *gin.Context) {
	file, _ := c.FormFile("image")
	temp := "temp.png"
	c.SaveUploadedFile(file, temp)
	input, _ := preprocessImage(temp)

	tensor, err := onnx.NewTensor(input, []int64{1, 3, 60, 160})
	if err != nil {
		c.JSON(500, gin.H{"error": "tensor error"})
		return
	}

	output, err := session.Run(map[string]*onnx.Tensor{"input": tensor})
	if err != nil {
		c.JSON(500, gin.H{"error": "inference error"})
		return
	}
	result := decodeOutput(output["output"].Float32s(), 4)
	c.JSON(200, gin.H{"result": result})
})
r.Run(":8080")

}
四、测试服务

curl -X POST -F "image=@testdata/sample.png" http://localhost:8080/predict
返回:

{"result": "9TK2"}

posted @ 2025-05-30 12:00  ttocr、com  阅读(27)  评论(0)    收藏  举报