<|start_filename|>deploy/lite/db_post_process.h<|end_filename|>
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <math.h>

#include <iostream>
#include <map>
#include <vector>

#include "clipper.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"

template <class T> T clamp(T x, T min, T max) {
  if (x > max)
    return max;
  if (x < min)
    return min;
  return x;
}

std::vector<std::vector<float>> Mat2Vector(cv::Mat mat);

void GetContourArea(std::vector<std::vector<float>> box, float unclip_ratio,
                    float &distance);

cv::RotatedRect Unclip(std::vector<std::vector<float>> box, float unclip_ratio);

std::vector<std::vector<float>> Mat2Vector(cv::Mat mat);

bool XsortFp32(std::vector<float> a, std::vector<float> b);

bool XsortInt(std::vector<int> a, std::vector<int> b);

std::vector<std::vector<int>>
OrderPointsClockwise(std::vector<std::vector<int>> pts);

std::vector<std::vector<float>> GetMiniBoxes(cv::RotatedRect box, float &ssid);

float BoxScoreFast(std::vector<std::vector<float>> box_array, cv::Mat pred);

std::vector<std::vector<std::vector<int>>>
BoxesFromBitmap(const cv::Mat pred, const cv::Mat bitmap,
                std::map<std::string, double> Config);

std::vector<std::vector<std::vector<int>>>
FilterTagDetRes(std::vector<std::vector<std::vector<int>>> boxes, float ratio_h,
                float ratio_w, cv::Mat srcimg);


