Complex image CAPTCHAs use connected letters, overlapping characters, varied fonts, and noise to prevent OCR. Here's how to approach them with CaptchaAI.
Common Complexity Types
| Type | Description | Difficulty |
|---|---|---|
| Clean text | No distortion, uniform font | Easy |
| Warped text | Letters individually rotated/scaled | Medium |
| Connected letters | Characters overlap or touch | Hard |
| Multi-font | Different fonts per character | Hard |
| Noise + lines | Background noise, strikethrough lines | Medium |
| Color variation | Different colors per character | Medium |
| Math expression | Numbers + operators, result expected | Medium |
Submitting Complex CAPTCHAs
For standard multi-character CAPTCHAs, submit via base64 with appropriate hints:
import requests
import base64
import time
import os
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_complex_image(image_b64, hints=None):
"""Solve a complex multi-character image CAPTCHA."""
payload = {
"key": API_KEY,
"method": "base64",
"body": image_b64,
"json": 1,
}
if hints:
payload.update(hints)
resp = requests.post(
"https://ocr.captchaai.com/in.php",
data=payload,
timeout=30,
)
result = resp.json()
if result.get("status") != 1:
raise RuntimeError(f"Submit failed: {result.get('request')}")
task_id = result["request"]
time.sleep(8)
for _ in range(24):
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}, timeout=15)
data = resp.json()
if data.get("status") == 1:
return data["request"]
if data["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(data["request"])
time.sleep(5)
raise TimeoutError("Solve timeout")
Strategy: Connected Letters
Connected letters are the hardest for basic OCR but not for CaptchaAI:
def solve_connected_letters(image_path):
"""Solve CAPTCHA with connected/overlapping characters."""
with open(image_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("ascii")
return solve_complex_image(b64, hints={
"textinstructions": "Characters may be connected or overlapping",
"minLen": 4,
"maxLen": 8,
})
Strategy: Mixed Case with Noise
def solve_noisy_mixed(image_path):
"""Solve CAPTCHA with background noise and mixed case."""
with open(image_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("ascii")
return solve_complex_image(b64, hints={
"regsense": 1, # Case-sensitive
"language": 2, # Latin characters
"textinstructions": "Ignore background lines and noise",
})
Strategy: Multi-Font Text
def solve_multi_font(image_path):
"""Solve CAPTCHA using multiple fonts per character."""
with open(image_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("ascii")
return solve_complex_image(b64, hints={
"textinstructions": "Each character may use a different font or style",
"minLen": 5,
"maxLen": 7,
})
Image Preprocessing for Better Results
Preprocessing before submission can improve accuracy:
# preprocess.py
from PIL import Image, ImageFilter, ImageEnhance
import io
import base64
def preprocess_for_ocr(image_path):
"""Preprocess image to improve OCR accuracy."""
img = Image.open(image_path)
# Convert to grayscale
img = img.convert("L")
# Increase contrast
enhancer = ImageEnhance.Contrast(img)
img = enhancer.enhance(2.0)
# Sharpen
img = img.filter(ImageFilter.SHARPEN)
# Binarize (threshold)
threshold = 128
img = img.point(lambda p: 255 if p > threshold else 0)
# Encode back to base64
buffer = io.BytesIO()
img.save(buffer, format="PNG")
return base64.b64encode(buffer.getvalue()).decode("ascii")
Retry Strategy with Reporting
# retry_strategy.py
def solve_with_retry(image_b64, hints, max_retries=3):
"""Retry solving with fallback strategies."""
strategies = [
hints, # Original hints
{**hints, "textinstructions": ""}, # Without instructions
{**hints, "numeric": 0, "regsense": 0}, # Relaxed constraints
]
for i, strategy in enumerate(strategies[:max_retries]):
try:
result = solve_complex_image(image_b64, strategy)
return {"text": result, "strategy": i, "success": True}
except RuntimeError:
continue
return {"text": None, "strategy": -1, "success": False}
def report_bad_answer(task_id):
"""Report incorrect answer for quality feedback."""
requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "reportbad",
"id": task_id,
}, timeout=10)
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| Missing characters | Connected letters misread | Add textinstructions about connected text |
| Extra characters | Noise interpreted as text | Preprocess: remove noise before submission |
| Wrong case | Case not preserved | Set regsense=1 |
| Math result returned as expression | Missing calc=1 |
Enable calc mode for math CAPTCHAs |
| Consistently wrong on specific site | Site-specific font | Report bad answers to improve model |
FAQ
Should I preprocess images before submitting?
Only if you're getting poor results. CaptchaAI handles most distortions natively. Preprocessing helps for very noisy or low-contrast images.
What if the same image type keeps failing?
Report bad answers with reportbad to help improve accuracy. Also try adding specific textinstructions describing the CAPTCHA characteristics.
Is there a character limit for image CAPTCHAs?
CaptchaAI can handle CAPTCHAs up to about 20 characters. Most are 4-8 characters.
Related Guides
Solve complex image CAPTCHAs — start with CaptchaAI.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.