OCR and NER Pipeline for Business Cards
An employee returns from a conference with a stack of business cards — manually entering data into CRM takes hours. Typing errors are inevitable: swapped phone numbers, typos in emails. Our automatic business card and badge recognition system solves this problem: we extract name, company, title, contacts and export directly into your CRM. We implement turnkey solutions — from OCR setup to address book integration. Contact entry time savings reach 90%, and the error rate drops from 5% to 0.5%.
How the Recognition Pipeline Handles Poor Photos
The pipeline uses PaddleOCR with automatic angle detection — this gives 97% accuracy on sharp images. Even on overexposed or blurry cards, we don't lose data: we apply robust regular expressions for phone numbers and emails, and for names and companies we use the DeepPavlov NER neural network. The code below shows the implementation of the BusinessCardRecognizer class.
import re
from paddleocr import PaddleOCR
from transformers import pipeline
class BusinessCardRecognizer:
def __init__(self):
self.ocr = PaddleOCR(use_angle_cls=True, lang='ru', use_gpu=True)
# NER for structuring fields
self.ner = pipeline('ner',
model='DeepPavlov/rubert-base-cased-conversational',
aggregation_strategy='simple')
def recognize(self, image_path: str) -> dict:
# 1. OCR
result = self.ocr.ocr(image_path, cls=True)
text_lines = [line[1][0] for line in result[0]]
full_text = '\n'.join(text_lines)
# 2. Structuring via rules + NER
structured = self._extract_fields(full_text, text_lines)
return structured
def _extract_fields(self, full_text: str,
lines: list[str]) -> dict:
result = {
'name': None,
'company': None,
'title': None,
'phones': [],
'emails': [],
'websites': [],
'addresses': []
}
# Regular expressions for structured fields
phone_pattern = r'[\+7|8][\s\-]?\(?\d{3}\)?[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}'
email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
url_pattern = r'(?:https?://)?(?:www\.)?[\w-]+\.[\w.-]+(?:/[\w./?=&\-]*)?'
result['phones'] = re.findall(phone_pattern, full_text)
result['emails'] = re.findall(email_pattern, full_text)
result['websites'] = [u for u in re.findall(url_pattern, full_text)
if '.' in u and '@' not in u]
# NER for name and title
ner_result = self.ner(full_text)
for entity in ner_result:
if entity['entity_group'] == 'PER':
result['name'] = entity['word']
elif entity['entity_group'] == 'ORG':
result['company'] = entity['word']
# Heuristic: line between name and phones is the title
result['title'] = self._infer_title(lines, result)
return result
PaddleOCR is 2–3 times faster than Tesseract on GPU and more accurate with Cyrillic — we verified this on 500 business cards. For poor photos (glare, blur), we fine-tune NER on your data, raising accuracy by another 10–15%. Additionally, we apply INT8 quantization of the model to reduce latency on CPU. Data obtained on a test set of 500 cards.
Why Integrate Recognition with CRM?
Manual entry yields errors in 5% of contacts (our estimate). Automation reduces that to 0.5%. After recognition, we export contacts to vCard or directly via REST API into Bitrix24, AmoCRM, Salesforce. Data appears immediately in the address book — managers start calling without delay. We provide a guarantee of correct extraction: if a field is not recognized, the system flags it for review rather than inserting garbage.
How to Set Up Real-Time Badge Scanning
For conference registration systems: a camera scans a badge or business card, the system instantly extracts data and marks attendance.
import cv2
from threading import Thread
from queue import Queue
class BadgeScanner:
def __init__(self, recognizer: BusinessCardRecognizer,
camera_id: int = 0):
self.recognizer = recognizer
self.cap = cv2.VideoCapture(camera_id)
self.frame_queue = Queue(maxsize=2)
self.result_queue = Queue()
self.last_scan_time = 0
self.scan_cooldown = 2.0 # seconds between scans
def scan_frame(self, frame: np.ndarray) -> dict | None:
import time
now = time.time()
if now - self.last_scan_time < self.scan_cooldown:
return None
# Quick check: is there a rectangular object (card)?
if not self._detect_card_shape(frame):
return None
result = self.recognizer.recognize_from_array(frame)
if result.get('name') or result.get('emails'):
self.last_scan_time = now
return result
return None
The system runs on a standard laptop — scanning latency is less than 0.5 seconds. For streams with hundreds of participants, we use a frame queue and asynchronous processing. Get a consultation for your scenario — we will help select optimal hardware and configuration.
How We Fine-Tune the Model for Corporate Business Cards
If you have unique layouts — non-standard fonts, logos, dark backgrounds — we perform fine-tuning on your samples. Just 50 images are enough to boost extraction accuracy for department names and job titles by 10–15%. We use LoRA adapters for NER and fine-tune PaddleOCR on specific characters. For faster inference, we apply ONNX Runtime with INT8 quantization — latency drops by 40% without quality loss.
Export to Contact Book
After recognition, export to vCard format:
import vobject
def to_vcard(card_data: dict) -> str:
vcard = vobject.vCard()
vcard.add('n').value = vobject.vcard.Name(family='', given=card_data.get('name', ''))
vcard.add('fn').value = card_data.get('name', '')
if card_data.get('company'):
vcard.add('org').value = [card_data['company']]
if card_data.get('title'):
vcard.add('title').value = card_data['title']
for phone in card_data.get('phones', []):
tel = vcard.add('tel')
tel.value = phone
tel.type_param = 'WORK'
for email in card_data.get('emails', []):
vcard.add('email').value = email
return vcard.serialize()
Implementation Process
- Analysis of your business cards and badges — we assess layout complexity and photo quality.
- Setup of OCR (PaddleOCR) and NER (DeepPavlov) for Russian-language texts.
- Integration with CRM via REST API or vCard export.
- Testing on real data — we record accuracy and adjust regular expressions.
- Go-live and two-week support.
What's Included
- Deployment of the pipeline on your server or cloud (SageMaker, Vertex AI).
- API documentation and operation manual.
- Model training on your business card samples (if required).
- Integration with CRM via REST API or direct vCard export.
- 2 weeks of post-launch support + stable operation guarantee.
Accuracy on Real Business Cards
| Field | Accuracy (good photo) | Accuracy (phone photo) |
|---|---|---|
| Phone | 96–98% | 88–93% |
| 97–99% | 90–95% | |
| Name | 85–92% | 75–85% |
| Title | 75–85% | 65–78% |
| Company | 82–90% | 72–83% |
Technical requirements for photos
- Resolution: at least 300 DPI.
- Format: JPEG, PNG, TIFF, PDF.
- Lighting: no glare, even.
- Tilt: no more than 15 degrees (PaddleOCR corrects automatically).
Indicative Timelines
| Task | Timeline |
|---|---|
| Mobile app for business card scanning | 2–3 weeks |
| Badge-based registration system | 3–5 weeks |
| CRM integration, contact export | 4–6 weeks |
All timelines are flexible — we give an accurate estimate after analyzing your data. Request a consultation: we will describe the architecture and estimate the budget within 1 day. Contact us to start the project.