<|start_filename|>ppocr/postprocess/lanms/include/pybind11/typeid.h<|end_filename|>
/*
    pybind11/typeid.h: Compiler-independent access to type identifiers

    Copyright (c) 2016 <NAME> <<EMAIL>>

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

#pragma once

#include <cstdio>
#include <cstdlib>

#if defined(__GNUG__)
#include <cxxabi.h>
#endif

NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
/// Erase all occurrences of a substring
inline void erase_all(std::string &string, const std::string &search) {
    for (size_t pos = 0;;) {
        pos = string.find(search, pos);
        if (pos == std::string::npos) break;
        string.erase(pos, search.length());
    }
}

PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
#if defined(__GNUG__)
    int status = 0;
    std::unique_ptr<char, void (*)(void *)> res {
        abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
    if (status == 0)
        name = res.get();
#else
    detail::erase_all(name, "class ");
    detail::erase_all(name, "struct ");
    detail::erase_all(name, "enum ");
#endif
    detail::erase_all(name, "pybind11::");
}
NAMESPACE_END(detail)

/// Return a string representation of a C++ type
template <typename T> static std::string type_id() {
    std::string name(typeid(T).name());
    detail::clean_type_id(name);
    return name;
}

NAMESPACE_END(pybind11)


<|start_filename|>deploy/ios_demo/ocr_demo/OcrData.h<|end_filename|>
//
// Created by Lv,Xiangxiang on 2020/7/11.
// Copyright (c) 2020 Li,Xiaoyang(SYS). All rights reserved.
//

#import <Foundation/Foundation.h>


@interface OcrData : NSObject
@property(nonatomic, copy) NSString *label;
@property(nonatomic) int category;
@property(nonatomic) float accuracy;
@property(nonatomic) NSArray *polygonPoints;

@end

<|start_filename|>thirdparty/paddleocr-go/paddle/common.go<|end_filename|>
package paddle

// #cgo CFLAGS: -I../paddle_c/include
// #cgo LDFLAGS: -lpaddle_fluid_c
// #include <stdbool.h>
import "C"
import "fmt"

func ConvertCBooleanToGo(b C.bool) bool {
	var c_false C.bool
	if b != c_false {
		return true
	}
	return false
}

func numel(shape []int32) int32 {
	n := int32(1)
	for _, d := range shape {
		n *= d
	}
	return n
}

func bug(format string, args ...interface{}) error {
	return fmt.Errorf("Bug %v", fmt.Sprintf(format, args...))
}


<|start_filename|>deploy/lite/crnn_process.cc<|end_filename|>
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "crnn_process.h" //NOLINT
#include <algorithm>
#include <memory>
#include <string>

const std::vector<int> rec_image_shape{3, 32, 320};

cv::Mat CrnnResizeImg(cv::Mat img, float wh_ratio) {
  int imgC, imgH, imgW;
  imgC = rec_image_shape[0];
  imgW = rec_image_shape[2];
  imgH = rec_image_shape[1];

  imgW = int(32 * wh_ratio);

  float ratio = static_cast<float>(img.cols) / static_cast<float>(img.rows);
  int resize_w, resize_h;
  if (ceilf(imgH * ratio) > imgW)
    resize_w = imgW;
  else
    resize_w = static_cast<int>(ceilf(imgH * ratio));
  cv::Mat resize_img;
  cv::resize(img, resize_img, cv::Size(resize_w, imgH), 0.f, 0.f,
             cv::INTER_LINEAR);

  return resize_img;
}

std::vector<std::string> ReadDict(std::string path) {
  std::ifstream in(path);
  std::string filename;
  std::string line;
  std::vector<std::string> m_vec;
  if (in) {
    while (getline(in, line)) {
      m_vec.push_back(line);
    }
  } else {
    std::cout << "no such file" << std::endl;
  }
  return m_vec;
}

cv::Mat GetRotateCropImage(cv::Mat srcimage,
                           std::vector<std::vector<int>> box) {
  cv::Mat image;
  srcimage.copyTo(image);
  std::vector<std::vector<int>> points = box;

  int x_collect[4] = {box[0][0], box[1][0], box[2][0], box[3][0]};
  int y_collect[4] = {box[0][1], box[1][1], box[2][1], box[3][1]};
  int left = int(*std::min_element(x_collect, x_collect + 4));
  int right = int(*std::max_element(x_collect, x_collect + 4));
  int top = int(*std::min_element(y_collect, y_collect + 4));
  int bottom = int(*std::max_element(y_collect, y_collect + 4));

  cv::Mat img_crop;
  image(cv::Rect(left, top, right - left, bottom - top)).copyTo(img_crop);

  for (int i = 0; i < points.size(); i++) {
    points[i][0] -= left;
    points[i][1] -= top;
  }

  int img_crop_width =
      static_cast<int>(sqrt(pow(points[0][0] - points[1][0], 2) +
                            pow(points[0][1] - points[1][1], 2)));
  int img_crop_height =
      static_cast<int>(sqrt(pow(points[0][0] - points[3][0], 2) +
                            pow(points[0][1] - points[3][1], 2)));

  cv::Point2f pts_std[4];
  pts_std[0] = cv::Point2f(0., 0.);
  pts_std[1] = cv::Point2f(img_crop_width, 0.);
  pts_std[2] = cv::Point2f(img_crop_width, img_crop_height);
  pts_std[3] = cv::Point2f(0.f, img_crop_height);

  cv::Point2f pointsf[4];
  pointsf[0] = cv::Point2f(points[0][0], points[0][1]);
  pointsf[1] = cv::Point2f(points[1][0], points[1][1]);
  pointsf[2] = cv::Point2f(points[2][0], points[2][1]);
  pointsf[3] = cv::Point2f(points[3][0], points[3][1]);

  cv::Mat M = cv::getPerspectiveTransform(pointsf, pts_std);

  cv::Mat dst_img;
  cv::warpPerspective(img_crop, dst_img, M,
                      cv::Size(img_crop_width, img_crop_height),
                      cv::BORDER_REPLICATE);

  const float ratio = 1.5;
  if (static_cast<float>(dst_img.rows) >=
      static_cast<float>(dst_img.cols) * ratio) {
    cv::Mat srcCopy = cv::Mat(dst_img.rows, dst_img.cols, dst_img.depth());
    cv::transpose(dst_img, srcCopy);
    cv::flip(srcCopy, srcCopy, 0);
    return srcCopy;
  } else {
    return dst_img;
  }
}


<|start_filename|>thirdparty/paddleocr-go/paddle/tensor.go<|end_filename|>
package paddle

// #include <stdbool.h>
// #include <stdlib.h>
// #include <string.h>
// #include <paddle_c_api.h>
import "C"

import (
	"reflect"
	"runtime"
	"unsafe"
)

type PaddleDType C.PD_DataType

const (
	FLOAT32  PaddleDType = C.PD_FLOAT32
	INT32    PaddleDType = C.PD_INT32
	INT64    PaddleDType = C.PD_INT64
	UINT8    PaddleDType = C.PD_UINT8
	UNKDTYPE PaddleDType = C.PD_UNKDTYPE
)

var types = []struct {
	gotype reflect.Type
	dtype  PaddleDType
}{
	{reflect.TypeOf(float32(0)), FLOAT32},
	{reflect.TypeOf(int32(0)), INT32},
	{reflect.TypeOf(int64(0)), INT64},
	{reflect.TypeOf(uint8(0)), UINT8},
}

func typeOfDataType(dtype PaddleDType) reflect.Type {
	var ret reflect.Type
	for _, t := range types {
		if t.dtype == dtype {
			ret = t.gotype
		}
	}
	return ret
}

func sizeofDataType(dtype PaddleDType) int32 {
	switch dtype {
	case UINT8:
		return int32(C.sizeof_uchar)
	case INT32:
		return int32(C.sizeof_int)
	case INT64:
		return int32(C.sizeof_longlong)
	case FLOAT32:
		return int32(C.sizeof_float)
	}
	return -1
}

func shapeAndTypeOf(val reflect.Value) (shape []int32, dt PaddleDType) {
	gotype := val.Type()
	for gotype.Kind() == reflect.Array || gotype.Kind() == reflect.Slice {
		shape = append(shape, int32(val.Len()))
		if val.Len() > 0 {
			val = val.Index(0)
		}
		gotype = gotype.Elem()
	}

	for _, t := range types {
		if gotype.Kind() == t.gotype.Kind() {
			return shape, PaddleDType(t.dtype)
		}
	}
	return shape, dt
}

type ZeroCopyTensor struct {
	c     *C.PD_ZeroCopyTensor
	name  string
	shape []int32
}

func NewZeroCopyTensor() *ZeroCopyTensor {
	c_tensor := C.PD_NewZeroCopyTensor()

	tensor := &ZeroCopyTensor{c: c_tensor}
	runtime.SetFinalizer(tensor, (*ZeroCopyTensor).finalize)
	return tensor
}

func (tensor *ZeroCopyTensor) finalize() {
	C.PD_DeleteZeroCopyTensor(tensor.c)
}

func (tensor *ZeroCopyTensor) Shape() []int32 {
	return tensor.shape
}

func (tensor *ZeroCopyTensor) Name() string {
	return C.GoString(tensor.c.name)
}

func (tensor *ZeroCopyTensor) Rename(name string) {
	tensor.name = name
	tensor.c.name = (*C.char)(unsafe.Pointer(tensor.c.name))
}

func (tensor *ZeroCopyTensor) Reshape(shape []int32) {
	tensor.shape = make([]int32, len(shape))
	copy(tensor.shape, shape)
	length := C.sizeof_int * C.size_t(len(shape))
	if tensor.c.shape.capacity < C.size_t(length) {
		if tensor.c.shape.capacity != C.size_t(0) {
			C.free(tensor.c.shape.data)
		}
		tensor.c.shape.data = C.malloc(length)
		tensor.c.shape.capacity = length
	}
	tensor.c.shape.length = length
	C.memcpy(tensor.c.shape.data, unsafe.Pointer(&shape[0]), length)
}

func (tensor *ZeroCopyTensor) DataType() PaddleDType {
	return PaddleDType(tensor.c.dtype)
}

func (tensor *ZeroCopyTensor) SetValue(value interface{}) {
	val := reflect.ValueOf(value)
	shape, dtype := shapeAndTypeOf(val)
	num := numel(shape)
	length := C.size_t(sizeofDataType(dtype) * num)
	if tensor.c.data.capacity < length {
		if tensor.c.data.capacity != C.size_t(0) {
			C.free(tensor.c.data.data)
		}
		tensor.c.data.data = C.malloc(length)
		tensor.c.data.capacity = length
	}
	tensor.c.data.length = length

	switch dtype {
	case PaddleDType(UINT8):
		data := val.Interface().([]uint8)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	case PaddleDType(INT32):
		data := val.Interface().([]int32)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	case PaddleDType(INT64):
		data := val.Interface().([]int64)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	case PaddleDType(FLOAT32):
		data := val.Interface().([]float32)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	}
	tensor.c.dtype = C.PD_DataType(dtype)
}

func (tensor *ZeroCopyTensor) tensorData() []byte {
	cbytes := tensor.c.data.data
	length := tensor.c.data.length
	var slice []byte
	if unsafe.Sizeof(unsafe.Pointer(nil)) == 8 {
		slice = (*[1<<50 - 1]byte)(unsafe.Pointer(cbytes))[:length:length]
	} else {
		slice = (*[1 << 30]byte)(unsafe.Pointer(cbytes))[:length:length]
	}
	return slice
}

func (tensor *ZeroCopyTensor) Value() interface{} {
	t := typeOfDataType(PaddleDType(tensor.c.dtype))
	data := tensor.tensorData()
	return decodeTensor(data, tensor.Shape(), t).Interface()
}

// It isn't safe to use reflect.SliceHeader as it uses a uintptr for Data and
// this is not inspected by the garbage collector
type sliceHeader struct {
	Data unsafe.Pointer
	Len  int
	Cap  int
}

func decodeTensor(raw []byte, shape []int32, t reflect.Type) reflect.Value {
	// Create a 1-dimensional slice of the base large enough for the data and
	// copy the data in.
	n := int(numel(shape))

	l := n * int(t.Size())
	typ := reflect.SliceOf(t)
	slice := reflect.MakeSlice(typ, n, n)
	baseBytes := *(*[]byte)(unsafe.Pointer(&sliceHeader{
		Data: unsafe.Pointer(slice.Pointer()),
		Len:  l,
		Cap:  l,
	}))
	copy(baseBytes, raw)

	if len(shape) == 0 {
		// for n
		return slice.Index(0)
	}
	if len(shape) == 1 {
		// for {}
		return slice
	}
	// for {{} {}} {{} {}} {{} {}}
	if n == 0 {
		n = int(numel(shape[:len(shape)-1]))
	}
	for i := len(shape) - 2; i >= 0; i-- {
		underlyingSize := typ.Elem().Size()
		typ = reflect.SliceOf(typ)
		subsliceLen := int(shape[i+1])
		if subsliceLen != 0 {
			n = n / subsliceLen
		}
		data := unsafe.Pointer(slice.Pointer())
		nextSlice := reflect.MakeSlice(typ, n, n)

		for j := 0; j < n; j++ {
			// This is equivalent to nSlice[j] = slice[j*subsliceLen: (j+1)*subsliceLen]
			setSliceInSlice(nextSlice, j, sliceHeader{
				Data: unsafe.Pointer(uintptr(data) + (uintptr(j*subsliceLen) * underlyingSize)),
				Len:  subsliceLen,
				Cap:  subsliceLen,
			})
		}

		slice = nextSlice
	}
	return slice
}

// setSliceInSlice sets slice[index] = content.
func setSliceInSlice(slice reflect.Value, index int, content sliceHeader) {
	const sliceSize = unsafe.Sizeof(sliceHeader{})
	// We must cast slice.Pointer to uninptr & back again to avoid GC issues.
	// See https://github.com/google/go-cmp/issues/167#issuecomment-546093202
	*(*sliceHeader)(unsafe.Pointer(uintptr(unsafe.Pointer(slice.Pointer())) + (uintptr(index) * sliceSize))) = content
}

func (tensor *ZeroCopyTensor) Lod() []uint {
	var val []uint
	valHdr := (*reflect.SliceHeader)(unsafe.Pointer(&val))
	valHdr.Data = uintptr(unsafe.Pointer(tensor.c.lod.data))
	valHdr.Len = int(tensor.c.lod.length / C.sizeof_size_t)
	valHdr.Cap = int(tensor.c.lod.length / C.sizeof_size_t)
	return val
}


<|start_filename|>thirdparty/paddleocr-go/paddle/config.go<|end_filename|>
package paddle

// #include <stdbool.h>
// #include <stdlib.h>
// #include <paddle_c_api.h>
import "C"

import (
	"runtime"
	"unsafe"
)

type Precision C.Precision

const (
	Precision_FLOAT32 Precision = C.kFloat32
	Precision_INT8    Precision = C.kInt8
	Precision_HALF    Precision = C.kHalf
)

type AnalysisConfig struct {
	c *C.PD_AnalysisConfig
}

func NewAnalysisConfig() *AnalysisConfig {
	c_config := C.PD_NewAnalysisConfig()
	config := &AnalysisConfig{c: c_config}
	runtime.SetFinalizer(config, (*AnalysisConfig).finalize)
	return config
}

func (config *AnalysisConfig) finalize() {
	C.PD_DeleteAnalysisConfig(config.c)
}

func (config *AnalysisConfig) SetModel(model, params string) {
	c_model := C.CString(model)
	defer C.free(unsafe.Pointer(c_model))
	var c_params *C.char
	if params == "" {
		c_params = nil
	} else {
		c_params = C.CString(params)
		defer C.free(unsafe.Pointer(c_params))
	}

	C.PD_SetModel(config.c, c_model, c_params)
}

func (config *AnalysisConfig) ModelDir() string {
	return C.GoString(C.PD_ModelDir(config.c))
}

func (config *AnalysisConfig) ProgFile() string {
	return C.GoString(C.PD_ProgFile(config.c))
}

func (config *AnalysisConfig) ParamsFile() string {
	return C.GoString(C.PD_ParamsFile(config.c))
}

func (config *AnalysisConfig) EnableUseGpu(memory_pool_init_size_mb int, device_id int) {
	C.PD_EnableUseGpu(config.c, C.int(memory_pool_init_size_mb), C.int(device_id))
}

func (config *AnalysisConfig) DisableGpu() {
	C.PD_DisableGpu(config.c)
}

func (config *AnalysisConfig) UseGpu() bool {
	return ConvertCBooleanToGo(C.PD_UseGpu(config.c))
}

func (config *AnalysisConfig) GpuDeviceId() int {
	return int(C.PD_GpuDeviceId(config.c))
}

func (config *AnalysisConfig) MemoryPoolInitSizeMb() int {
	return int(C.PD_MemoryPoolInitSizeMb(config.c))
}

func (config *AnalysisConfig) EnableCudnn() {
	C.PD_EnableCUDNN(config.c)
}

func (config *AnalysisConfig) CudnnEnabled() bool {
	return ConvertCBooleanToGo(C.PD_CudnnEnabled(config.c))
}

func (config *AnalysisConfig) SwitchIrOptim(x bool) {
	C.PD_SwitchIrOptim(config.c, C.bool(x))
}

func (config *AnalysisConfig) IrOptim() bool {
	return ConvertCBooleanToGo(C.PD_IrOptim(config.c))
}

func (config *AnalysisConfig) SwitchUseFeedFetchOps(x bool) {
	C.PD_SwitchUseFeedFetchOps(config.c, C.bool(x))
}

func (config *AnalysisConfig) UseFeedFetchOpsEnabled() bool {
	return ConvertCBooleanToGo(C.PD_UseFeedFetchOpsEnabled(config.c))
}

func (config *AnalysisConfig) SwitchSpecifyInputNames(x bool) {
	C.PD_SwitchSpecifyInputNames(config.c, C.bool(x))
}

func (config *AnalysisConfig) SpecifyInputName() bool {
	return ConvertCBooleanToGo(C.PD_SpecifyInputName(config.c))
}

func (config *AnalysisConfig) EnableTensorRtEngine(workspace_size int, max_batch_size int, min_subgraph_size int, precision Precision, use_static bool, use_calib_mode bool) {
	C.PD_EnableTensorRtEngine(config.c, C.int(workspace_size), C.int(max_batch_size), C.int(min_subgraph_size), C.Precision(precision), C.bool(use_static), C.bool(use_calib_mode))
}

func (config *AnalysisConfig) TensorrtEngineEnabled() bool {
	return ConvertCBooleanToGo(C.PD_TensorrtEngineEnabled(config.c))
}

func (config *AnalysisConfig) SwitchIrDebug(x bool) {
	C.PD_SwitchIrDebug(config.c, C.bool(x))
}

func (config *AnalysisConfig) EnableMkldnn() {
	C.PD_EnableMKLDNN(config.c)
}

func (config *AnalysisConfig) SetCpuMathLibraryNumThreads(n int) {
	C.PD_SetCpuMathLibraryNumThreads(config.c, C.int(n))
}

func (config *AnalysisConfig) CpuMathLibraryNumThreads() int {
	return int(C.PD_CpuMathLibraryNumThreads(config.c))
}

func (config *AnalysisConfig) EnableMkldnnQuantizer() {
	C.PD_EnableMkldnnQuantizer(config.c)
}

func (config *AnalysisConfig) MkldnnQuantizerEnabled() bool {
	return ConvertCBooleanToGo(C.PD_MkldnnQuantizerEnabled(config.c))
}

// SetModelBuffer
// ModelFromMemory

func (config *AnalysisConfig) EnableMemoryOptim() {
	C.PD_EnableMemoryOptim(config.c)
}

func (config *AnalysisConfig) MemoryOptimEnabled() bool {
	return ConvertCBooleanToGo(C.PD_MemoryOptimEnabled(config.c))
}

func (config *AnalysisConfig) EnableProfile() {
	C.PD_EnableProfile(config.c)
}

func (config *AnalysisConfig) ProfileEnabled() bool {
	return ConvertCBooleanToGo(C.PD_ProfileEnabled(config.c))
}

func (config *AnalysisConfig) DisableGlogInfo() {
	C.PD_DisableGlogInfo(config.c)
}

func (config *AnalysisConfig) DeletePass(pass string) {
	c_pass := C.CString(pass)
	defer C.free(unsafe.Pointer(c_pass))
	C.PD_DeletePass(config.c, c_pass)
}

func (config *AnalysisConfig) SetInValid() {
	C.PD_SetInValid(config.c)
}

func (config *AnalysisConfig) IsValid() bool {
	return ConvertCBooleanToGo(C.PD_IsValid(config.c))
}


<|start_filename|>thirdparty/paddleocr-go/ppocr-go.go<|end_filename|>
package main

import (
	"flag"
	"log"
	"github.com/PaddlePaddle/PaddleOCR/thirdparty/paddleocr-go/ocr"
)

var (
	confFile     string
	image        string
	imageDir     string
	useServering bool
	port         string
)

func init() {
	flag.StringVar(&confFile, "config", "config/conf.yaml", "config from ocr system. If not given, will use default config.")
	flag.StringVar(&image, "image", "", "image to predict. if not given, will use image_dir")
	flag.StringVar(&imageDir, "image_dir", "", "imgs in dir to be predicted. if not given, will check servering")
	flag.BoolVar(&useServering, "use_servering", false, "whether to use ocr server. [default: false]")
	flag.StringVar(&port, "port", "18600", "which port to serve ocr server. [default: 18600].")
}

func main() {
	flag.Parse()
	sys := ocr.NewOCRSystem(confFile, nil)

	if image != "" {
		img := ocr.ReadImage(image)
		defer img.Close()
		results := sys.PredictOneImage(img)
		for _, res := range results {
			log.Println(res)
		}
		return
	}

	if imageDir != "" {
		results := sys.PredictDirImages(imageDir)
		for k, vs := range results {
			log.Printf("======== image: %v =======\n", k)
			for _, res := range vs {
				log.Println(res)
			}
		}
	}

	if useServering {
		sys.StartServer(port)
	}
}


<|start_filename|>deploy/android_demo/app/src/main/cpp/common.h<|end_filename|>
//
// Created by fu on 4/25/18.
//

#pragma once
#import <vector>
#import <numeric>

#ifdef __ANDROID__

#include <android/log.h>

#define LOG_TAG "OCR_NDK"

#define LOGI(...) \
  __android_log_print(ANDROID_LOG_INFO,  LOG_TAG,  __VA_ARGS__)
#define LOGW(...) \
  __android_log_print(ANDROID_LOG_WARN,  LOG_TAG,  __VA_ARGS__)
#define LOGE(...) \
  __android_log_print(ANDROID_LOG_ERROR,  LOG_TAG,  __VA_ARGS__)
#else
#include <stdio.h>
#define LOGI(format, ...) \
  fprintf(stdout, "[" LOG_TAG "]" format "\n", ##__VA_ARGS__)
#define LOGW(format, ...) \
  fprintf(stdout, "[" LOG_TAG "]" format "\n", ##__VA_ARGS__)
#define LOGE(format, ...) \
  fprintf(stderr, "[" LOG_TAG "]Error: " format "\n", ##__VA_ARGS__)
#endif

enum RETURN_CODE {
    RETURN_OK = 0
};

enum NET_TYPE{
    NET_OCR = 900100,
    NET_OCR_INTERNAL = 991008
};


template <typename  T>
inline T product(const std::vector<T> &vec) {
    if (vec.empty()){
        return 0;
    }
    return std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<T>());
}



<|start_filename|>thirdparty/paddleocr-go/ocr/postprocess.go<|end_filename|>
package ocr

import (
	"image"
	"image/color"
	"math"
	"sort"

	"github.com/LKKlein/gocv"
	"github.com/PaddlePaddle/PaddleOCR/thirdparty/paddleocr-go/paddle"
	clipper "github.com/ctessum/go.clipper"
)

type xFloatSortBy [][]float32

func (a xFloatSortBy) Len() int           { return len(a) }
func (a xFloatSortBy) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a xFloatSortBy) Less(i, j int) bool { return a[i][0] < a[j][0] }

type xIntSortBy [][]int

func (a xIntSortBy) Len() int           { return len(a) }
func (a xIntSortBy) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a xIntSortBy) Less(i, j int) bool { return a[i][0] < a[j][0] }

type DetPostProcess interface {
	Run(output *paddle.ZeroCopyTensor, oriH, oriW int, ratioH, ratioW float64) [][][]int
}

type DBPostProcess struct {
	thresh        float64
	boxThresh     float64
	maxCandidates int
	unClipRatio   float64
	minSize       int
}

func NewDBPostProcess(thresh, boxThresh, unClipRatio float64) *DBPostProcess {
	return &DBPostProcess{
		thresh:        thresh,
		boxThresh:     boxThresh,
		unClipRatio:   unClipRatio,
		maxCandidates: 1000,
		minSize:       3,
	}
}

func (d *DBPostProcess) getMinBoxes(rect gocv.RotatedRect) [][]float32 {
	points := gocv.NewMat()
	gocv.BoxPoints(rect, &points)
	defer points.Close()
	array := d.mat2slice(points)
	sort.Sort(xFloatSortBy(array))

	point1, point2, point3, point4 := array[0], array[1], array[2], array[3]
	if array[3][1] <= array[2][1] {
		point2, point3 = array[3], array[2]
	} else {
		point2, point3 = array[2], array[3]
	}

	if array[1][1] <= array[0][1] {
		point1, point4 = array[1], array[0]
	} else {
		point1, point4 = array[0], array[1]
	}

	array = [][]float32{point1, point2, point3, point4}
	return array
}

func (d *DBPostProcess) mat2slice(mat gocv.Mat) [][]float32 {
	array := make([][]float32, mat.Rows())
	for i := 0; i < mat.Rows(); i++ {
		tmp := make([]float32, mat.Cols())
		for j := 0; j < mat.Cols(); j++ {
			tmp[j] = mat.GetFloatAt(i, j)
		}
		array[i] = tmp
	}
	return array
}

func (d *DBPostProcess) boxScoreFast(array [][]float32, pred gocv.Mat) float64 {
	height, width := pred.Rows(), pred.Cols()
	boxX := []float32{array[0][0], array[1][0], array[2][0], array[3][0]}
	boxY := []float32{array[0][1], array[1][1], array[2][1], array[3][1]}

	xmin := clip(int(math.Floor(float64(minf(boxX)))), 0, width-1)
	xmax := clip(int(math.Ceil(float64(maxf(boxX)))), 0, width-1)
	ymin := clip(int(math.Floor(float64(minf(boxY)))), 0, height-1)
	ymax := clip(int(math.Ceil(float64(maxf(boxY)))), 0, height-1)

	mask := gocv.NewMatWithSize(ymax-ymin+1, xmax-xmin+1, gocv.MatTypeCV8UC1)
	defer mask.Close()
	ppt := make([][]image.Point, 1)
	ppt[0] = make([]image.Point, 4)
	ppt[0][0] = image.Point{int(array[0][0]) - xmin, int(array[0][1]) - ymin}
	ppt[0][1] = image.Point{int(array[1][0]) - xmin, int(array[1][1]) - ymin}
	ppt[0][2] = image.Point{int(array[2][0]) - xmin, int(array[2][1]) - ymin}
	ppt[0][3] = image.Point{int(array[3][0]) - xmin, int(array[3][1]) - ymin}
	gocv.FillPoly(&mask, ppt, color.RGBA{0, 0, 1, 0})
	croppedImg := pred.Region(image.Rect(xmin, ymin, xmax+1, ymax+1))
	s := croppedImg.MeanWithMask(mask)
	return s.Val1
}

func (d *DBPostProcess) unClip(box [][]float32) gocv.RotatedRect {
	var area, dist float64
	for i := 0; i < 4; i++ {
		area += float64(box[i][0]*box[(i+1)%4][1] - box[i][1]*box[(i+1)%4][0])
		dist += math.Sqrt(float64(
			(box[i][0]-box[(i+1)%4][0])*(box[i][0]-box[(i+1)%4][0]) +
				(box[i][1]-box[(i+1)%4][1])*(box[i][1]-box[(i+1)%4][1]),
		))
	}
	area = math.Abs(area / 2.0)
	distance := area * d.unClipRatio / dist
	offset := clipper.NewClipperOffset()
	path := make([]*clipper.IntPoint, 4)
	path[0] = &clipper.IntPoint{X: clipper.CInt(box[0][0]), Y: clipper.CInt(box[0][1])}
	path[1] = &clipper.IntPoint{X: clipper.CInt(box[1][0]), Y: clipper.CInt(box[1][1])}
	path[2] = &clipper.IntPoint{X: clipper.CInt(box[2][0]), Y: clipper.CInt(box[2][1])}
	path[3] = &clipper.IntPoint{X: clipper.CInt(box[3][0]), Y: clipper.CInt(box[3][1])}
	offset.AddPath(clipper.Path(path), clipper.JtRound, clipper.EtClosedPolygon)
	soln := offset.Execute(distance)

	points := make([]image.Point, 0, 4)
	for i := 0; i < len(soln); i++ {
		for j := 0; j < len(soln[i]); j++ {
			points = append(points, image.Point{int(soln[i][j].X), int(soln[i][j].Y)})
		}
	}

	var res gocv.RotatedRect
	if len(points) <= 0 {
		points = make([]image.Point, 4)
		points[0] = image.Pt(0, 0)
		points[1] = image.Pt(1, 0)
		points[2] = image.Pt(1, 1)
		points[3] = image.Pt(0, 1)
		res = gocv.RotatedRect{
			Contour:      points,
			BoundingRect: image.Rect(0, 0, 1, 1),
			Center:       gocv.Point2f{X: 0.5, Y: 0.5},
			Width:        1,
			Height:       1,
			Angle:        0,
		}
	} else {
		res = gocv.MinAreaRect(points)
	}
	return res
}

func (d *DBPostProcess) boxesFromBitmap(pred gocv.Mat, mask gocv.Mat, ratioH float64, ratioW float64) [][][]int {
	height, width := mask.Rows(), mask.Cols()
	mask.MultiplyUChar(255)
	contours := gocv.FindContours(mask, gocv.RetrievalList, gocv.ChainApproxSimple)
	numContours := len(contours)
	if numContours > d.maxCandidates {
		numContours = d.maxCandidates
	}

	boxes := make([][][]int, 0, numContours)
	for i := 0; i < numContours; i++ {
		contour := contours[i]
		boundingbox := gocv.MinAreaRect(contour)
		if boundingbox.Width < float32(d.minSize) || boundingbox.Height < float32(d.minSize) {
			continue
		}
		points := d.getMinBoxes(boundingbox)
		score := d.boxScoreFast(points, pred)
		if score < d.boxThresh {
			continue
		}

		box := d.unClip(points)
		if box.Width < float32(d.minSize+2) || box.Height < float32(d.minSize+2) {
			continue
		}

		cliparray := d.getMinBoxes(box)
		dstHeight, dstWidth := pred.Rows(), pred.Cols()
		intcliparray := make([][]int, 4)
		for i := 0; i < 4; i++ {
			p := []int{
				int(float64(clip(int(math.Round(
					float64(cliparray[i][0]/float32(width)*float32(dstWidth)))), 0, dstWidth)) / ratioW),
				int(float64(clip(int(math.Round(
					float64(cliparray[i][1]/float32(height)*float32(dstHeight)))), 0, dstHeight)) / ratioH),
			}
			intcliparray[i] = p
		}
		boxes = append(boxes, intcliparray)
	}
	return boxes
}

func (d *DBPostProcess) orderPointsClockwise(box [][]int) [][]int {
	sort.Sort(xIntSortBy(box))
	leftmost := [][]int{box[0], box[1]}
	rightmost := [][]int{box[2], box[3]}

	if leftmost[0][1] > leftmost[1][1] {
		leftmost[0], leftmost[1] = leftmost[1], leftmost[0]
	}

	if rightmost[0][1] > rightmost[1][1] {
		rightmost[0], rightmost[1] = rightmost[1], rightmost[0]
	}

	return [][]int{leftmost[0], rightmost[0], rightmost[1], leftmost[1]}
}

func (d *DBPostProcess) filterTagDetRes(boxes [][][]int, oriH, oriW int) [][][]int {
	points := make([][][]int, 0, len(boxes))
	for i := 0; i < len(boxes); i++ {
		boxes[i] = d.orderPointsClockwise(boxes[i])
		for j := 0; j < len(boxes[i]); j++ {
			boxes[i][j][0] = clip(boxes[i][j][0], 0, oriW-1)
			boxes[i][j][1] = clip(boxes[i][j][1], 0, oriH-1)
		}
	}

	for i := 0; i < len(boxes); i++ {
		rectW := int(math.Sqrt(math.Pow(float64(boxes[i][0][0]-boxes[i][1][0]), 2.0) +
			math.Pow(float64(boxes[i][0][1]-boxes[i][1][1]), 2.0)))
		rectH := int(math.Sqrt(math.Pow(float64(boxes[i][0][0]-boxes[i][3][0]), 2.0) +
			math.Pow(float64(boxes[i][0][1]-boxes[i][3][1]), 2.0)))
		if rectW <= 4 || rectH <= 4 {
			continue
		}
		points = append(points, boxes[i])
	}
	return points
}

func (d *DBPostProcess) Run(output *paddle.ZeroCopyTensor, oriH, oriW int, ratioH, ratioW float64) [][][]int {
	v := output.Value().([][][][]float32)

	shape := output.Shape()
	height, width := int(shape[2]), int(shape[3])

	pred := gocv.NewMatWithSize(height, width, gocv.MatTypeCV32F)
	bitmap := gocv.NewMatWithSize(height, width, gocv.MatTypeCV8UC1)
	thresh := float32(d.thresh)
	for i := 0; i < height; i++ {
		for j := 0; j < width; j++ {
			pred.SetFloatAt(i, j, v[0][0][i][j])
			if v[0][0][i][j] > thresh {
				bitmap.SetUCharAt(i, j, 1)
			} else {
				bitmap.SetUCharAt(i, j, 0)
			}
		}
	}

	mask := gocv.NewMat()
	kernel := gocv.GetStructuringElement(gocv.MorphRect, image.Point{2, 2})
	gocv.Dilate(bitmap, &mask, kernel)
	boxes := d.boxesFromBitmap(pred, mask, ratioH, ratioW)
	dtboxes := d.filterTagDetRes(boxes, oriH, oriW)
	return dtboxes
}


<|start_filename|>deploy/android_demo/app/src/main/cpp/ocr_db_post_process.h<|end_filename|>
//
// Created by fujiayi on 2020/7/2.
//
#pragma once
#include <vector>
#include <opencv2/opencv.hpp>

std::vector<std::vector<std::vector<int>>>
boxes_from_bitmap(const cv::Mat &pred, const cv::Mat &bitmap);

std::vector<std::vector<std::vector<int>>>
filter_tag_det_res(
    const std::vector<std::vector<std::vector<int>>> &o_boxes,
    float ratio_h,
    float ratio_w,
    const cv::Mat &srcimg
);

<|start_filename|>deploy/cpp_infer/src/ocr_cls.cpp<|end_filename|>
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <include/ocr_cls.h>

namespace PaddleOCR {

cv::Mat Classifier::Run(cv::Mat &img) {
  cv::Mat src_img;
  img.copyTo(src_img);
  cv::Mat resize_img;

  std::vector<int> rec_image_shape = {3, 48, 192};
  int index = 0;
  float wh_ratio = float(img.cols) / float(img.rows);

  this->resize_op_.Run(img, resize_img, rec_image_shape);

  this->normalize_op_.Run(&resize_img, this->mean_, this->scale_,
                          this->is_scale_);

  std::vector<float> input(1 * 3 * resize_img.rows * resize_img.cols, 0.0f);

  this->permute_op_.Run(&resize_img, input.data());

  // Inference.
  if (this->use_zero_copy_run_) {
    auto input_names = this->predictor_->GetInputNames();
    auto input_t = this->predictor_->GetInputTensor(input_names[0]);
    input_t->Reshape({1, 3, resize_img.rows, resize_img.cols});
    input_t->copy_from_cpu(input.data());
    this->predictor_->ZeroCopyRun();
  } else {
    paddle::PaddleTensor input_t;
    input_t.shape = {1, 3, resize_img.rows, resize_img.cols};
    input_t.data =
        paddle::PaddleBuf(input.data(), input.size() * sizeof(float));
    input_t.dtype = PaddleDType::FLOAT32;
    std::vector<paddle::PaddleTensor> outputs;
    this->predictor_->Run({input_t}, &outputs, 1);
  }

  std::vector<float> softmax_out;
  std::vector<int64_t> label_out;
  auto output_names = this->predictor_->GetOutputNames();
  auto softmax_out_t = this->predictor_->GetOutputTensor(output_names[0]);
  auto label_out_t = this->predictor_->GetOutputTensor(output_names[1]);
  auto softmax_shape_out = softmax_out_t->shape();
  auto label_shape_out = label_out_t->shape();

  int softmax_out_num =
      std::accumulate(softmax_shape_out.begin(), softmax_shape_out.end(), 1,
                      std::multiplies<int>());

  int label_out_num =
      std::accumulate(label_shape_out.begin(), label_shape_out.end(), 1,
                      std::multiplies<int>());
  softmax_out.resize(softmax_out_num);
  label_out.resize(label_out_num);

  softmax_out_t->copy_to_cpu(softmax_out.data());
  label_out_t->copy_to_cpu(label_out.data());

  int label = label_out[0];
  float score = softmax_out[label];
  //    std::cout << "\nlabel "<<label<<" score: "<<score;
  if (label % 2 == 1 && score > this->cls_thresh) {
    cv::rotate(src_img, src_img, 1);
  }
  return src_img;
}

void Classifier::LoadModel(const std::string &model_dir) {
  AnalysisConfig config;
  config.SetModel(model_dir + "/model", model_dir + "/params");

  if (this->use_gpu_) {
    config.EnableUseGpu(this->gpu_mem_, this->gpu_id_);
  } else {
    config.DisableGpu();
    if (this->use_mkldnn_) {
      config.EnableMKLDNN();
    }
    config.SetCpuMathLibraryNumThreads(this->cpu_math_library_num_threads_);
  }

  // false for zero copy tensor
  config.SwitchUseFeedFetchOps(!this->use_zero_copy_run_);
  // true for multiple input
  config.SwitchSpecifyInputNames(true);

  config.SwitchIrOptim(true);

  config.EnableMemoryOptim();
  config.DisableGlogInfo();

  this->predictor_ = CreatePaddlePredictor(config);
}
} // namespace PaddleOCR


<|start_filename|>ppocr/postprocess/lanms/include/pybind11/options.h<|end_filename|>
/*
    pybind11/options.h: global settings that are configurable at runtime.

    Copyright (c) 2016 <NAME> <<EMAIL>>

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

#pragma once

#include "common.h"

NAMESPACE_BEGIN(pybind11)

class options {
public:

    // Default RAII constructor, which leaves settings as they currently are.
    options() : previous_state(global_state()) {}

    // Class is non-copyable.
    options(const options&) = delete;
    options& operator=(const options&) = delete;

    // Destructor, which restores settings that were in effect before.
    ~options() {
        global_state() = previous_state;
    }

    // Setter methods (affect the global state):

    options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; }

    options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; }

    options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; }

    options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }

    // Getter methods (return the global state):

    static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }

    static bool show_function_signatures() { return global_state().show_function_signatures; }

    // This type is not meant to be allocated on the heap.
    void* operator new(size_t) = delete;

private:

    struct state {
        bool show_user_defined_docstrings = true;  //< Include user-supplied texts in docstrings.
        bool show_function_signatures = true;      //< Include auto-generated function signatures in docstrings.
    };

    static state &global_state() {
        static state instance;
        return instance;
    }

    state previous_state;
};

NAMESPACE_END(pybind11)


<|start_filename|>thirdparty/paddleocr-go/ocr/utils.go<|end_filename|>
package ocr

import (
	"archive/tar"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/LKKlein/gocv"
	"gopkg.in/yaml.v3"
)

func getString(args map[string]interface{}, key string, dv string) string {
	if f, ok := args[key]; ok {
		return f.(string)
	}
	return dv
}

func getFloat64(args map[string]interface{}, key string, dv float64) float64 {
	if f, ok := args[key]; ok {
		return f.(float64)
	}
	return dv
}

func getInt(args map[string]interface{}, key string, dv int) int {
	if i, ok := args[key]; ok {
		return i.(int)
	}
	return dv
}

func getBool(args map[string]interface{}, key string, dv bool) bool {
	if b, ok := args[key]; ok {
		return b.(bool)
	}
	return dv
}

func ReadImage(image_path string) gocv.Mat {
	img := gocv.IMRead(image_path, gocv.IMReadColor)
	if img.Empty() {
		log.Printf("Could not read image %s\n", image_path)
		os.Exit(1)
	}
	return img
}

func clip(value, min, max int) int {
	if value <= min {
		return min
	} else if value >= max {
		return max
	}
	return value
}

func minf(data []float32) float32 {
	v := data[0]
	for _, val := range data {
		if val < v {
			v = val
		}
	}
	return v
}

func maxf(data []float32) float32 {
	v := data[0]
	for _, val := range data {
		if val > v {
			v = val
		}
	}
	return v
}

func mini(data []int) int {
	v := data[0]
	for _, val := range data {
		if val < v {
			v = val
		}
	}
	return v
}

func maxi(data []int) int {
	v := data[0]
	for _, val := range data {
		if val > v {
			v = val
		}
	}
	return v
}

func argmax(arr []float32) (int, float32) {
	max_value, index := arr[0], 0
	for i, item := range arr {
		if item > max_value {
			max_value = item
			index = i
		}
	}
	return index, max_value
}

func checkModelExists(modelPath string) bool {
	if isPathExist(modelPath+"/model") && isPathExist(modelPath+"/params") {
		return true
	}
	if strings.HasPrefix(modelPath, "http://") ||
		strings.HasPrefix(modelPath, "ftp://") || strings.HasPrefix(modelPath, "https://") {
		return true
	}
	return false
}

func downloadFile(filepath, url string) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	out, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	log.Println("[download_file] from:", url, " to:", filepath)
	return err
}

func isPathExist(path string) bool {
	if _, err := os.Stat(path); err == nil {
		return true
	} else if os.IsNotExist(err) {
		return false
	}
	return false
}

func downloadModel(modelDir, modelPath string) (string, error) {
	if modelPath != "" && (strings.HasPrefix(modelPath, "http://") ||
		strings.HasPrefix(modelPath, "ftp://") || strings.HasPrefix(modelPath, "https://")) {
		if checkModelExists(modelDir) {
			return modelDir, nil
		}
		_, suffix := path.Split(modelPath)
		outPath := filepath.Join(modelDir, suffix)
		outDir := filepath.Dir(outPath)
		if !isPathExist(outDir) {
			os.MkdirAll(outDir, os.ModePerm)
		}

		if !isPathExist(outPath) {
			err := downloadFile(outPath, modelPath)
			if err != nil {
				return "", err
			}
		}

		if strings.HasSuffix(outPath, ".tar") && !checkModelExists(modelDir) {
			unTar(modelDir, outPath)
			os.Remove(outPath)
			return modelDir, nil
		}
		return modelDir, nil
	}
	return modelPath, nil
}

func unTar(dst, src string) (err error) {
	fr, err := os.Open(src)
	if err != nil {
		return err
	}
	defer fr.Close()

	tr := tar.NewReader(fr)
	for {
		hdr, err := tr.Next()

		switch {
		case err == io.EOF:
			return nil
		case err != nil:
			return err
		case hdr == nil:
			continue
		}

		var dstFileDir string
		if strings.Contains(hdr.Name, "model") {
			dstFileDir = filepath.Join(dst, "model")
		} else if strings.Contains(hdr.Name, "params") {
			dstFileDir = filepath.Join(dst, "params")
		}

		switch hdr.Typeflag {
		case tar.TypeDir:
			continue
		case tar.TypeReg:
			file, err := os.OpenFile(dstFileDir, os.O_CREATE|os.O_RDWR, os.FileMode(hdr.Mode))
			if err != nil {
				return err
			}
			_, err2 := io.Copy(file, tr)
			if err2 != nil {
				return err2
			}
			file.Close()
		}
	}

	return nil
}

func readLines2StringSlice(filepath string) []string {
	if strings.HasPrefix(filepath, "http://") || strings.HasPrefix(filepath, "https://") {
		home, _ := os.UserHomeDir()
		dir := home + "/.paddleocr/rec/"
		_, suffix := path.Split(filepath)
		f := dir + suffix
		if !isPathExist(f) {
			err := downloadFile(f, filepath)
			if err != nil {
				log.Println("download ppocr key file error! You can specify your local dict path by conf.yaml.")
				return nil
			}
		}
		filepath = f
	}
	content, err := ioutil.ReadFile(filepath)
	if err != nil {
		log.Println("read ppocr key file error!")
		return nil
	}
	lines := strings.Split(string(content), "\n")
	return lines
}

func ReadYaml(yamlPath string) (map[string]interface{}, error) {
	data, err := ioutil.ReadFile(yamlPath)
	if err != nil {
		return nil, err
	}
	var body interface{}
	if err := yaml.Unmarshal(data, &body); err != nil {
		return nil, err
	}

	body = convertYaml2Map(body)
	return body.(map[string]interface{}), nil
}

func convertYaml2Map(i interface{}) interface{} {
	switch x := i.(type) {
	case map[interface{}]interface{}:
		m2 := map[string]interface{}{}
		for k, v := range x {
			m2[k.(string)] = convertYaml2Map(v)
		}
		return m2
	case []interface{}:
		for i, v := range x {
			x[i] = convertYaml2Map(v)
		}
	}
	return i
}


<|start_filename|>deploy/ios_demo/ocr_demo/timer.h<|end_filename|>
//
//  timer.h
//  face_demo
//
//  Created by Li,Xiaoyang(SYS) on 2019/8/20.
//  Copyright © 2019年 Li,Xiaoyang(SYS). All rights reserved.
//

#ifndef timer_h
#define timer_h
#include <chrono>
#include <list>
class Timer final {
    
public:
    Timer() {}
    
    ~Timer() {}
    
    void clear() {
        ms_time.clear();
    }
    
    void start() {
        tstart = std::chrono::system_clock::now();
    }
    
    void end() {
        tend = std::chrono::system_clock::now();
        auto ts = std::chrono::duration_cast<std::chrono::microseconds>(tend - tstart);
        float elapse_ms = 1000.f * float(ts.count()) * std::chrono::microseconds::period::num / \
        std::chrono::microseconds::period::den;
        ms_time.push_back(elapse_ms);
    }
    
    float get_average_ms() {
        if (ms_time.size() == 0) {
            return 0.f;
        }
        float sum = 0.f;
        for (auto i : ms_time){
            sum += i;
        }
        return sum / ms_time.size();
    }
    
    float get_sum_ms(){
        if (ms_time.size() == 0) {
            return 0.f;
        }
        float sum = 0.f;
        for (auto i : ms_time){
            sum += i;
        }
        return sum;
    }
    
    // return tile (0-99) time.
    float get_tile_time(float tile) {
        
        if (tile <0 || tile > 100) {
            return -1.f;
        }
        int total_items = (int)ms_time.size();
        if (total_items <= 0) {
            return -2.f;
        }
        ms_time.sort();
        int pos = (int)(tile * total_items / 100);
        auto it = ms_time.begin();
        for (int i = 0; i < pos; ++i) {
            ++it;
        }
        return *it;
    }
    
    const std::list<float> get_time_stat() {
        return ms_time;
    }
    
private:
    std::chrono::time_point<std::chrono::system_clock> tstart;
    std::chrono::time_point<std::chrono::system_clock> tend;
    std::list<float> ms_time;
};

#endif /* timer_h */


