Introducing mica-ppocr: The First Java Native PP-OCR Library with Zero Python Dependency
The article presents mica-ppocr, a Java‑17 native implementation of PP‑OCRv6 that eliminates Python and Paddle dependencies, offers three model tiers, Spring Boot starter support, and detailed usage examples, enabling Java back‑ends to perform high‑quality OCR locally and compliantly.
Problem
Java back‑end developers often encounter three pain points when integrating OCR: (1) cloud services require data to leave the network, which may violate compliance; (2) existing Java libraries either have poor accuracy or depend on many native Python/Paddle components; (3) results from Python ports are difficult to reproduce, leading to inconsistent inference.
mica-ppocr
mica-ppocr is a pure Java 17 implementation of PP‑OCRv6 that runs on ONNX Runtime. It is a line‑by‑line, bit‑exact port of the reference Python implementation, reproducing preprocessing, post‑processing (DB post‑processing, CTC decoding, polygon unclip) and delivering identical results.
Key features
Zero Python dependency : Maven import pulls native OpenCV and ONNX Runtime libraries automatically; works on Windows, Linux and macOS out of the box.
Bit‑exact reproduction : Guarantees per‑bit consistency with the Python version.
Three model tiers : tiny, small and medium, covering lightweight to high‑accuracy scenarios.
Spring Boot starter : One‑line configuration for Spring Boot 3.x projects.
Core module without framework dependencies : Can be used in any Java project.
Apache 2.0 license : Commercial‑friendly.
Model tiers
tiny – 1.7 MB detection model, 4.3 MB recognition model, ~2855 characters; fast, low memory, suitable for mobile/embedded and real‑time video.
small – 9.4 MB + 20.2 MB, balanced speed and accuracy; default choice for general document recognition.
medium – 59.2 MB + 73.0 MB, ~7180 characters; highest accuracy for complex layouts and rare characters.
Quick start
Add the core dependency via Maven:
<dependency>
<groupId>net.dreamlu.mica.ai</groupId>
<artifactId>mica-ppocr-core</artifactId>
<version>${mica.ppocr.version}</version>
</dependency>Run the engine in a try‑with‑resources block:
import net.dreamlu.mica.ai.ppocr.config.PPOcrV6Config;
import net.dreamlu.mica.ai.ppocr.engine.PPOcrV6Engine;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import nu.pattern.OpenCV;
import java.util.List;
public class Demo {
public static void main(String[] args) {
OpenCV.loadShared();
Mat img = Imgcodecs.imread("test.png");
PPOcrV6Config config = PPOcrV6Config.builder()
.detModelPath("models/ppocr-v6/tiny/det.onnx")
.recModelPath("models/ppocr-v6/tiny/rec.onnx")
.recCharDictPath("models/ppocr-v6/tiny/dict.txt")
.build();
try (PPOcrV6Engine engine = new PPOcrV6Engine(config)) {
List<PPOcrV6Result> results = engine.run(img);
for (PPOcrV6Result r : results) {
System.out.printf("%s (%.3f)%n", r.text(), r.score());
}
}
}
}The engine defaults to single‑thread CPU (intraOp = interOp = 1). Inference parameters such as DB threshold, batch size, ONNX Runtime threads and GPU acceleration can be tuned via the PPOcrV6Config builder.
Spring Boot integration
Add the starter dependency:
<dependency>
<groupId>net.dreamlu.mica.ai</groupId>
<artifactId>mica-ppocr-spring-boot-starter</artifactId>
<version>${mica.ppocr.version}</version>
</dependency>Configure model paths in application.yml:
mica:
ai:
ppocr:
enabled: true
det-model-path: models/ppocr-v6/tiny/det.onnx
rec-model-path: models/ppocr-v6/tiny/rec.onnx
rec-char-dict-path: models/ppocr-v6/tiny/dict.txtInject the engine into a service:
@Service
public class OcrService {
private final PPOcrV6Engine engine;
public OcrService(PPOcrV6Engine engine) { this.engine = engine; }
public List<PPOcrV6Result> recognize(Mat image) { return engine.run(image); }
}The starter also provides a PPOCRPropertiesCustomizer SPI, allowing model tier overrides via environment variables (e.g., PPOCR_TIER) or configuration centers.
Architecture overview
The project is split into two modules:
mica-ppocr-core : core engine with no Spring dependency.
mica-ppocr-spring-boot-starter : Spring Boot auto‑configuration.
Key pipeline steps (detect → sort boxes → crop → recognize):
DetectionPreprocessor : resize, normalize, convert HWC to NCHW.
DbPostProcessor : extract contours from DB binary map to obtain text boxes.
BoxUtil : sort quadrilateral boxes in reading order.
CropUtil : perspective transform and crop; skips invalid crops.
RecognitionPreprocessor : batch resize and pad to uniform width.
CtcLabelDecoder : load character dictionary and perform greedy CTC decoding with confidence scores.
Implementation details
Bit‑exact mapping of Python libraries to Java equivalents ensures <1 px difference in unclip operations: numpy →
NdArrayUtils pyclipper→
BufferOp cv2.minAreaRect→
Imgproc.minAreaRect np.rot90→
Core.ROTATE_90_COUNTERCLOCKWISEExample result
Using the tiny model on a driving‑license image ( test_images/1.png) yields the following visualisation and extracted fields:
--- 行驶证结构化解析 ---
plateNo: 鲁GH9P12
owner: 盛瑞传动股份有限公司
vehicleType: 小型普通客车
vin: LJ8F3D5H910700001
issueDate: 2018-02-24All fields are correctly recognized, demonstrating reliability for structured document scenarios.
Applicable scenarios
License and ID card recognition (driving license, identity card, business license).
Invoice and receipt digitization.
Bulk document scanning and text extraction.
On‑premise compliance where data must stay within the internal network.
Unifying OCR capabilities within an existing Java/Spring ecosystem.
Conclusion
mica-ppocr brings high‑quality OCR—previously only feasible in Python—to the Java ecosystem with a single Maven dependency, zero Python requirement, bit‑exact results, three model tiers, Spring Boot starter, and an Apache 2.0 license. Project URLs: https://gitee.com/dreamlu/mica-ppocr, https://github.com/lets-mica/mica-ppocr.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
