vwxyzarii commited on
Commit
1b7f4bc
·
verified ·
1 Parent(s): 630d2cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -95
app.py CHANGED
@@ -1,96 +1,95 @@
1
  import base64, cv2, numpy as np
2
- from fastapi import FastAPI
3
- from pydantic import BaseModel
4
- import uvicorn
5
-
6
- app = FastAPI(
7
- ‎    title="IconCaptcha Solver API",
8
- ‎    version="1.0",
9
- ‎    description="Solver IconCaptcha - return click point, bounding box, and edited image"
10
- )
11
-
12
- class SolveRequest(BaseModel):
13
- ‎    widgetId: str
14
- ‎    challengeId: str
15
- ‎    image_base64: str
16
-
17
-
18
- def b64_to_image(b64):
19
- ‎    nparr = np.frombuffer(base64.b64decode(b64), np.uint8)
20
- ‎    img = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
21
-
22
- ‎    if img.shape[2] == 4:   # transparan → ubah ke background putih
23
- ‎        alpha = img[:,:,3] / 255.0
24
- ‎        rgb   = img[:,:,:3]
25
- ‎        bg    = np.ones_like(rgb)*255
26
- ‎        img   = (rgb*alpha[:,:,None] + bg*(1-alpha[:,:,None])).astype(np.uint8)
27
-
28
- ‎    return img
29
-
30
-
31
- def extract_icons(img):
32
- ‎    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
33
- ‎    _,thr = cv2.threshold(gray,200,255,cv2.THRESH_BINARY_INV)
34
- ‎    cnt,_ = cv2.findContours(thr,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
35
-
36
- ‎    icons,pos=[],[]
37
- ‎    for c in cnt:
38
- ‎        x,y,w,h=cv2.boundingRect(c)
39
- ‎        if w>20 and h>20:
40
- ‎            roi=cv2.resize(thr[y:y+h,x:x+w],(50,50))
41
- ‎            icons.append(roi)
42
- ‎            pos.append((x,y,w,h))
43
- ‎    return icons,pos
44
-
45
-
46
- def img_hash(img):
47
- ‎    small=cv2.resize(img,(8,8))
48
- ‎    return (small>small.mean()).astype(np.uint8).flatten()
49
-
50
-
51
- def rare_icon(icons,pos):
52
- ‎    hashes=[img_hash(i) for i in icons]
53
- ‎    groups=[]
54
-
55
- ‎    for h in hashes:
56
- ‎        placed=False
57
- ‎        for g in groups:
58
- ‎            if np.sum(h!=g[0]) < 4:
59
- ‎                g.append(h); placed=True; break
60
- ‎        if not placed:
61
- ‎            groups.append([h])
62
-
63
- ‎    rare=min(groups,key=len)[0]
64
- ‎    idx=[h.tolist()==rare.tolist() for h in hashes].index(True)
65
- ‎    x,y,w,h = pos[idx]
66
- ‎    return x+w//2, y+h//2, (x,y,w,h)
67
-
68
-
69
- @app.post("/solve")
70
- def solve(req:SolveRequest):
71
-
72
- ‎    img = b64_to_image(req.image_base64)
73
- ‎    icons,pos = extract_icons(img)
74
- ‎    cx,cy,(bx,by,bw,bh) = rare_icon(icons,pos)
75
-
76
- ‎    cv2.rectangle(img,(bx,by),(bx+bw,by+bh),(0,0,255),3)
77
- ‎    cv2.circle(img,(cx,cy),8,(0,0,255),-1)
78
-
79
- ‎    _,buf=cv2.imencode(".png",img)
80
- ‎    result_b64=base64.b64encode(buf).decode()
81
-
82
- ‎    return {
83
- ‎        "widgetId":req.widgetId,
84
- ‎        "challengeId":req.challengeId,
85
- ‎        "click_x":cx,
86
- ‎        "click_y":cy,
87
- ‎        "result_base64":result_b64
88
- ‎    }
89
-
90
-
91
- def start():
92
- ‎    uvicorn.run(app,host="0.0.0.0",port=7860)
93
-
94
- if __name__=="__main__":
95
- ‎    start()
96
-
 
1
  import base64, cv2, numpy as np
2
+ from fastapi import FastAPI
3
+ from pydantic import BaseModel
4
+ import uvicorn
5
+
6
+ app = FastAPI(
7
+ title="IconCaptcha Solver API",
8
+ version="1.0",
9
+ description="Solver IconCaptcha - return click point, bounding box, and edited image"
10
+ )
11
+
12
+ class SolveRequest(BaseModel):
13
+ widgetId: str
14
+ challengeId: str
15
+ image_base64: str
16
+
17
+
18
+ def b64_to_image(b64):
19
+ nparr = np.frombuffer(base64.b64decode(b64), np.uint8)
20
+ img = cv2.imdecode(nparr, cv2.IMREAD_UNCHANGED)
21
+
22
+ if img.shape[2] == 4: # transparan → ubah ke background putih
23
+ alpha = img[:,:,3] / 255.0
24
+ rgb = img[:,:,:3]
25
+ bg = np.ones_like(rgb)*255
26
+ img = (rgb*alpha[:,:,None] + bg*(1-alpha[:,:,None])).astype(np.uint8)
27
+
28
+ return img
29
+
30
+
31
+ def extract_icons(img):
32
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
33
+ _,thr = cv2.threshold(gray,200,255,cv2.THRESH_BINARY_INV)
34
+ cnt,_ = cv2.findContours(thr,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
35
+
36
+ icons,pos=[],[]
37
+ for c in cnt:
38
+ x,y,w,h=cv2.boundingRect(c)
39
+ if w>20 and h>20:
40
+ roi=cv2.resize(thr[y:y+h,x:x+w],(50,50))
41
+ icons.append(roi)
42
+ pos.append((x,y,w,h))
43
+ return icons,pos
44
+
45
+
46
+ def img_hash(img):
47
+ small=cv2.resize(img,(8,8))
48
+ return (small>small.mean()).astype(np.uint8).flatten()
49
+
50
+
51
+ def rare_icon(icons,pos):
52
+ hashes=[img_hash(i) for i in icons]
53
+ groups=[]
54
+
55
+ for h in hashes:
56
+ placed=False
57
+ for g in groups:
58
+ if np.sum(h!=g[0]) < 4:
59
+ g.append(h); placed=True; break
60
+ if not placed:
61
+ groups.append([h])
62
+
63
+ rare=min(groups,key=len)[0]
64
+ idx=[h.tolist()==rare.tolist() for h in hashes].index(True)
65
+ x,y,w,h = pos[idx]
66
+ return x+w//2, y+h//2, (x,y,w,h)
67
+
68
+
69
+ @app.post("/solve")
70
+ def solve(req:SolveRequest):
71
+
72
+ img = b64_to_image(req.image_base64)
73
+ icons,pos = extract_icons(img)
74
+ cx,cy,(bx,by,bw,bh) = rare_icon(icons,pos)
75
+
76
+ cv2.rectangle(img,(bx,by),(bx+bw,by+bh),(0,0,255),3)
77
+ cv2.circle(img,(cx,cy),8,(0,0,255),-1)
78
+
79
+ _,buf=cv2.imencode(".png",img)
80
+ result_b64=base64.b64encode(buf).decode()
81
+
82
+ return {
83
+ "widgetId":req.widgetId,
84
+ "challengeId":req.challengeId,
85
+ "click_x":cx,
86
+ "click_y":cy,
87
+ "result_base64":result_b64
88
+ }
89
+
90
+
91
+ def start():
92
+ uvicorn.run(app,host="0.0.0.0",port=7860)
93
+
94
+ if __name__=="__main__":
95
+ start()