<|start_filename|>thirdparty/paddleocr-go/ocr/core.go<|end_filename|>
package ocr

import (
	"bytes"
	"encoding/json"
	"errors"
	"image"
	"image/color"
	"io"
	"log"
	"math"
	"net/http"
	"path"
	"path/filepath"
	"sort"
	"strings"

	"github.com/LKKlein/gocv"
	"github.com/PaddlePaddle/PaddleOCR/thirdparty/paddleocr-go/paddle"
)

type PaddleModel struct {
	predictor *paddle.Predictor
	input     *paddle.ZeroCopyTensor
	outputs   []*paddle.ZeroCopyTensor

	useGPU      bool
	deviceID    int
	initGPUMem  int
	numThreads  int
	useMKLDNN   bool
	useTensorRT bool
	useIROptim  bool
}

func NewPaddleModel(args map[string]interface{}) *PaddleModel {
	return &PaddleModel{
		useGPU:      getBool(args, "use_gpu", false),
		deviceID:    getInt(args, "gpu_id", 0),
		initGPUMem:  getInt(args, "gpu_mem", 1000),
		numThreads:  getInt(args, "num_cpu_threads", 6),
		useMKLDNN:   getBool(args, "enable_mkldnn", false),
		useTensorRT: getBool(args, "use_tensorrt", false),
		useIROptim:  getBool(args, "ir_optim", true),
	}
}

