Spaces:
Sleeping
Sleeping
| 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) | |
| 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() |