source: pwntcha/trunk/src/slashdot.c @ 385

Last change on this file since 385 was 385, checked in by Sam Hocevar, 15 years ago
  • moved generic filter functions to filters.c
  • fixed uninitialised value in trick().
  • Property svn:keywords set to Id
File size: 10.3 KB
Line 
1/*
2 * slashdot.c: decode Slashdot captchas
3 * $Id: slashdot.c 385 2005-01-03 15:00:45Z sam $
4 *
5 * Copyright: (c) 2004 Sam Hocevar <sam@zoy.org>
6 *   This program is free software; you can redistribute it and/or
7 *   modify it under the terms of the Do What The Fuck You Want To
8 *   Public License as published by Banlu Kemiyatorn. See
9 *   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <math.h>
16
17#include "config.h"
18#include "common.h"
19
20/* Our macros */
21#define FACTOR 1
22//#define FONTNAME "share/font.png" // use with FACTOR = 2
23//#define FONTNAME "share/font_dilated.png" // use with FACTOR = 2
24#define FONTNAME "share/font_dilated_half.png" // use with FACTOR = 1
25
26/* Global stuff */
27char *result;
28
29struct
30{
31    int xmin, ymin, xmax, ymax;
32}
33objlist[100];
34int objects = 0, first = -1, last = -1;
35
36/* Functions */
37
38struct image *count_objects(struct image *img)
39{
40    struct image *dst;
41    int gotblack = 1;
42    int x, y, i;
43    int r, g, b;
44
45    dst = new_image(img->width, img->height);
46
47    for(y = 0; y < img->height; y++)
48        for(x = 0; x < img->width; x++)
49        {
50            getpixel(img, x, y, &r, &g, &b);
51            setpixel(dst, x, y, r, g, b);
52        }
53
54    while(gotblack)
55    {
56        gotblack = 0;
57        for(y = 0; y < dst->height; y++)
58            for(x = 0; x < dst->width; x++)
59            {
60                getpixel(dst, x, y, &r, &g, &b);
61                if(r == 50 && g == 50 && b == 50)
62                {
63                    gotblack = 1;
64                    flood_fill(dst, x, y, 255 - objects, 0, 0);
65                    objects++;
66                }
67            }
68    }
69
70    //printf("%i objects\n", objects);
71
72    for(i = 0; i < objects; i++)
73    {
74        objlist[i].ymin = dst->height;
75        objlist[i].ymax = 0;
76
77        for(y = 0; y < dst->height; y++)
78            for(x = 0; x < dst->width; x++)
79            {
80                getpixel(dst, x, y, &r, &g, &b);
81                if(r == 255 - i && g == 0 && b == 0)
82                {
83                    if(y < objlist[i].ymin) { objlist[i].ymin = y; objlist[i].xmin = x; }
84                    if(y > objlist[i].ymax) { objlist[i].ymax = y; objlist[i].xmax = x; }
85                }
86            }
87        //printf("y min-max: %i %i (size %i)\n", objlist[i].ymin, objlist[i].ymax, objlist[i].ymax - objlist[i].ymin + 1);
88        if(objlist[i].ymax - objlist[i].ymin > 18 && objlist[i].ymax - objlist[i].ymin < 27)
89        {
90            if(first == -1)
91                first = i;
92            last = i;
93            flood_fill(dst, objlist[i].xmin, objlist[i].ymin, 0, 0, 255);
94        }
95    }
96
97#if 0
98    { CvPoint A, B;
99      A.x = (objlist[first].xmin + objlist[first].xmax) / 2;
100      A.y = (objlist[first].ymin + objlist[first].ymax) / 2;
101      B.x = (objlist[last].xmin + objlist[last].xmax) / 2;
102      B.y = (objlist[last].ymin + objlist[last].ymax) / 2;
103      cvLine(dst, A, B, 0, 2.0, 0);
104    }
105#endif
106
107    return dst;
108}
109
110struct image *rotate(struct image *img)
111{
112    struct image *dst;
113    int x, y, xdest, ydest;
114    int r, g, b, R, G, B;
115    int X = objlist[first].xmin - objlist[last].xmin;
116    int Y = objlist[first].ymin - objlist[last].ymin;
117    float xtmp, ytmp;
118    float sina = (1.0 * Y) / sqrt(1.0 * X * X + Y * Y);
119    float cosa = (1.0 * X) / sqrt(1.0 * X * X + Y * Y);
120    if(sina * cosa > 0)
121    {
122        sina = -sina;
123        cosa = -cosa;
124    }
125
126    dst = new_image(img->width * FACTOR, img->height * FACTOR);
127
128    for(y = 0; y < img->height * FACTOR; y++)
129        for(x = 0; x < img->width * FACTOR; x++)
130        {
131            xtmp = 1.0 * (x - img->width * FACTOR / 2) / FACTOR;
132            ytmp = 1.0 * (y - img->height * FACTOR / 2) / FACTOR;
133            xdest = xtmp * cosa - ytmp * sina + 0.5 * img->width;
134            ydest = ytmp * cosa + xtmp * sina + 0.5 * img->height;
135            //R = G = B = 0;
136            getpixel(img, xdest, ydest, &r, &g, &b);
137            //R += r; G += g; B += b;
138            //getpixel(img, xdest+1, ydest, &r, &g, &b);
139            //R += r; G += g; B += b;
140            //getpixel(img, xdest, ydest+1, &r, &g, &b);
141            //R += r; G += g; B += b;
142            //getpixel(img, xdest+1, ydest+1, &r, &g, &b);
143            //R += r; G += g; B += b;
144            //r = R / 4; g = G / 4; b = B / 4;
145            if(r == 255 && g == 0 && b == 255)
146                g = 255;
147            setpixel(dst, x, y, r, g, b);
148        }
149
150    return dst;
151}
152
153struct image *cut_cells(struct image *img)
154{
155    struct image *dst;
156    int x, y;
157    int r, g, b;
158
159    dst = new_image(img->width, img->height);
160
161    for(y = 0; y < img->height; y++)
162        for(x = 0; x < img->width; x++)
163        {
164            getpixel(img, x, y, &r, &g, &b);
165            setpixel(dst, x, y, r, g, b);
166        }
167
168    for(x = 0; x < img->width; x++)
169    {
170        setpixel(dst, x, 0, 255, 255, 255);
171        setpixel(dst, x, img->height - 1, 255, 255, 255);
172    }
173
174    for(y = 0; y < img->height; y++)
175        for(x = 0; x < 7; x++)
176        {
177            setpixel(dst, x * img->width / 7, y, 255, 255, 255);
178            setpixel(dst, (x + 1) * img->width / 7 - 1, y, 255, 255, 255);
179        }
180
181    return dst;
182}
183
184struct image * find_glyphs(struct image *img)
185{
186    char all[] = "abcdefgijkmnpqrstvwxyz";
187    struct
188    {
189        int xmin, xmax, ymin, ymax;
190        int count;
191    }
192    glyphs[22];
193    struct image *dst;
194    struct image *font = load_image(FONTNAME);
195    int x, y, i = 0;
196    int r, g, b, r2, g2, b2;
197    int xmin, xmax, ymin, ymax, incell = 0, count = 0, startx = 0, cur = 0;
198    int distmin, distx, disty, distch;
199
200    if(!font)
201    {
202        fprintf(stderr, "cannot load font %s\n", FONTNAME);
203        exit(-1);
204    }
205
206    dst = new_image(img->width, img->height);
207
208    for(y = 0; y < img->height; y++)
209        for(x = 0; x < img->width; x++)
210        {
211            getpixel(img, x, y, &r, &g, &b);
212            setpixel(dst, x, y, 255, g, 255);
213        }
214
215    strcpy(result, "       ");
216
217    for(x = 0; x < font->width; x++)
218    {
219        int found = 0;
220        for(y = 0; y < font->height; y++)
221        {
222            getpixel(font, x, y, &r, &g, &b);
223            if(r < 128)
224            {
225                found = 1;
226                count += (255 - r);
227            }
228        }
229        if(found && !incell)
230        {
231            incell = 1;
232            xmin = x;
233        }
234        else if(!found && incell)
235        {
236            incell = 0;
237            xmax = x;
238#if 0
239            ymin = font->height;
240            ymax = 0;
241            for(y = 0; y < font->height; y++)
242            {
243                int newx;
244                int gotit = 0;
245                for(newx = xmin; newx < xmax; newx++)
246                {
247                    getpixel(font, newx, y, &r, &g, &b);
248                    if(r < 128)
249                    {
250                        gotit = 1;
251                        break;
252                    }
253                }
254                if(gotit)
255                {
256                    if(ymin > y) ymin = y;
257                    if(ymax <= y) ymax = y + 1;
258                }
259            }
260#else
261            ymin = 0;
262            ymax = font->height;
263#endif
264            glyphs[i].xmin = xmin;
265            glyphs[i].xmax = xmax;
266            glyphs[i].ymin = ymin;
267            glyphs[i].ymax = ymax;
268            glyphs[i].count = count;
269            count = 0;
270            i++;
271        }
272    }
273
274    if(i != 22)
275    {
276        printf("error: could not find 22 glyphs in font\n");
277        exit(-1);
278    }
279
280while(cur < 7)
281{
282    /* Try to find 1st letter */
283    distmin = 999999999;
284    for(i = 0; i < 22; i++)
285    {
286        int localmin = 99999999, localx, localy;
287//if(all[i] == 'i') continue;
288        xmin = glyphs[i].xmin;
289        ymin = glyphs[i].ymin;
290        xmax = glyphs[i].xmax;
291        ymax = glyphs[i].ymax;
292        //printf("trying to find %c (%i×%i) - ", all[i], xmax - xmin, ymax - ymin);
293        for(y = -5 * FACTOR; y < 5 * FACTOR; y++)
294            for(x = startx - 5 * FACTOR; x < startx + 5 * FACTOR; x++)
295            {
296                int z, t, dist;
297                dist = 0;
298                for(t = 0; t < ymax - ymin; t++)
299                    for(z = 0; z < xmax - xmin; z++)
300                    {
301                        getgray(font, xmin + z, ymin + t, &r);
302                        getgray(img, x + z, y + t, &r2);
303                        dist += abs(r - r2);
304                    }
305//                printf("%i %i -> %i\n", x, y, dist);
306                //dist /= sqrt(xmax - xmin);
307                dist = dist * 128 / glyphs[i].count;
308                if(dist < localmin)
309                {
310                    localmin = dist;
311                    localx = x;
312                    localy = y;
313                }
314            }
315        //fprintf(stderr, "%i (%i,%i)\n", localmin, localx - startx, localy);
316        if(localmin < distmin)
317        {
318            distmin = localmin;
319            distx = localx;
320            disty = localy;
321            distch = i;
322        }
323    }
324
325    //fprintf(stderr, "%i (%i,%i)\n", distmin, distx - startx, disty);
326    //printf("min diff: %c - %i (%i, %i)\n", all[distch], distmin, distx, disty);
327
328    /* Print min glyph */
329    xmin = glyphs[distch].xmin;
330    ymin = glyphs[distch].ymin;
331    xmax = glyphs[distch].xmax;
332    ymax = glyphs[distch].ymax;
333    for(y = 0; y < ymax - ymin; y++)
334        for(x = 0; x < xmax - xmin; x++)
335        {
336            getpixel(font, xmin + x, ymin + y, &r, &g, &b);
337            if(r > 128) continue;
338            setpixel(dst, distx + x, disty + y, r, g, b);
339        }
340
341    startx = distx + xmax - xmin;
342    result[cur++] = all[distch];
343}
344
345    return dst;
346}
347
348char * slashdot_decode(char *image)
349{
350    struct image *img, *tmp, *tmp2;
351
352    img = load_image(image);
353    if(img == NULL)
354        return NULL;
355
356    result = malloc(8 * sizeof(char));
357//    display(img);
358
359//    tmp = equalize(img);
360//    display(tmp);
361//    tmp = fill_holes(tmp);
362//    display(tmp);
363
364//    dst = median(tmp);
365//tmp = smooth(img);
366tmp = fill_holes(img);
367tmp = median(tmp);
368//tmp = smooth(tmp);
369//display(tmp);
370//tmp = trick(tmp);
371//display(tmp);
372tmp = equalize(tmp);
373//display(tmp);
374
375tmp = detect_lines(img);
376tmp = fill_holes(tmp);
377//tmp = cut_cells(tmp);
378//display_image(tmp);
379
380tmp2 = median(tmp);
381tmp2 = equalize(tmp2);
382count_objects(tmp2);
383//display_image(tmp2);
384
385//tmp = median(tmp);
386tmp = rotate(tmp);
387tmp = median(tmp);
388//display_image(tmp);
389//tmp = equalize(tmp);
390//tmp = cut_cells(tmp);
391//        cvSaveImage(argv[2], tmp);
392
393tmp = find_glyphs(tmp);
394//display_image(tmp);
395
396//        cvSaveImage(argv[3], tmp);
397
398    return result;
399}
400
Note: See TracBrowser for help on using the repository browser.