func (model *PaddleModel) LoadModel(modelDir string) {
	config := paddle.NewAnalysisConfig()
	config.DisableGlogInfo()

	config.SetModel(modelDir+"/model", modelDir+"/params")
	if model.useGPU {
		config.EnableUseGpu(model.initGPUMem, model.deviceID)
	} else {
		config.DisableGpu()
		config.SetCpuMathLibraryNumThreads(model.numThreads)
		if model.useMKLDNN {
			config.EnableMkldnn()
		}
	}

	// config.EnableMemoryOptim()
	if model.useIROptim {
		config.SwitchIrOptim(true)
	}

	// false for zero copy tensor
	config.SwitchUseFeedFetchOps(false)
	config.SwitchSpecifyInputNames(true)

	model.predictor = paddle.NewPredictor(config)
	model.input = model.predictor.GetInputTensors()[0]
	model.outputs = model.predictor.GetOutputTensors()
}

type OCRText struct {
	BBox  [][]int `json:"bbox"`
	Text  string  `json:"text"`
	Score float64 `json:"score"`
}

type TextPredictSystem struct {
	detector *DBDetector
	cls      *TextClassifier
	rec      *TextRecognizer
}

func NewTextPredictSystem(args map[string]interface{}) *TextPredictSystem {
	sys := &TextPredictSystem{
		detector: NewDBDetector(getString(args, "det_model_dir", ""), args),
		rec:      NewTextRecognizer(getString(args, "rec_model_dir", ""), args),
	}
	if getBool(args, "use_angle_cls", false) {
		sys.cls = NewTextClassifier(getString(args, "cls_model_dir", ""), args)
	}
	return sys
}

