Build a Fast Multilingual OCR Service with Go, OpenCV, Tesseract, Vue3 & Docker
This step‑by‑step guide shows how to create a high‑performance OCR service that recognizes Chinese and English, using a Go Gin backend with OpenCV preprocessing and Tesseract, a Vue3 frontend, Docker multi‑stage builds, and Swagger UI for API testing.
Project Highlights
Backend : Go + Gin + GoCV + Tesseract – concurrent OCR, image preprocessing, JSON API.
Frontend : Vue3 + Tailwind + Axios – image upload, one‑click recognition, result display.
Build : Docker multi‑stage – single image containing both Go and Node builds.
Documentation : Swagger (OpenAPI 3) + Swagger UI – built‑in API docs and interactive testing.
Deployment : Docker Compose – one‑command start for the OCR service and Swagger UI.
Project Structure
go-ocr-vue/
├── backend/ # Go backend (Gin + Tesseract + OpenCV)
│ ├── main.go
│ ├── swagger.yaml
│ └── go.mod
├── frontend/ # Vue3 + Tailwind frontend
│ ├── index.html
│ ├── package.json
│ ├── vite.config.js
│ ├── tailwind.config.js
│ └── src/
│ ├── App.vue
│ └── main.js
├── Dockerfile # Multi‑stage build
└── docker-compose.yml # One‑click service startBackend: Go OCR Core Logic
The OCR pipeline consists of three stages:
Image preprocessing – grayscale conversion, Gaussian blur, adaptive threshold.
Tesseract recognition – wrapped by the gosseract client.
Worker pool – Goroutine pool to handle concurrent requests and improve throughput.
Key preprocessing code:
gray := gocv.NewMat()
gocv.CvtColor(img, &gray, gocv.ColorBGRToGray)
blur := gocv.NewMat()
gocv.GaussianBlur(gray, &blur, image.Pt(3, 3), 0, 0, gocv.BorderDefault)
bin := gocv.NewMat()
gocv.AdaptiveThreshold(blur, &bin, 255, gocv.AdaptiveThresholdMean, gocv.ThresholdBinary, 15, 10)Tesseract invocation:
client := gosseract.NewClient()
defer client.Close()
client.SetLanguage("chi_sim", "eng")
client.SetPageSegMode(gosseract.PSM_AUTO)
client.SetImageFromBytes(imgBytes)
text, _ := client.Text()Gin API endpoint:
r.POST("/ocr", func(c *gin.Context) {
file, _ := c.FormFile("image")
f, _ := file.Open()
imgBytes, _ := io.ReadAll(f)
text := doOCR(imgBytes)
c.JSON(200, gin.H{"text": text})
})Frontend: Vue3 + Tailwind UI
Minimal interface for uploading an image, triggering OCR, and displaying the result.
<template>
<div class="min-h-screen flex flex-col items-center justify-center bg-gray-100">
<div class="bg-white p-6 rounded-2xl shadow-lg w-full max-w-md">
<h1 class="text-2xl font-bold text-center mb-4">Go OCR Service</h1>
<form @submit.prevent="handleUpload" class="flex flex-col gap-4">
<input type="file" @change="onFileChange" accept="image/*" />
<button type="submit" class="bg-blue-500 hover:bg-blue-600 text-white py-2 rounded" :disabled="loading">
{{ loading ? "识别中..." : "上传并识别" }}
</button>
</form>
<div v-if="result" class="mt-4 bg-gray-50 border p-3 rounded">
<strong>识别结果:</strong>
<p>{{ result }}</p>
</div>
</div>
</div>
</template>Upload logic:
import axios from "axios";
const formData = new FormData();
formData.append("image", file.value);
const res = await axios.post("/ocr", formData);
result.value = res.data.text;Docker: Multi‑stage Build
Dockerfile builds the frontend with Node, the backend with Go, and packages everything into a single lightweight image.
FROM node:20 AS frontend-builder
WORKDIR /frontend
COPY frontend/ .
RUN yarn install && yarn build
FROM golang:1.22-bullseye AS backend-builder
RUN apt-get update && apt-get install -y libtesseract-dev libleptonica-dev tesseract-ocr tesseract-ocr-chi-sim tesseract-ocr-eng
WORKDIR /app
COPY backend/ .
COPY --from=frontend-builder /frontend/dist ./frontend-dist
RUN go build -o server main.go
FROM debian:bullseye-slim
WORKDIR /app
COPY --from=backend-builder /app/server .
COPY --from=backend-builder /app/frontend-dist ./frontend-dist
EXPOSE 8080
CMD ["./server"]For environments with slow Debian mirrors, replace the source list:
RUN sed -i 's|http://deb.debian.org/debian|https://mirrors.aliyun.com/debian|g' /etc/apt/sources.listSwagger Documentation & Online Debugging
The OpenAPI specification is stored in backend/swagger.yaml. Example excerpt:
openapi: 3.0.3
info:
title: Go OCR Service
version: "1.0.0"
paths:
/ocr:
post:
summary: Upload image and return OCR text
requestBody:
required: true
content:
multipart/form-data:
schema:
properties:
image:
type: string
format: binary
responses:
"200":
description: SuccessDocker Compose: One‑Click Startup
version: "3.8"
services:
app:
build: .
ports: ["8080:8080"]
swagger-ui:
image: swaggerapi/swagger-ui
ports: ["8081:8080"]
environment:
- SWAGGER_JSON_URL=http://app:8080/swagger.yaml
depends_on:
- appStart the stack:
docker compose up --buildAccess points:
Frontend UI – http://localhost:8080 Swagger UI –
http://localhost:8081Quick Start Commands
# Clone the repository
git clone https://github.com/louis-xie-programmer/go-ocr-vue.git
cd go-ocr-vue
# Build and start the service with Swagger UI
docker compose up --buildTechnical Tips & Performance Optimizations
Recognition speed : Use a Goroutine pool to reuse the Tesseract client and avoid repeated initialization.
Image preprocessing : For low‑quality images, apply gocv.EqualizeHist to enhance contrast.
Language packs : Chinese and English are bundled; add tesseract-ocr-chi-tra for Traditional Chinese support.
Deployment optimization : Build a custom base image that already contains OpenCV and Tesseract to speed up Docker builds.
Caching : Store results of identical images (e.g., using an MD5 hash) in Redis to avoid redundant OCR work.
Source Code
GitHub repository: https://github.com/louis-xie-programmer/go-ocr-vue Gitee mirror (China):
https://gitee.com/louis_xie/go-ocr-vueSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Wrench
Focuses on code debugging, performance optimization, and real-world engineering, sharing efficient development tips and pitfall guides. We break down technical challenges in a down-to-earth style, helping you craft handy tools so every line of code becomes a problem‑solving weapon. 🔧💻
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
