一、为什么选 Go
二进制部署方便、启动速度快,适合在服务器或微服务中部署 OCR 接口。
gosseract 是成熟的 Go 对 Tesseract 的封装,调用简单。
可与 Go 的并发模型天然结合,便于批量或并发识别。
二、环境准备
- 安装 Go(1.18+ 推荐)
更多内容访问ttocr.com或联系1436423940
macOS(Homebrew):
brew install go
Ubuntu:
sudo apt update
sudo apt install golang-go
验证:
go version
- 安装 Tesseract OCR
macOS:
brew install tesseract
Ubuntu / Debian:
sudo apt install tesseract-ocr libtesseract-dev libleptonica-dev
确认:
tesseract --version
- 安装 ImageMagick(用于外部预处理,可选)
可用 convert 进行灰度/二值化(脚本里会示例使用)。
macOS:
brew install imagemagick
Ubuntu:
sudo apt install imagemagick
- 安装 Go 依赖
我们用 gosseract 和 gocv/imaging(可选)做图像处理。最简单用 imaging。
go get github.com/otiai10/gosseract/v2
go get github.com/disintegration/imaging
三、思路与流程概览
准备或收集验证码图片(示例用 captcha.png),建议清晰且为英文数字组合。
对图像做预处理:灰度、对比增强、二值化、去噪(可用 ImageMagick 或 Go 的 imaging 做基本处理)。
用 gosseract 调用 Tesseract 做 OCR,设置字符白名单(只识别 A-Z、0-9)提高准确率。
清洗识别结果(去掉非字母数字字符),输出最终验证码字符串。
可扩展为批量处理、并发识别或 REST 接口。
四、示例工程(文件清单)
main.go — 主识别程序(含预处理和识别)
(可选)Dockerfile — 容器化部署
测试图片:captcha.png
五、详细代码(main.go)
package main
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"sync"
"github.com/disintegration/imaging"
"github.com/otiai10/gosseract/v2"
)
// 使用 ImageMagick 的 convert 进行更强的二值化/去噪(如果安装了 ImageMagick)
// 如果不想依赖 convert,可用 imaging 做灰度与简单增强
func preprocessWithConvert(src, dst string) error {
// 灰度、增强对比、自动阈值二值化
// 这个命令可按需调整 threshold 值
cmd := exec.Command("convert", src,
"-colorspace", "Gray",
"-contrast-stretch", "0.5%",
"-threshold", "50%",
dst)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("convert error: %v, output: %s", err, string(out))
}
return nil
}
// 纯 Go 预处理(不依赖 ImageMagick): 灰度、调整对比/锐化、二值化
func preprocessWithImaging(src, dst string) error {
img, err := imaging.Open(src)
if err != nil {
return err
}
// 灰度
gray := imaging.Grayscale(img)
// 轻微提高清晰度(可选)
// gray = imaging.Sharpen(gray, 0.5)
// 增强对比度
gray = imaging.AdjustContrast(gray, 20) // -100..100
// 二值化(手动阈值)
b := imaging.AdjustFunc(gray, func(c float64) float64 {
// c in 0..1
if c > 0.6 { // 阈值可调
return 1.0
}
return 0.0
})
return imaging.Save(b, dst)
}
func cleanText(s string) string {
// 保留大小写字母和数字
re := regexp.MustCompile([^A-Za-z0-9]
)
return re.ReplaceAllString(s, "")
}
func ocrSingle(imagePath string) (string, error) {
// 先做预处理到临时文件
tmp := strings.TrimSuffix(imagePath, filepath.Ext(imagePath)) + "_proc.png"
// 尝试用 ImageMagick 的 convert(若安装),否则用 Go imaging
if _, err := exec.LookPath("convert"); err == nil {if err := preprocessWithConvert(imagePath, tmp); err != nil {log.Printf("convert preproc failed: %v, fallback to imaging", err)if err := preprocessWithImaging(imagePath, tmp); err != nil {return "", err}}
} else {if err := preprocessWithImaging(imagePath, tmp); err != nil {return "", err}
}client := gosseract.NewClient()
defer client.Close()
// 设置语言为英文,并限制可识别字符白名单
client.SetLanguage("eng")
client.SetWhitelist("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
if err := client.SetImage(tmp); err != nil {return "", err
}
text, err := client.Text()
if err != nil {return "", err
}
// 清洗结果
clean := cleanText(text)
// 可删临时文件
_ = os.Remove(tmp)
return clean, nil
}
func ocrBatch(paths []string, concurrency int) map[string]string {
res := make(map[string]string)
var mu sync.Mutex
wg := sync.WaitGroup{}
sem := make(chan struct{}, concurrency)
for _, p := range paths {p := pwg.Add(1)sem <- struct{}{}go func() {defer wg.Done()defer func() { <-sem }()out, err := ocrSingle(p)if err != nil {log.Printf("ocr error %s: %v", p, err)out = ""}mu.Lock()res[p] = outmu.Unlock()}()
}
wg.Wait()
return res
}
func main() {
if len(os.Args) < 2 {
fmt.Println("usage: go run main.go ")
return
}
target := os.Args[1]
info, err := os.Stat(target)
if err != nil {
log.Fatalf("stat error: %v", err)
}
if info.IsDir() {
// 遍历目录下 png/jpg
var files []string
err := filepath.Walk(target, func(path string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
if fi.IsDir() {
return nil
}
ext := strings.ToLower(filepath.Ext(path))
if ext == ".png" || ext == ".jpg" || ext == ".jpeg" {
files = append(files, path)
}
return nil
})
if err != nil {
log.Fatalf("walk error: %v", err)
}
results := ocrBatch(files, 4) // 并发 4 个
for k, v := range results {
fmt.Printf("%s -> %s\n", k, v)
}
} else {
out, err := ocrSingle(target)
if err != nil {
log.Fatalf("ocr failed: %v", err)
}
fmt.Println("识别结果:", out)
}
}
说明(代码关键点)
preprocessWithConvert:如果系统安装了 ImageMagick 的 convert,优先用其二值化能力(通常效果更好);否则用 imaging 做灰度+对比调整+手动阈值二值化。阈值和对比数值可根据你的验证码样式调参。
gosseract:设置 SetWhitelist 只允许英文字母和数字,能大幅减少误识别的字符。
并发:ocrBatch 使用 goroutine 和信号量(channel)限制并发数,适合在服务器批量处理场景。
清洗:用正则去掉非字母数字字符。
六、运行示例
构建并运行(假设文件名 captcha.png 在当前目录):
go run main.go captcha.png
批量识别目录:
go run main.go ./captchas_dir