func (sys *TextPredictSystem) sortBoxes(boxes [][][]int) [][][]int {
	sort.Slice(boxes, func(i, j int) bool {
		if boxes[i][0][1] < boxes[j][0][1] {
			return true
		}
		if boxes[i][0][1] > boxes[j][0][1] {
			return false
		}
		return boxes[i][0][0] < boxes[j][0][0]
	})

	for i := 0; i < len(boxes)-1; i++ {
		if math.Abs(float64(boxes[i+1][0][1]-boxes[i][0][1])) < 10 && boxes[i+1][0][0] < boxes[i][0][0] {
			boxes[i], boxes[i+1] = boxes[i+1], boxes[i]
		}
	}
	return boxes
}

func (sys *TextPredictSystem) getRotateCropImage(img gocv.Mat, box [][]int) gocv.Mat {
	cropW := int(math.Sqrt(math.Pow(float64(box[0][0]-box[1][0]), 2) + math.Pow(float64(box[0][1]-box[1][1]), 2)))
	cropH := int(math.Sqrt(math.Pow(float64(box[0][0]-box[3][0]), 2) + math.Pow(float64(box[0][1]-box[3][1]), 2)))
	ptsstd := make([]image.Point, 4)
	ptsstd[0] = image.Pt(0, 0)
	ptsstd[1] = image.Pt(cropW, 0)
	ptsstd[2] = image.Pt(cropW, cropH)
	ptsstd[3] = image.Pt(0, cropH)

	points := make([]image.Point, 4)
	points[0] = image.Pt(box[0][0], box[0][1])
	points[1] = image.Pt(box[1][0], box[1][1])
	points[2] = image.Pt(box[2][0], box[2][1])
	points[3] = image.Pt(box[3][0], box[3][1])

	M := gocv.GetPerspectiveTransform(points, ptsstd)
	defer M.Close()
	dstimg := gocv.NewMat()
	gocv.WarpPerspectiveWithParams(img, &dstimg, M, image.Pt(cropW, cropH),
		gocv.InterpolationCubic, gocv.BorderReplicate, color.RGBA{0, 0, 0, 0})

	if float64(dstimg.Rows()) >= float64(dstimg.Cols())*1.5 {
		srcCopy := gocv.NewMat()
		gocv.Transpose(dstimg, &srcCopy)
		defer dstimg.Close()
		gocv.Flip(srcCopy, &srcCopy, 0)
		return srcCopy
	}
	return dstimg
}

func (sys *TextPredictSystem) Run(img gocv.Mat) []OCRText {
	srcimg := gocv.NewMat()
	defer srcimg.Close()
	img.CopyTo(&srcimg)
	boxes := sys.detector.Run(img)
	if len(boxes) == 0 {
		return nil
	}

	boxes = sys.sortBoxes(boxes)
	cropimages := make([]gocv.Mat, len(boxes))
	for i := 0; i < len(boxes); i++ {
		tmpbox := make([][]int, len(boxes[i]))
		for j := 0; j < len(tmpbox); j++ {
			tmpbox[j] = make([]int, len(boxes[i][j]))
			copy(tmpbox[j], boxes[i][j])
		}
		cropimg := sys.getRotateCropImage(srcimg, tmpbox)
		cropimages[i] = cropimg
	}
	if sys.cls != nil {
		cropimages = sys.cls.Run(cropimages)
	}
	recResult := sys.rec.Run(cropimages, boxes)
	return recResult
}

type OCRSystem struct {
	args map[string]interface{}
	tps  *TextPredictSystem
}

func NewOCRSystem(confFile string, a map[string]interface{}) *OCRSystem {
	args, err := ReadYaml(confFile)
	if err != nil {
		log.Printf("Read config file %v failed! Please check. err: %v\n", confFile, err)
		log.Println("Program will use default config.")
		args = defaultArgs
	}
	for k, v := range a {
		args[k] = v
	}
	return &OCRSystem{
		args: args,
		tps:  NewTextPredictSystem(args),
	}
}

func (ocr *OCRSystem) StartServer(port string) {
	http.HandleFunc("/ocr", ocr.predictHandler)
	log.Println("OCR Server has been started on port :", port)
	err := http.ListenAndServe(":"+port, nil)
	if err != nil {
		log.Panicf("http error! error: %v\n", err)
	}
}

func (ocr *OCRSystem) predictHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.Write([]byte(errors.New("post method only").Error()))
		return
	}
	r.ParseMultipartForm(32 << 20)
	var buf bytes.Buffer
	file, header, err := r.FormFile("image")
	if err != nil {
		w.Write([]byte(err.Error()))
		return
	}
	defer file.Close()
	ext := strings.ToLower(path.Ext(header.Filename))
	if ext != ".jpg" && ext != ".png" {
		w.Write([]byte(errors.New("only support image endswith jpg/png").Error()))
		return
	}

	io.Copy(&buf, file)
	img, err2 := gocv.IMDecode(buf.Bytes(), gocv.IMReadColor)
	defer img.Close()
	if err2 != nil {
		w.Write([]byte(err2.Error()))
		return
	}
	result := ocr.PredictOneImage(img)
	if output, err3 := json.Marshal(result); err3 != nil {
		w.Write([]byte(err3.Error()))
	} else {
		w.Write(output)
	}
}

func (ocr *OCRSystem) PredictOneImage(img gocv.Mat) []OCRText {
	return ocr.tps.Run(img)
}

func (ocr *OCRSystem) PredictDirImages(dirname string) map[string][]OCRText {
	if dirname == "" {
		return nil
	}

	imgs, _ := filepath.Glob(dirname + "/*.jpg")
	tmpimgs, _ := filepath.Glob(dirname + "/*.png")
	imgs = append(imgs, tmpimgs...)
	results := make(map[string][]OCRText, len(imgs))
	for i := 0; i < len(imgs); i++ {
		imgname := imgs[i]
		img := ReadImage(imgname)
		defer img.Close()
		res := ocr.PredictOneImage(img)
		results[imgname] = res
	}
	return results
}


<|start_filename|>deploy/android_demo/app/src/main/cpp/native.cpp<|end_filename|>
//
// Created by fujiayi on 2020/7/5.
//

#include "native.h"
#include "ocr_ppredictor.h"
#include <algorithm>
#include <paddle_api.h>
#include <string>

static paddle::lite_api::PowerMode str_to_cpu_mode(const std::string &cpu_mode);

extern "C" JNIEXPORT jlong JNICALL
Java_com_baidu_paddle_lite_demo_ocr_OCRPredictorNative_init(
    JNIEnv *env, jobject thiz, jstring j_det_model_path,
    jstring j_rec_model_path, jstring j_cls_model_path, jint j_thread_num,
    jstring j_cpu_mode) {
  std::string det_model_path = jstring_to_cpp_string(env, j_det_model_path);
  std::string rec_model_path = jstring_to_cpp_string(env, j_rec_model_path);
  std::string cls_model_path = jstring_to_cpp_string(env, j_cls_model_path);
  int thread_num = j_thread_num;
  std::string cpu_mode = jstring_to_cpp_string(env, j_cpu_mode);
  ppredictor::OCR_Config conf;
  conf.thread_num = thread_num;
  conf.mode = str_to_cpu_mode(cpu_mode);
  ppredictor::OCR_PPredictor *orc_predictor =
      new ppredictor::OCR_PPredictor{conf};
  orc_predictor->init_from_file(det_model_path, rec_model_path, cls_model_path);
  return reinterpret_cast<jlong>(orc_predictor);
}

/**
 * "LITE_POWER_HIGH" convert to paddle::lite_api::LITE_POWER_HIGH
 * @param cpu_mode
 * @return
 */
