mirror of
https://github.com/swdee/go-rknnlite.git
synced 2025-10-05 07:16:56 +08:00
185 lines
4.9 KiB
Go
185 lines
4.9 KiB
Go
/*
|
|
Example code showing how to perform OCR on an image using PaddleOCR recognition
|
|
*/
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"github.com/swdee/go-rknnlite"
|
|
"github.com/swdee/go-rknnlite/postprocess"
|
|
"github.com/swdee/go-rknnlite/preprocess"
|
|
"github.com/swdee/go-rknnlite/render"
|
|
"gocv.io/x/gocv"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func main() {
|
|
// disable logging timestamps
|
|
log.SetFlags(0)
|
|
|
|
// read in cli flags
|
|
modelFile := flag.String("m", "../../data/models/rk3588/ppocrv4_rec-rk3588.rknn", "RKNN compiled model file")
|
|
imgFile := flag.String("i", "../../data/ppocr-rec-test.png", "Image file to run inference on")
|
|
keysFile := flag.String("k", "../../data/ppocr_keys_v1.txt", "Text file containing OCR character keys")
|
|
rkPlatform := flag.String("p", "rk3588", "Rockchip CPU Model number [rk3562|rk3566|rk3568|rk3576|rk3582|rk3582|rk3588]")
|
|
flag.Parse()
|
|
|
|
err := rknnlite.SetCPUAffinityByPlatform(*rkPlatform, rknnlite.FastCores)
|
|
|
|
if err != nil {
|
|
log.Printf("Failed to set CPU Affinity: %v\n", err)
|
|
}
|
|
|
|
// check if user specified model file or if default is being used. if default
|
|
// then pick the default platform model to use.
|
|
if f := flag.Lookup("m"); f != nil && f.Value.String() == f.DefValue && *rkPlatform != "rk3588" {
|
|
*modelFile = strings.ReplaceAll(*modelFile, "rk3588", *rkPlatform)
|
|
}
|
|
|
|
// create rknn runtime instance
|
|
rt, err := rknnlite.NewRuntimeByPlatform(*rkPlatform, *modelFile)
|
|
|
|
if err != nil {
|
|
log.Fatal("Error initializing RKNN runtime: ", err)
|
|
}
|
|
|
|
// set runtime to pass input gocv.Mat's to Inference() function as float32
|
|
// to RKNN backend
|
|
rt.SetInputTypeFloat32(true)
|
|
|
|
// optional querying of model file tensors and SDK version for printing
|
|
// to stdout. not necessary for production inference code
|
|
err = rt.Query(os.Stdout)
|
|
|
|
if err != nil {
|
|
log.Fatal("Error querying runtime: ", err)
|
|
}
|
|
|
|
// load in Model character labels
|
|
modelChars, err := rknnlite.LoadLabels(*keysFile)
|
|
|
|
if err != nil {
|
|
log.Fatal("Error loading model OCR character keys: ", err)
|
|
}
|
|
|
|
// check that we have as many modelChars as tensor outputs dimension
|
|
if len(modelChars) != int(rt.OutputAttrs()[0].Dims[2]) {
|
|
log.Fatalf("OCR character keys text input has %d characters and does "+
|
|
"not match the required number in the Model of %d",
|
|
len(modelChars), rt.OutputAttrs()[0].Dims[2])
|
|
}
|
|
|
|
// create PPOCR post processor
|
|
ppocrProcessor := postprocess.NewPPOCRRecognise(postprocess.PPOCRRecogniseParams{
|
|
ModelChars: modelChars,
|
|
OutputSeqLen: int(rt.InputAttrs()[0].Dims[2]) / 8, // modelWidth (320/8)
|
|
})
|
|
|
|
// load image
|
|
img := gocv.IMRead(*imgFile, gocv.IMReadColor)
|
|
|
|
if img.Empty() {
|
|
log.Fatal("Error reading image from: ", *imgFile)
|
|
}
|
|
|
|
// resize image to 320x48 and keep aspect ratio, centered with black letterboxing
|
|
resizedImg := gocv.NewMat()
|
|
|
|
resizer := preprocess.NewResizer(img.Cols(), img.Rows(),
|
|
int(rt.InputAttrs()[0].Dims[2]), int(rt.InputAttrs()[0].Dims[1]),
|
|
)
|
|
|
|
resizer.LetterBoxResize(img, &resizedImg, render.Black)
|
|
|
|
// convert image to float32 in 3 channels
|
|
resizedImg.ConvertTo(&resizedImg, gocv.MatTypeCV32FC3)
|
|
|
|
// normalize the image (img - 127.5) / 127.5
|
|
resizedImg.AddFloat(-127.5)
|
|
resizedImg.DivideFloat(127.5)
|
|
|
|
defer img.Close()
|
|
defer resizedImg.Close()
|
|
defer resizer.Close()
|
|
|
|
start := time.Now()
|
|
|
|
// perform inference on image file
|
|
outputs, err := rt.Inference([]gocv.Mat{resizedImg})
|
|
|
|
if err != nil {
|
|
log.Fatal("Runtime inferencing failed with error: ", err)
|
|
}
|
|
|
|
endInference := time.Now()
|
|
|
|
results := ppocrProcessor.Recognise(outputs)
|
|
|
|
endRecognise := time.Now()
|
|
|
|
log.Printf("Model first run speed: inference=%s, post processing=%s, total time=%s\n",
|
|
endInference.Sub(start).String(),
|
|
endRecognise.Sub(endInference).String(),
|
|
endRecognise.Sub(start).String(),
|
|
)
|
|
|
|
for _, result := range results {
|
|
log.Printf("Recognize result: %s, score=%.2f", result.Text, result.Score)
|
|
}
|
|
|
|
// free outputs allocated in C memory after you have finished post processing
|
|
err = outputs.Free()
|
|
|
|
if err != nil {
|
|
log.Fatal("Error freeing Outputs: ", err)
|
|
}
|
|
|
|
// optional code. run benchmark to get average time of 10 runs
|
|
runBenchmark(rt, ppocrProcessor, []gocv.Mat{resizedImg})
|
|
|
|
// close runtime and release resources
|
|
err = rt.Close()
|
|
|
|
if err != nil {
|
|
log.Fatal("Error closing RKNN runtime: ", err)
|
|
}
|
|
|
|
log.Println("done")
|
|
}
|
|
|
|
func runBenchmark(rt *rknnlite.Runtime, ppocrProcessor *postprocess.PPOCRRecognise,
|
|
mats []gocv.Mat) {
|
|
|
|
count := 100
|
|
start := time.Now()
|
|
|
|
for i := 0; i < count; i++ {
|
|
// perform inference on image file
|
|
outputs, err := rt.Inference(mats)
|
|
|
|
if err != nil {
|
|
log.Fatal("Runtime inferencing failed with error: ", err)
|
|
}
|
|
|
|
// post process
|
|
_ = ppocrProcessor.Recognise(outputs)
|
|
|
|
err = outputs.Free()
|
|
|
|
if err != nil {
|
|
log.Fatal("Error freeing Outputs: ", err)
|
|
}
|
|
}
|
|
|
|
end := time.Now()
|
|
total := end.Sub(start)
|
|
avg := total / time.Duration(count)
|
|
|
|
log.Printf("Benchmark time=%s, count=%d, average total time=%s\n",
|
|
total.String(), count, avg.String(),
|
|
)
|
|
}
|