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 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"; } } }