static paddle::lite_api::PowerMode
str_to_cpu_mode(const std::string &cpu_mode) {
  static std::map<std::string, paddle::lite_api::PowerMode> cpu_mode_map{
      {"LITE_POWER_HIGH", paddle::lite_api::LITE_POWER_HIGH},
      {"LITE_POWER_LOW", paddle::lite_api::LITE_POWER_HIGH},
      {"LITE_POWER_FULL", paddle::lite_api::LITE_POWER_FULL},
      {"LITE_POWER_NO_BIND", paddle::lite_api::LITE_POWER_NO_BIND},
      {"LITE_POWER_RAND_HIGH", paddle::lite_api::LITE_POWER_RAND_HIGH},
      {"LITE_POWER_RAND_LOW", paddle::lite_api::LITE_POWER_RAND_LOW}};
  std::string upper_key;
  std::transform(cpu_mode.cbegin(), cpu_mode.cend(), upper_key.begin(),
                 ::toupper);
  auto index = cpu_mode_map.find(upper_key);
  if (index == cpu_mode_map.end()) {
    LOGE("cpu_mode not found %s", upper_key.c_str());
    return paddle::lite_api::LITE_POWER_HIGH;
  } else {
    return index->second;
  }
}

extern "C" JNIEXPORT jfloatArray JNICALL
Java_com_baidu_paddle_lite_demo_ocr_OCRPredictorNative_forward(
    JNIEnv *env, jobject thiz, jlong java_pointer, jfloatArray buf,
    jfloatArray ddims, jobject original_image) {
  LOGI("begin to run native forward");
  if (java_pointer == 0) {
    LOGE("JAVA pointer is NULL");
    return cpp_array_to_jfloatarray(env, nullptr, 0);
  }
  cv::Mat origin = bitmap_to_cv_mat(env, original_image);
  if (origin.size == 0) {
    LOGE("origin bitmap cannot convert to CV Mat");
    return cpp_array_to_jfloatarray(env, nullptr, 0);
  }
  ppredictor::OCR_PPredictor *ppredictor =
      (ppredictor::OCR_PPredictor *)java_pointer;
  std::vector<float> dims_float_arr = jfloatarray_to_float_vector(env, ddims);
  std::vector<int64_t> dims_arr;
  dims_arr.resize(dims_float_arr.size());
  std::copy(dims_float_arr.cbegin(), dims_float_arr.cend(), dims_arr.begin());

  // 这里值有点大，就不调用jfloatarray_to_float_vector了
  int64_t buf_len = (int64_t)env->GetArrayLength(buf);
  jfloat *buf_data = env->GetFloatArrayElements(buf, JNI_FALSE);
  float *data = (jfloat *)buf_data;
  std::vector<ppredictor::OCRPredictResult> results =
      ppredictor->infer_ocr(dims_arr, data, buf_len, NET_OCR, origin);
  LOGI("infer_ocr finished with boxes %ld", results.size());
  // 这里将std::vector<ppredictor::OCRPredictResult> 序列化成
  // float数组，传输到java层再反序列化
  std::vector<float> float_arr;
  for (const ppredictor::OCRPredictResult &r : results) {
    float_arr.push_back(r.points.size());
    float_arr.push_back(r.word_index.size());
    float_arr.push_back(r.score);
    for (const std::vector<int> &point : r.points) {
      float_arr.push_back(point.at(0));
      float_arr.push_back(point.at(1));
    }
    for (int index : r.word_index) {
      float_arr.push_back(index);
    }
  }
  return cpp_array_to_jfloatarray(env, float_arr.data(), float_arr.size());
}

extern "C" JNIEXPORT void JNICALL
Java_com_baidu_paddle_lite_demo_ocr_OCRPredictorNative_release(
    JNIEnv *env, jobject thiz, jlong java_pointer) {
  if (java_pointer == 0) {
    LOGE("JAVA pointer is NULL");
    return;
  }
  ppredictor::OCR_PPredictor *ppredictor =
      (ppredictor::OCR_PPredictor *)java_pointer;
  delete ppredictor;
}

