iconcaptcha / app.py
vwxyzarii's picture
Update app.py
1b7f4bc verified
import base64, cv2, numpy as np
from fastapi import FastAPI
from pydantic import BaseModel
import uvicorn
app = FastAPI(
title="IconCaptcha Solver API",
version="1.0",
description="Solver IconCaptcha - return click point, bounding box, and edited image"
)
class SolveRequest(BaseModel):
widgetId: str
challengeId: str
image_base64: str
def b64_to_image(b64):
nparr = np.frombuffer(base64.b64decode(b64), np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
if img.shape[2] == 4: # transparan → ubah ke background putih
alpha = img[:,:,3] / 255.0
rgb = img[:,:,:3]
bg = np.ones_like(rgb)*255
img = (rgb*alpha[:,:,None] + bg*(1-alpha[:,:,None])).astype(np.uint8)
return img
def extract_icons(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_,thr = cv2.threshold(gray,200,255,cv2.THRESH_BINARY_INV)
cnt,_ = cv2.findContours(thr,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
icons,pos=[],[]
for c in cnt:
x,y,w,h=cv2.boundingRect(c)
if w>20 and h>20:
roi=cv2.resize(thr[y:y+h,x:x+w],(50,50))
icons.append(roi)
pos.append((x,y,w,h))
return icons,pos
def img_hash(img):
small=cv2.resize(img,(8,8))
return (small>small.mean()).astype(np.uint8).flatten()
def rare_icon(icons,pos):
hashes=[img_hash(i) for i in icons]
groups=[]
for h in hashes:
placed=False
for g in groups:
if np.sum(h!=g[0]) < 4:
g.append(h); placed=True; break
if not placed:
groups.append([h])
rare=min(groups,key=len)[0]
idx=[h.tolist()==rare.tolist() for h in hashes].index(True)
x,y,w,h = pos[idx]
return x+w//2, y+h//2, (x,y,w,h)
@app.post("/solve")
def solve(req:SolveRequest):
img = b64_to_image(req.image_base64)
icons,pos = extract_icons(img)
cx,cy,(bx,by,bw,bh) = rare_icon(icons,pos)
cv2.rectangle(img,(bx,by),(bx+bw,by+bh),(0,0,255),3)
cv2.circle(img,(cx,cy),8,(0,0,255),-1)
_,buf=cv2.imencode(".png",img)
result_b64=base64.b64encode(buf).decode()
return {
"widgetId":req.widgetId,
"challengeId":req.challengeId,
"click_x":cx,
"click_y":cy,
"result_base64":result_b64
}
def start():
uvicorn.run(app,host="0.0.0.0",port=7860)
if __name__=="__main__":
start()