File size: 2,781 Bytes
214a036 6af2ae5 214a036 e79654b 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 214a036 6af2ae5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
import base64
import cv2
import numpy as np
import uvicorn
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from collections import defaultdict
app = FastAPI()
@app.get("/")
def root():
return {
"status": "ok",
"service": "iconCaptcha solver",
"endpoint": "/solve"
}
class Input(BaseModel):
image_base64: str
def preprocess_image_memory(base64_str):
try:
img_data = base64.b64decode(base64_str)
nparr = np.frombuffer(img_data, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
if img is None:
raise ValueError("Invalid/corrupt image")
if len(img.shape) == 3 and img.shape[2] == 4:
alpha = img[:, :, 3] / 255.0
rgb = img[:, :, :3]
white_bg = np.ones_like(rgb, dtype=np.uint8) * 255
img = (rgb * alpha[:, :, None] + white_bg * (1 - alpha[:, :, None])).astype(np.uint8)
return img
except Exception as e:
raise ValueError(f"Error decoding image: {str(e)}")
def extract_icon_positions(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
icons, pos = [], []
for c in contours:
x, y, w, h = cv2.boundingRect(c)
if w > 10 and h > 10:
roi = cv2.resize(thresh[y:y+h, x:x+w], (50, 50))
icons.append(roi)
pos.append((x, y))
return icons, pos
def img_hash(img):
img = cv2.resize(img, (8, 8))
return (img > img.mean()).astype(np.uint8).flatten()
def find_rarest(icon_features, positions):
if not icon_features:
return None, None
hashes = [img_hash(i) for i in icon_features]
groups = defaultdict(list)
for i, h in enumerate(hashes):
found = False
for label, group in groups.items():
if np.sum(h != hashes[group[0]]) < 3:
group.append(i)
found = True
break
if not found:
groups[len(groups)] = [i]
if not groups:
return None, None
idx = min(groups.values(), key=len)[0]
return positions[idx]
@app.post("/solve")
def solve(data: Input):
try:
img = preprocess_image_memory(data.image_base64)
icons, pos = extract_icon_positions(img)
if not icons:
return {"error": "No icons found", "x": 0, "y": 0}
x, y = find_rarest(icons, pos)
return {"x": int(x), "y": int(y)}
except Exception as e:
return {"error": str(e)}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860) |