<|start_filename|>ppocr/postprocess/lanms/include/pybind11/stl.h<|end_filename|>
/*
    pybind11/stl.h: Transparent conversion for STL data types

    Copyright (c) 2016 <NAME> <<EMAIL>>

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

#pragma once

#include "pybind11.h"
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <iostream>
#include <list>
#include <valarray>

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
#endif

#ifdef __has_include
// std::optional (but including it in c++14 mode isn't allowed)
#  if defined(PYBIND11_CPP17) && __has_include(<optional>)
#    include <optional>
#    define PYBIND11_HAS_OPTIONAL 1
#  endif
// std::experimental::optional (but not allowed in c++11 mode)
#  if defined(PYBIND11_CPP14) && __has_include(<experimental/optional>)
#    include <experimental/optional>
#    define PYBIND11_HAS_EXP_OPTIONAL 1
#  endif
// std::variant
#  if defined(PYBIND11_CPP17) && __has_include(<variant>)
#    include <variant>
#    define PYBIND11_HAS_VARIANT 1
#  endif
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
#  include <optional>
#  include <variant>
#  define PYBIND11_HAS_OPTIONAL 1
#  define PYBIND11_HAS_VARIANT 1
#endif

NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)

/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
/// forwarding a container element).  Typically used indirect via forwarded_type(), below.
template <typename T, typename U>
using forwarded_type = conditional_t<
    std::is_lvalue_reference<T>::value, remove_reference_t<U> &, remove_reference_t<U> &&>;

/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
/// used for forwarding a container's elements.
template <typename T, typename U>
forwarded_type<T, U> forward_like(U &&u) {
    return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
}

template <typename Type, typename Key> struct set_caster {
    using type = Type;
    using key_conv = make_caster<Key>;

    bool load(handle src, bool convert) {
        if (!isinstance<pybind11::set>(src))
            return false;
        auto s = reinterpret_borrow<pybind11::set>(src);
        value.clear();
        for (auto entry : s) {
            key_conv conv;
            if (!conv.load(entry, convert))
                return false;
            value.insert(cast_op<Key &&>(std::move(conv)));
        }
        return true;
    }

    template <typename T>
    static handle cast(T &&src, return_value_policy policy, handle parent) {
        pybind11::set s;
        for (auto &value: src) {
            auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
            if (!value_ || !s.add(value_))
                return handle();
        }
        return s.release();
    }

    PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]"));
};

template <typename Type, typename Key, typename Value> struct map_caster {
    using key_conv   = make_caster<Key>;
    using value_conv = make_caster<Value>;

    bool load(handle src, bool convert) {
        if (!isinstance<dict>(src))
            return false;
        auto d = reinterpret_borrow<dict>(src);
        value.clear();
        for (auto it : d) {
            key_conv kconv;
            value_conv vconv;
            if (!kconv.load(it.first.ptr(), convert) ||
                !vconv.load(it.second.ptr(), convert))
                return false;
            value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
        }
        return true;
    }

    template <typename T>
    static handle cast(T &&src, return_value_policy policy, handle parent) {
        dict d;
        for (auto &kv: src) {
            auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy, parent));
            auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy, parent));
            if (!key || !value)
                return handle();
            d[key] = value;
        }
        return d.release();
    }

    PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]"));
};

template <typename Type, typename Value> struct list_caster {
    using value_conv = make_caster<Value>;

    bool load(handle src, bool convert) {
        if (!isinstance<sequence>(src))
            return false;
        auto s = reinterpret_borrow<sequence>(src);
        value.clear();
        reserve_maybe(s, &value);
        for (auto it : s) {
            value_conv conv;
            if (!conv.load(it, convert))
                return false;
            value.push_back(cast_op<Value &&>(std::move(conv)));
        }
        return true;
    }

private:
    template <typename T = Type,
              enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
    void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); }
    void reserve_maybe(sequence, void *) { }

public:
    template <typename T>
    static handle cast(T &&src, return_value_policy policy, handle parent) {
        list l(src.size());
        size_t index = 0;
        for (auto &value: src) {
            auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
            if (!value_)
                return handle();
            PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
        }
        return l.release();
    }

    PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]"));
};

template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
 : list_caster<std::vector<Type, Alloc>, Type> { };

template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
 : list_caster<std::list<Type, Alloc>, Type> { };

template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> struct array_caster {
    using value_conv = make_caster<Value>;

private:
    template <bool R = Resizable>
    bool require_size(enable_if_t<R, size_t> size) {
        if (value.size() != size)
            value.resize(size);
        return true;
    }
    template <bool R = Resizable>
    bool require_size(enable_if_t<!R, size_t> size) {
        return size == Size;
    }

public:
    bool load(handle src, bool convert) {
        if (!isinstance<list>(src))
            return false;
        auto l = reinterpret_borrow<list>(src);
        if (!require_size(l.size()))
            return false;
        size_t ctr = 0;
        for (auto it : l) {
            value_conv conv;
            if (!conv.load(it, convert))
                return false;
            value[ctr++] = cast_op<Value &&>(std::move(conv));
        }
        return true;
    }

    template <typename T>
    static handle cast(T &&src, return_value_policy policy, handle parent) {
        list l(src.size());
        size_t index = 0;
        for (auto &value: src) {
            auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
            if (!value_)
                return handle();
            PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
        }
        return l.release();
    }

    PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name() + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
};

template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
 : array_caster<std::array<Type, Size>, Type, false, Size> { };

template <typename Type> struct type_caster<std::valarray<Type>>
 : array_caster<std::valarray<Type>, Type, true> { };

template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
  : set_caster<std::set<Key, Compare, Alloc>, Key> { };

template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
  : set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };

template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
  : map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };

template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
  : map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };

// This type caster is intended to be used for std::optional and std::experimental::optional
template<typename T> struct optional_caster {
    using value_conv = make_caster<typename T::value_type>;

    template <typename T_>
    static handle cast(T_ &&src, return_value_policy policy, handle parent) {
        if (!src)
            return none().inc_ref();
        return value_conv::cast(*std::forward<T_>(src), policy, parent);
    }

    bool load(handle src, bool convert) {
        if (!src) {
            return false;
        } else if (src.is_none()) {
            return true;  // default-constructed value is already empty
        }
        value_conv inner_caster;
        if (!inner_caster.load(src, convert))
            return false;

        value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
        return true;
    }

    PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]"));
};

#if PYBIND11_HAS_OPTIONAL
template<typename T> struct type_caster<std::optional<T>>
    : public optional_caster<std::optional<T>> {};

template<> struct type_caster<std::nullopt_t>
    : public void_caster<std::nullopt_t> {};
#endif

#if PYBIND11_HAS_EXP_OPTIONAL
template<typename T> struct type_caster<std::experimental::optional<T>>
    : public optional_caster<std::experimental::optional<T>> {};

template<> struct type_caster<std::experimental::nullopt_t>
    : public void_caster<std::experimental::nullopt_t> {};
#endif

/// Visit a variant and cast any found type to Python
struct variant_caster_visitor {
    return_value_policy policy;
    handle parent;

    template <typename T>
    handle operator()(T &&src) const {
        return make_caster<T>::cast(std::forward<T>(src), policy, parent);
    }
};

/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
/// automatically using argument-dependent lookup. Users can provide specializations for other
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
template <template<typename...> class Variant>
struct visit_helper {
    template <typename... Args>
    static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
        return visit(std::forward<Args>(args)...);
    }
};

/// Generic variant caster
template <typename Variant> struct variant_caster;

template <template<typename...> class V, typename... Ts>
struct variant_caster<V<Ts...>> {
    static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");

    template <typename U, typename... Us>
    bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
        auto caster = make_caster<U>();
        if (caster.load(src, convert)) {
            value = cast_op<U>(caster);
            return true;
        }
        return load_alternative(src, convert, type_list<Us...>{});
    }

    bool load_alternative(handle, bool, type_list<>) { return false; }

    bool load(handle src, bool convert) {
        // Do a first pass without conversions to improve constructor resolution.
        // E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
        // slot of the variant. Without two-pass loading `double` would be filled
        // because it appears first and a conversion is possible.
        if (convert && load_alternative(src, false, type_list<Ts...>{}))
            return true;
        return load_alternative(src, convert, type_list<Ts...>{});
    }

    template <typename Variant>
    static handle cast(Variant &&src, return_value_policy policy, handle parent) {
        return visit_helper<V>::call(variant_caster_visitor{policy, parent},
                                     std::forward<Variant>(src));
    }

    using Type = V<Ts...>;
    PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name()...) + _("]"));
};

#if PYBIND11_HAS_VARIANT
template <typename... Ts>
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
#endif
NAMESPACE_END(detail)

inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
    os << (std::string) str(obj);
    return os;
}

NAMESPACE_END(pybind11)

#if defined(_MSC_VER)
#pragma warning(pop)
#endif


<|start_filename|>thirdparty/paddleocr-go/ocr/preprocess.go<|end_filename|>
package ocr

import (
	"image"
	"image/color"
	"math"

	"github.com/LKKlein/gocv"
)

func resizeByShape(img gocv.Mat, resizeShape []int) (gocv.Mat, int, int) {
	resizeH := resizeShape[0]
	resizeW := resizeShape[1]
	gocv.Resize(img, &img, image.Pt(resizeW, resizeH), 0, 0, gocv.InterpolationLinear)
	return img, resizeH, resizeW
}

func resizeByMaxLen(img gocv.Mat, maxLen int) (gocv.Mat, int, int) {
	oriH := img.Rows()
	oriW := img.Cols()
	var resizeH, resizeW int = oriH, oriW

	var ratio float64 = 1.0
	if resizeH > maxLen || resizeW > maxLen {
		if resizeH > resizeW {
			ratio = float64(maxLen) / float64(resizeH)
		} else {
			ratio = float64(maxLen) / float64(resizeW)
		}
	}

	resizeH = int(float64(resizeH) * ratio)
	resizeW = int(float64(resizeW) * ratio)

	if resizeH%32 == 0 {
		resizeH = resizeH
	} else if resizeH/32 <= 1 {
		resizeH = 32
	} else {
		resizeH = (resizeH/32 - 1) * 32
	}

	if resizeW%32 == 0 {
		resizeW = resizeW
	} else if resizeW/32 <= 1 {
		resizeW = 32
	} else {
		resizeW = (resizeW/32 - 1) * 32
	}

	if resizeW <= 0 || resizeH <= 0 {
		return gocv.NewMat(), 0, 0
	}

	gocv.Resize(img, &img, image.Pt(resizeW, resizeH), 0, 0, gocv.InterpolationLinear)
	return img, resizeH, resizeW
}

func normPermute(img gocv.Mat, mean []float32, std []float32, scaleFactor float32) []float32 {
	img.ConvertTo(&img, gocv.MatTypeCV32F)
	img.DivideFloat(scaleFactor)

	c := gocv.Split(img)
	data := make([]float32, img.Rows()*img.Cols()*img.Channels())
	for i := 0; i < 3; i++ {
		c[i].SubtractFloat(mean[i])
		c[i].DivideFloat(std[i])
		defer c[i].Close()
		x, _ := c[i].DataPtrFloat32()
		copy(data[i*img.Rows()*img.Cols():], x)
	}
	return data
}

type DetPreProcess interface {
	Run(gocv.Mat) ([]float32, int, int)
}

type DBPreProcess struct {
	resizeType  int
	imageShape  []int
	maxSideLen  int
	mean        []float32
	std         []float32
	scaleFactor float32
}

func NewDBProcess(shape []int, sideLen int) *DBPreProcess {
	db := &DBPreProcess{
		resizeType:  0,
		imageShape:  shape,
		maxSideLen:  sideLen,
		mean:        []float32{0.485, 0.456, 0.406},
		std:         []float32{0.229, 0.224, 0.225},
		scaleFactor: 255.0,
	}
	if len(shape) > 0 {
		db.resizeType = 1
	}
	if sideLen == 0 {
		db.maxSideLen = 2400
	}
	return db
}

func (d *DBPreProcess) Run(img gocv.Mat) ([]float32, int, int) {
	var resizeH, resizeW int
	if d.resizeType == 0 {
		img, resizeH, resizeW = resizeByMaxLen(img, d.maxSideLen)
	} else {
		img, resizeH, resizeW = resizeByShape(img, d.imageShape)
	}

	im := normPermute(img, d.mean, d.std, d.scaleFactor)
	return im, resizeH, resizeW
}

func clsResize(img gocv.Mat, resizeShape []int) gocv.Mat {
	imgH, imgW := resizeShape[1], resizeShape[2]
	h, w := img.Rows(), img.Cols()
	ratio := float64(w) / float64(h)
	var resizeW int
	if math.Ceil(float64(imgH)*ratio) > float64(imgW) {
		resizeW = imgW
	} else {
		resizeW = int(math.Ceil(float64(imgH) * ratio))
	}
	gocv.Resize(img, &img, image.Pt(resizeW, imgH), 0, 0, gocv.InterpolationLinear)
	if resizeW < imgW {
		gocv.CopyMakeBorder(img, &img, 0, 0, 0, imgW-resizeW, gocv.BorderConstant, color.RGBA{0, 0, 0, 0})
	}
	return img
}

func crnnPreprocess(img gocv.Mat, resizeShape []int, mean []float32, std []float32,
	scaleFactor float32, whRatio float64, charType string) []float32 {
	imgH := resizeShape[1]
	imgW := resizeShape[2]
	if charType == "ch" {
		imgW = int(32 * whRatio)
	}
	h, w := img.Rows(), img.Cols()
	ratio := float64(w) / float64(h)
	var resizeW int
	if math.Ceil(float64(imgH)*ratio) > float64(imgW) {
		resizeW = imgW
	} else {
		resizeW = int(math.Ceil(float64(imgH) * ratio))
	}
	gocv.Resize(img, &img, image.Pt(resizeW, imgH), 0, 0, gocv.InterpolationLinear)

	img.ConvertTo(&img, gocv.MatTypeCV32F)
	img.DivideFloat(scaleFactor)
	img.SubtractScalar(gocv.NewScalar(float64(mean[0]), float64(mean[1]), float64(mean[2]), 0))
	img.DivideScalar(gocv.NewScalar(float64(std[0]), float64(std[1]), float64(std[2]), 0))

	if resizeW < imgW {
		gocv.CopyMakeBorder(img, &img, 0, 0, 0, imgW-resizeW, gocv.BorderConstant, color.RGBA{0, 0, 0, 0})
	}

	c := gocv.Split(img)
	data := make([]float32, img.Rows()*img.Cols()*img.Channels())
	for i := 0; i < 3; i++ {
		defer c[i].Close()
		x, _ := c[i].DataPtrFloat32()
		copy(data[i*img.Rows()*img.Cols():], x)
	}
	return data
}


<|start_filename|>thirdparty/paddleocr-go/ocr/ocr_cls.go<|end_filename|>
package ocr

import (
	"log"
	"os"
	"time"

	"github.com/LKKlein/gocv"
)

type TextClassifier struct {
	*PaddleModel
	batchNum int
	thresh   float64
	shape    []int
	labels   []string
}

type ClsResult struct {
	Score float32
	Label int64
}

func NewTextClassifier(modelDir string, args map[string]interface{}) *TextClassifier {
	shapes := []int{3, 48, 192}
	if v, ok := args["cls_image_shape"]; ok {
		for i, s := range v.([]interface{}) {
			shapes[i] = s.(int)
		}
	}
	cls := &TextClassifier{
		PaddleModel: NewPaddleModel(args),
		batchNum:    getInt(args, "cls_batch_num", 30),
		thresh:      getFloat64(args, "cls_thresh", 0.9),
		shape:       shapes,
	}
	if checkModelExists(modelDir) {
		home, _ := os.UserHomeDir()
		modelDir, _ = downloadModel(home+"/.paddleocr/cls", modelDir)
	} else {
		log.Panicf("cls model path: %v not exist! Please check!", modelDir)
	}
	cls.LoadModel(modelDir)
	return cls
}

func (cls *TextClassifier) Run(imgs []gocv.Mat) []gocv.Mat {
	batch := cls.batchNum
	var clsTime int64 = 0
	clsout := make([]ClsResult, len(imgs))
	srcimgs := make([]gocv.Mat, len(imgs))
	c, h, w := cls.shape[0], cls.shape[1], cls.shape[2]
	for i := 0; i < len(imgs); i += batch {
		j := i + batch
		if len(imgs) < j {
			j = len(imgs)
		}

		normImgs := make([]float32, (j-i)*c*h*w)
		for k := i; k < j; k++ {
			tmp := gocv.NewMat()
			imgs[k].CopyTo(&tmp)
			srcimgs[k] = tmp
			img := clsResize(imgs[k], cls.shape)
			data := normPermute(img, []float32{0.5, 0.5, 0.5}, []float32{0.5, 0.5, 0.5}, 255.0)
			copy(normImgs[(k-i)*c*h*w:], data)
		}

		st := time.Now()
		cls.input.SetValue(normImgs)
		cls.input.Reshape([]int32{int32(j - i), int32(c), int32(h), int32(w)})

		cls.predictor.SetZeroCopyInput(cls.input)
		cls.predictor.ZeroCopyRun()
		cls.predictor.GetZeroCopyOutput(cls.outputs[0])
		cls.predictor.GetZeroCopyOutput(cls.outputs[1])

		var probout [][]float32
		var labelout []int64
		if len(cls.outputs[0].Shape()) == 2 {
			probout = cls.outputs[0].Value().([][]float32)
		} else {
			labelout = cls.outputs[0].Value().([]int64)
		}

		if len(cls.outputs[1].Shape()) == 2 {
			probout = cls.outputs[1].Value().([][]float32)
		} else {
			labelout = cls.outputs[1].Value().([]int64)
		}
		clsTime += int64(time.Since(st).Milliseconds())

		for no, label := range labelout {
			score := probout[no][label]
			clsout[i+no] = ClsResult{
				Score: score,
				Label: label,
			}

			if label%2 == 1 && float64(score) > cls.thresh {
				gocv.Rotate(srcimgs[i+no], &srcimgs[i+no], gocv.Rotate180Clockwise)
			}
		}
	}
	log.Println("cls num: ", len(clsout), ", cls time elapse: ", clsTime, "ms")
	return srcimgs
}


<|start_filename|>thirdparty/paddleocr-go/ocr/ocr_rec.go<|end_filename|>
package ocr

import (
	"log"
	"os"
	"time"

	"github.com/LKKlein/gocv"
)

type TextRecognizer struct {
	*PaddleModel
	batchNum int
	textLen  int
	shape    []int
	charType string
	labels   []string
}

func NewTextRecognizer(modelDir string, args map[string]interface{}) *TextRecognizer {
	shapes := []int{3, 32, 320}
	if v, ok := args["rec_image_shape"]; ok {
		for i, s := range v.([]interface{}) {
			shapes[i] = s.(int)
		}
	}
	home, _ := os.UserHomeDir()
	labelpath := getString(args, "rec_char_dict_path", home+"/.paddleocr/rec/ppocr_keys_v1.txt")
	labels := readLines2StringSlice(labelpath)
	if getBool(args, "use_space_char", true) {
		labels = append(labels, " ")
	}
	rec := &TextRecognizer{
		PaddleModel: NewPaddleModel(args),
		batchNum:    getInt(args, "rec_batch_num", 30),
		textLen:     getInt(args, "max_text_length", 25),
		charType:    getString(args, "rec_char_type", "ch"),
		shape:       shapes,
		labels:      labels,
	}
	if checkModelExists(modelDir) {
		modelDir, _ = downloadModel(home+"/.paddleocr/rec/ch", modelDir)
	} else {
		log.Panicf("rec model path: %v not exist! Please check!", modelDir)
	}
	rec.LoadModel(modelDir)
	return rec
}

func (rec *TextRecognizer) Run(imgs []gocv.Mat, bboxes [][][]int) []OCRText {
	recResult := make([]OCRText, 0, len(imgs))
	batch := rec.batchNum
	var recTime int64 = 0
	c, h, w := rec.shape[0], rec.shape[1], rec.shape[2]
	for i := 0; i < len(imgs); i += batch {
		j := i + batch
		if len(imgs) < j {
			j = len(imgs)
		}

		maxwhratio := 0.0
		for k := i; k < j; k++ {
			h, w := imgs[k].Rows(), imgs[k].Cols()
			ratio := float64(w) / float64(h)
			if ratio > maxwhratio {
				maxwhratio = ratio
			}
		}

		if rec.charType == "ch" {
			w = int(32 * maxwhratio)
		}
		normimgs := make([]float32, (j-i)*c*h*w)

		for k := i; k < j; k++ {
			data := crnnPreprocess(imgs[k], rec.shape, []float32{0.5, 0.5, 0.5},
				[]float32{0.5, 0.5, 0.5}, 255.0, maxwhratio, rec.charType)
			defer imgs[k].Close()
			copy(normimgs[(k-i)*c*h*w:], data)
		}

		st := time.Now()
		rec.input.SetValue(normimgs)
		rec.input.Reshape([]int32{int32(j - i), int32(c), int32(h), int32(w)})

		rec.predictor.SetZeroCopyInput(rec.input)
		rec.predictor.ZeroCopyRun()
		rec.predictor.GetZeroCopyOutput(rec.outputs[0])
		rec.predictor.GetZeroCopyOutput(rec.outputs[1])

		recIdxBatch := rec.outputs[0].Value().([][]int64)
		recIdxLod := rec.outputs[0].Lod()

		predictBatch := rec.outputs[1].Value().([][]float32)
		predictLod := rec.outputs[1].Lod()
		recTime += int64(time.Since(st).Milliseconds())

		for rno := 0; rno < len(recIdxLod)-1; rno++ {
			predIdx := make([]int, 0, 2)
			for beg := recIdxLod[rno]; beg < recIdxLod[rno+1]; beg++ {
				predIdx = append(predIdx, int(recIdxBatch[beg][0]))
			}
			if len(predIdx) == 0 {
				continue
			}
			words := ""
			for n := 0; n < len(predIdx); n++ {
				words += rec.labels[predIdx[n]]
			}

			score := 0.0
			count := 0
			blankPosition := int(rec.outputs[1].Shape()[1])
			for beg := predictLod[rno]; beg < predictLod[rno+1]; beg++ {
				argMaxID, maxVal := argmax(predictBatch[beg])
				if blankPosition-1-argMaxID > 0 {
					score += float64(maxVal)
					count++
				}
			}
			score = score / float64(count)
			recResult = append(recResult, OCRText{
				BBox:  bboxes[i+rno],
				Text:  words,
				Score: score,
			})
		}
	}
	log.Println("rec num: ", len(recResult), ", rec time elapse: ", recTime, "ms")
	return recResult
}


<|start_filename|>deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OcrResultModel.java<|end_filename|>
package com.baidu.paddle.lite.demo.ocr;

import android.graphics.Point;

import java.util.ArrayList;
import java.util.List;

public class OcrResultModel {
    private List<Point> points;
    private List<Integer> wordIndex;
    private String label;
    private float confidence;

    public OcrResultModel() {
        super();
        points = new ArrayList<>();
        wordIndex = new ArrayList<>();
    }

    public void addPoints(int x, int y) {
        Point point = new Point(x, y);
        points.add(point);
    }

    public void addWordIndex(int index) {
        wordIndex.add(index);
    }

    public List<Point> getPoints() {
        return points;
    }

    public List<Integer> getWordIndex() {
        return wordIndex;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public float getConfidence() {
        return confidence;
    }

    public void setConfidence(float confidence) {
        this.confidence = confidence;
    }
}


<|start_filename|>deploy/ios_demo/ocr_demo/Helpers.h<|end_filename|>
//
//  Helpers.h
//  EasyDLDemo
//
//  Created by chenxiaoyu on 2018/5/14.
//  Copyright © 2018年 baidu. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIImage.h>

#define UIColorFromRGB(rgbValue) \
[UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0x00FF00) >>  8))/255.0 \
blue:((float)((rgbValue & 0x0000FF) >>  0))/255.0 \
alpha:1.0]

#define SCREEN_HEIGHT  [UIScreen mainScreen].bounds.size.height
#define SCREEN_WIDTH  [UIScreen mainScreen].bounds.size.width

#define HIGHLIGHT_COLOR UIColorFromRGB(0xF5A623)

//#define BTN_HIGHTLIGH_TEXT_COLOR UIColorFromRGB(0xF5A623)


@interface Helpers : NSObject {


}

@end


<|start_filename|>deploy/lite/crnn_process.h<|end_filename|>
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

#include "math.h" //NOLINT
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"

cv::Mat CrnnResizeImg(cv::Mat img, float wh_ratio);

std::vector<std::string> ReadDict(std::string path);

cv::Mat GetRotateCropImage(cv::Mat srcimage, std::vector<std::vector<int>> box);

template <class ForwardIterator>
inline size_t Argmax(ForwardIterator first, ForwardIterator last) {
  return std::distance(first, std::max_element(first, last));
}


<|start_filename|>thirdparty/paddleOcrSpringBoot/src/main/java/com/paddelocr_springboot/demo/Controller/OCR.java<|end_filename|>
package com.paddelocr_springboot.demo.Controller;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.json.JSONObject;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.*;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Encoder;
import java.util.Objects;

@RestController
public class OCR {
@RequestMapping("/")
    public ResponseEntity<String> hi(){
        //创建请求头
        HttpHeaders headers = new HttpHeaders();
        //设置请求头格式
        headers.setContentType(MediaType.APPLICATION_JSON);
        //读入静态资源文件1.png
        InputStream imagePath = this.getClass().getResourceAsStream("/1.png");
        //构建请求参数
        MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
        //添加请求参数images，并将Base64编码的图片传入
        map.add("images", ImageToBase64(imagePath));
        //构建请求
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
        RestTemplate restTemplate = new RestTemplate();
        //发送请求
        ResponseEntity<String> response = restTemplate.postForEntity("http://127.0.0.1:8866/predict/ocr_system", request, String.class);
        //打印请求返回值
        return response;
    }
    private String ImageToBase64(InputStream imgPath) {
        byte[] data = null;
        // 读取图片字节数组
        try {
            InputStream in = imgPath;
            System.out.println(imgPath);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();
        // 返回Base64编码过的字节数组字符串
        //System.out.println("图片转换Base64:" + encoder.encode(Objects.requireNonNull(data)));
        return encoder.encode(Objects.requireNonNull(data));
    }

}


<|start_filename|>thirdparty/paddleocr-go/ocr/ocr_det.go<|end_filename|>
package ocr

import (
	"log"
	"os"
	"time"

	"github.com/LKKlein/gocv"
)

type DBDetector struct {
	*PaddleModel
	preProcess  DetPreProcess
	postProcess DetPostProcess
}

func NewDBDetector(modelDir string, args map[string]interface{}) *DBDetector {
	maxSideLen := getInt(args, "det_max_side_len", 960)
	thresh := getFloat64(args, "det_db_thresh", 0.3)
	boxThresh := getFloat64(args, "det_db_box_thresh", 0.5)
	unClipRatio := getFloat64(args, "det_db_unclip_ratio", 2.0)

	detector := &DBDetector{
		PaddleModel: NewPaddleModel(args),
		preProcess:  NewDBProcess(make([]int, 0), maxSideLen),
		postProcess: NewDBPostProcess(thresh, boxThresh, unClipRatio),
	}
	if checkModelExists(modelDir) {
		home, _ := os.UserHomeDir()
		modelDir, _ = downloadModel(home+"/.paddleocr/det", modelDir)
	} else {
		log.Panicf("det model path: %v not exist! Please check!", modelDir)
	}
	detector.LoadModel(modelDir)
	return detector
}

func (det *DBDetector) Run(img gocv.Mat) [][][]int {
	oriH := img.Rows()
	oriW := img.Cols()
	data, resizeH, resizeW := det.preProcess.Run(img)
	st := time.Now()
	det.input.SetValue(data)
	det.input.Reshape([]int32{1, 3, int32(resizeH), int32(resizeW)})

	det.predictor.SetZeroCopyInput(det.input)
	det.predictor.ZeroCopyRun()
	det.predictor.GetZeroCopyOutput(det.outputs[0])

	ratioH, ratioW := float64(resizeH)/float64(oriH), float64(resizeW)/float64(oriW)
	boxes := det.postProcess.Run(det.outputs[0], oriH, oriW, ratioH, ratioW)
	log.Println("det_box num: ", len(boxes), ", time elapse: ", time.Since(st))
	return boxes
}


<|start_filename|>deploy/android_demo/app/src/main/cpp/predictor_output.cpp<|end_filename|>
#include "predictor_output.h"
namespace ppredictor {
const float* PredictorOutput::get_float_data() const{
    return _tensor->data<float>();
}

const int* PredictorOutput::get_int_data() const{
    return _tensor->data<int>();
}

const std::vector<std::vector<uint64_t>> PredictorOutput::get_lod() const{
    return _tensor->lod();
}

int64_t PredictorOutput::get_size() const{
    if (_net_flag == NET_OCR) {
        return _tensor->shape().at(2) *  _tensor->shape().at(3);
    } else {
        return  product(_tensor->shape());
    }
}

const std::vector<int64_t> PredictorOutput::get_shape()  const{
    return _tensor->shape();

}
}

<|start_filename|>deploy/ios_demo/ocr_demo/BoxLayer.h<|end_filename|>
//
// Created by chenxiaoyu on 2018/5/5.
// Copyright (c) 2018 baidu. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "OcrData.h"


@interface BoxLayer : CAShapeLayer

/**
 * 绘制OCR的结果
 */
