BaiduPlateRecognizer.java 3.71 KB
package com.ectrip.checkincar.plate;

import android.content.Context;
import android.graphics.Bitmap;
import android.text.TextUtils;

import com.baidu.vis.ocrgve.plate.OcrgveEnginePlate;
import com.baidu.vis.ocrgve.plate.OcrgvesdkResponsePlate;
import com.ectrip.checkincar.core.prefs.AppPrefs;
import com.ectrip.checkincar.license.LicenseManager;
import com.ectrip.checkincar.model.PlateInfo;

import java.util.ArrayList;

/** 百度车牌离线 SDK 封装。构造在后台线程完成(含授权+模型初始化)。 */
public class BaiduPlateRecognizer implements PlateRecognizer {

    private boolean ready;
    private String error = "未初始化";

    public BaiduPlateRecognizer(Context context) {
        ready = LicenseManager.get().ensureReady(context);
        if (!ready) {
            error = LicenseManager.get().getLastError();
        }
    }

    public String getError() {
        return error;
    }

    @Override
    public boolean isReady() {
        return ready;
    }

    @Override
    public PlateInfo recognize(Bitmap bitmap) {
        OcrgveEnginePlate engine = LicenseManager.get().getEngine();
        if (!ready || engine == null || bitmap == null) {
            return null;
        }
        try {
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            int[] pixels = new int[w * h];
            bitmap.getPixels(pixels, 0, w, 0, 0, w, h);
            byte[] rgba = new byte[w * h * 4];
            for (int i = 0; i < pixels.length; i++) {
                int c = pixels[i];
                rgba[i * 4] = (byte) ((c >> 16) & 0xFF); // R
                rgba[i * 4 + 1] = (byte) ((c >> 8) & 0xFF); // G
                rgba[i * 4 + 2] = (byte) (c & 0xFF); // B
                rgba[i * 4 + 3] = (byte) ((c >> 24) & 0xFF); // A
            }

            ArrayList<OcrgvesdkResponsePlate> results =
                    engine.processOcrgvesdk(rgba, OcrgveEnginePlate.PIX_RGBA, w, h, 0);
            if (results == null || results.isEmpty()) {
                return null;
            }
            float threshold = AppPrefs.getThreshold();
            OcrgvesdkResponsePlate best = null;
            float bestProb = 0f;
            for (OcrgvesdkResponsePlate r : results) {
                if (r == null || !"plate_number".equals(r.name) || TextUtils.isEmpty(r.mystring)) {
                    continue;
                }
                float p = minCharProb(r.recgProb);
                if (p >= threshold && p > bestProb) {
                    bestProb = p;
                    best = r;
                }
            }
            if (best == null) {
                return null;
            }
            return new PlateInfo(best.mystring.trim(), normalizeColor(best.color),
                    bestProb > 0 ? bestProb : best.detScore, false);
        } catch (Throwable t) {
            return null;
        }
    }

    @Override
    public void release() {
        // 引擎单例由 LicenseManager 统一持有,随进程存活,不在此释放
    }

    /** 字符置信度取最小值;recgProb 为空时退回检测分 */
    private static float minCharProb(float[] probs) {
        if (probs == null || probs.length == 0) {
            return 0f;
        }
        float min = 1f;
        for (float p : probs) {
            if (p < min) {
                min = p;
            }
        }
        return min;
    }

    private static String normalizeColor(String color) {
        if (color == null) {
            return "unknown";
        }
        switch (color) {
            case "blue":
            case "yellow":
            case "green":
            case "white":
            case "black":
                return color;
            default:
                return "unknown";
        }
    }
}