-(void) renderOcrPolygon: (OcrData *)data withHeight:(CGFloat)originHeight withWidth:(CGFloat)originWidth withLabel:(bool) withLabel;



@end


<|start_filename|>deploy/android_demo/app/src/main/cpp/predictor_input.h<|end_filename|>
#pragma once

#include <paddle_api.h>
#include <vector>
#include "common.h"

namespace ppredictor {
class PredictorInput {
public:
    PredictorInput(std::unique_ptr<paddle::lite_api::Tensor> &&tensor, int index, int net_flag) :
        _tensor(std::move(tensor)), _index(index),_net_flag(net_flag) {

    }


    void set_dims(std::vector<int64_t> dims);

    float *get_mutable_float_data();

    void set_data(const float *input_data, int input_float_len);

private:
    std::unique_ptr<paddle::lite_api::Tensor> _tensor;
    bool _is_dims_set = false;
    int _index;
    int _net_flag;
};
}


<|start_filename|>thirdparty/paddleocr-go/ocr/default_args.go<|end_filename|>
package ocr

var (
	defaultArgs = map[string]interface{}{
		"use_gpu":         true,
		"ir_optim":        true,
		"enable_mkldnn":   false,
		"use_tensorrt":    false,
		"num_cpu_threads": 6,
		"gpu_id":          0,
		"gpu_mem":         2000,

		"det_algorithm":    "DB",
		"det_model_dir":    "https://paddleocr.bj.bcebos.com/20-09-22/mobile/det/ch_ppocr_mobile_v1.1_det_infer.tar",
		"det_max_side_len": 960,

		"det_db_thresh":       0.3,
		"det_db_box_thresh":   0.5,
		"det_db_unclip_ratio": 2.0,

		"det_east_score_thresh": 0.8,
		"det_east_cover_thresh": 0.1,
		"det_east_nms_thresh":   0.2,

		"rec_algorithm":      "CRNN",
		"rec_model_dir":      "https://paddleocr.bj.bcebos.com/20-09-22/mobile/rec/ch_ppocr_mobile_v1.1_rec_infer.tar",
		"rec_image_shape":    []interface{}{3, 32, 320},
		"rec_char_type":      "ch",
		"rec_batch_num":      30,
		"max_text_length":    25,
		"rec_char_dict_path": "https://raw.githubusercontent.com/PaddlePaddle/PaddleOCR/develop/ppocr/utils/ppocr_keys_v1.txt",
		"use_space_char":     true,

		"use_angle_cls":   false,
		"cls_model_dir":   "https://paddleocr.bj.bcebos.com/20-09-22/cls/ch_ppocr_mobile_v1.1_cls_infer.tar",
		"cls_image_shape": []interface{}{3, 48, 192},
		"label_list":      []interface{}{"0", "180"},
		"cls_batch_num":   30,
		"cls_thresh":      0.9,

		"lang": "ch",
		"det":  true,
		"rec":  true,
		"cls":  false,
	}
)
