Ich habe Land geschaffen…

Hier mein neustes kleines Projekt:
Eine kleine Agenten-Simulation. Das ganze besteht aus einer Server/Client Architektur. Eine Welt in die sich per Socket Agenten einloggen können. Natürlich gibt es Server und Client in Python, aaaaber… man kann die Agenten auch per netcat kreieren und steuern, wie man im Bild erkennen kann :)
Man kann mittels eines Bildes die Wände der Welt definieren, die von den Agenten erkannt werden. Die Jungs kollidieren auch schon mit den Wänden, aber noch nicht unter einander.
Simulation
Falls jemand Teile davon gebrauchen kann, oder den Code weiterentwickeln will: Fühlt euch frei den Code nach gut Dünken zu nutzen (quasi MIT-Lizenz). Hier gehts zum Download.
Der Code ist dokumentiert und eine README gibt’s auch, die die API und die Architektur erklärt. Viel Spass :D

Spaß mit Bildern

Bin letztens auf ein interessantes Paper gestoßen:
Das Thema ist, Copy & Paste in Bildern zu erkennen. Also im Prinzip den Einsatz von Photoshops Clone-tool.
Die Grundgedanke ist ganz einfach:
Zuerst werden aus dem Bild alle möglichen 16×16 Pixel großen Unterbilder extrahiert. Jedes Unterbild wird dann diskret Cosinus Transformiert (man schaut quasi welche Cosinus Anteile wie stark in den Unterbildern vorhanden sind) Zum Schluss vergleicht man die Ergebnisse der Transformationen untereinander. Cluster von ähnlichen Transformationen deuten stark auf Copy & Paste hin.

Hier hat sich jemand daran versucht das ganze nachzubauen. Ich hab’s auch probiert… überaschender Weise in Python ;)
Allerdings habe ich mich aus Gründen der Performanz gegen eine selbst geschriebene DCT und für numPy’s FFT entschieden. Es funktioniert, aber das Ergebnis überzeugt mich noch nicht so recht… Dafür habe ich mich in diesem Rahmen mal mit der Image-Library auseinander gesetzt und jetzt kann ich Bilder invertieren :D

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
from PIL import Image,ImageOps
from sys import argv

# open the image
filename = argv[1]
im = Image.open(filename)
w,h = im.size

# read the pixel data in a list
data = list(im.getdata())

# invert each pixel
counter = 0
for y in range(0,h):
    for x in range(0,w):
        RGBs = data[counter]
        counter += 1
        im.putpixel((x,y), (255-RGBs[0], 255-RGBs[1], 255-RGBs[2]))

# come up with a good name
tmp = filename.split('.')
tmp.pop() # kick file-extension
outputName = ''
for part in tmp: # In case there is a '.' in the name...
    outputName += part
    outputName += '_inverted.png'

    # save the inverted image
    im.save(outputName)

Hier ein Beispiel:

original

original_inverted

Einfach den Code unter Invert.py speichern und im Terminal folgendes tippen:

1
python Invert.py original.jpg

Der Barcode hatte Geburtstag

Letztens hatte der Barcode Geburtstag und die Jungs von Hackaday.com hatten eine kleine Challange aufgesetzt. Es ging darum einen Barcode zu entziffern…
Das hat mein Interesse geweckt! Hier ist meine Lösung dazu und noch zwei Barcodes zum rumspielen… Enjoy =)

wikipedia Barcode

hackaday Barcode

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/python

import Image
from sys import argv

# lookup tables for the 3 different charsets
CharSetA =  {
    ' ':0, '!':1, '"':2, '#':3, '$':4, '%':5, '&':6, "'":7,
    '(':8, ')':9, '*':10, '+':11, ',':12, '-':13, '.':14, '/':15,
    '0':16, '1':17, '2':18, '3':19, '4':20, '5':21, '6':22, '7':23,
    '8':24, '9':25, ':':26, ';':27, '<':28, '=':29, '>':30, '?':31,
    '@':32, 'A':33, 'B':34, 'C':35, 'D':36, 'E':37, 'F':38, 'G':39,
    'H':40, 'I':41, 'J':42, 'K':43, 'L':44, 'M':45, 'N':46, 'O':47,
    'P':48, 'Q':49, 'R':50, 'S':51, 'T':52, 'U':53, 'V':54, 'W':55,
    'X':56, 'Y':57, 'Z':58, '[':59, '\':60, ']':61, '^':62, '_':63,
    '
\x00':64, '\x01':65, '\x02':66, '\x03':67, '\x04':68, '\x05':69, '\x06':70, '\x07':71,
    '
\x08':72, '\x09':73, '\x0A':74, '\x0B':75, '\x0C':76, '\x0D':77, '\x0E':78, '\x0F':79,
    '
\x10':80, '\x11':81, '\x12':82, '\x13':83, '\x14':84, '\x15':85, '\x16':86, '\x17':87,
    '
\x18':88, '\x19':89, '\x1A':90, '\x1B':91, '\x1C':92, '\x1D':93, '\x1E':94, '\x1F':95,
    '
FNC3':96, 'FNC2':97, 'SHIFT':98, 'Code C':99, 'Code B':100, 'FNC4':101, 'FNC1':102, 'START A':103,
    '
START B':104, 'START C':105, ' STOP':106
}

CharSetB = {
    '
':0, '!':1, '"':2, '#':3, '$':4, '%':5, '&':6, "'":7,
    '
(':8, ')':9, '*':10, '+':11, ',':12, '-':13, '.':14, '/':15,
    '
0':16, '1':17, '2':18, '3':19, '4':20, '5':21, '6':22, '7':23,
    '
8':24, '9':25, ':':26, ';':27, '<':28, '=':29, '>':30, '?':31,
    '
@':32, 'A':33, 'B':34, 'C':35, 'D':36, 'E':37, 'F':38, 'G':39,
    '
H':40, 'I':41, 'J':42, 'K':43, 'L':44, 'M':45, 'N':46, 'O':47,
    '
P':48, 'Q':49, 'R':50, 'S':51, 'T':52, 'U':53, 'V':54, 'W':55,
    '
X':56, 'Y':57, 'Z':58, '[':59, '\':60, ']':61, '^':62, '_':63,
    '
' :64, 'a':65, 'b':66, 'c':67, 'd':68, 'e':69, 'f':70, 'g':71,
    '
h':72, 'i':73, 'j':74, 'k':75, 'l':76, 'm':77, 'n':78, 'o':79,
    '
p':80, 'q':81, 'r':82, 's':83, 't':84, 'u':85, 'v':86, 'w':87,
    '
x':88, 'y':89, 'z':90, '{':91, '|':92, '}':93, '~':94, '\x7F':95,
    '
FNC3':96, 'FNC2':97, 'SHIFT':98, 'Code C':99, 'FNC4':100, 'Code A':101, 'FNC1':102, 'START A':103,
    '
START B':104, 'START C':105, ' STOP':106
}

CharSetC = {
    '
00':0, '01':1, '02':2, '03':3, '04':4, '05':5, '06':6, '07':7,
    '
08':8, '09':9, '10':10, '11':11, '12':12, '13':13, '14':14, '15':15,
    '
16':16, '17':17, '18':18, '19':19, '20':20, '21':21, '22':22, '23':23,
    '
24':24, '25':25, '26':26, '27':27, '28':28, '29':29, '30':30, '31':31,
    '
32':32, '33':33, '34':34, '35':35, '36':36, '37':37, '38':38, '39':39,
    '
40':40, '41':41, '42':42, '43':43, '44':44, '45':45, '46':46, '47':47,
    '
48':48, '49':49, '50':50, '51':51, '52':52, '53':53, '54':54, '55':55,
    '
56':56, '57':57, '58':58, '59':59, '60':60, '61':61, '62':62, '63':63,
    '
64':64, '65':65, '66':66, '67':67, '68':68, '69':69, '70':70, '71':71,
    '
72':72, '73':73, '74':74, '75':75, '76':76, '77':77, '78':78, '79':79,
    '
80':80, '81':81, '82':82, '83':83, '84':84, '85':85, '86':86, '87':87,
    '
88':88, '89':89, '90':90, '91':91, '92':92, '93':93, '94':94, '95':95,
    '
96':96, '97':97, '98':98, '99':99, 'Code B':100, 'Code A':101, 'FNC1':102, 'START A':103,
    '
START B':104, 'START C':105, ' STOP':106
}

# The barcode and the according number in the according char-set
ValueEncodings = {
    0:'
11011001100',  1:'11001101100',  2:'11001100110',
    3:'
10010011000',  4:'10010001100',  5:'10001001100',
    6:'
10011001000',  7:'10011000100',  8:'10001100100',
    9:'
11001001000', 10:'11001000100', 11:'11000100100',
    12:'
10110011100', 13:'10011011100', 14:'10011001110',
    15:'
10111001100', 16:'10011101100', 17:'10011100110',
    18:'
11001110010', 19:'11001011100', 20:'11001001110',
    21:'
11011100100', 22:'11001110100', 23:'11101101110',
    24:'
11101001100', 25:'11100101100', 26:'11100100110',
    27:'
11101100100', 28:'11100110100', 29:'11100110010',
    30:'
11011011000', 31:'11011000110', 32:'11000110110',
    33:'
10100011000', 34:'10001011000', 35:'10001000110',
    36:'
10110001000', 37:'10001101000', 38:'10001100010',
    39:'
11010001000', 40:'11000101000', 41:'11000100010',
    42:'
10110111000', 43:'10110001110', 44:'10001101110',
    45:'
10111011000', 46:'10111000110', 47:'10001110110',
    48:'
11101110110', 49:'11010001110', 50:'11000101110',
    51:'
11011101000', 52:'11011100010', 53:'11011101110',
    54:'
11101011000', 55:'11101000110', 56:'11100010110',
    57:'
11101101000', 58:'11101100010', 59:'11100011010',
    60:'
11101111010', 61:'11001000010', 62:'11110001010',
    63:'
10100110000', 64:'10100001100', 65:'10010110000',
    66:'
10010000110', 67:'10000101100', 68:'10000100110',
    69:'
10110010000', 70:'10110000100', 71:'10011010000',
    72:'
10011000010', 73:'10000110100', 74:'10000110010',
    75:'
11000010010', 76:'11001010000', 77:'11110111010',
    78:'
11000010100', 79:'10001111010', 80:'10100111100',
    81:'
10010111100', 82:'10010011110', 83:'10111100100',
    84:'
10011110100', 85:'10011110010', 86:'11110100100',
    87:'
11110010100', 88:'11110010010', 89:'11011011110',
    90:'
11011110110', 91:'11110110110', 92:'10101111000',
    93:'
10100011110', 94:'10001011110', 95:'10111101000',
    96:'
10111100010', 97:'11110101000', 98:'11110100010',
    99:'
10111011110',100:'10111101110',101:'11101011110',
    102:'
11110101110',103:'11010000100',104:'11010010000',
    105:'
11010011100',106:'11000111010'
}# '


# swap the dictionaries
def swap_dictionary(original_dict):
    # old version
#   return dict( [(v, k) for (k, v) in original_dict.iteritems()] )
    # refined version... with generator expressions...thx J
    return dict( (v, k) for (k, v) in original_dict.iteritems() )

# I found these encoding tables on the web...
# sadly the key:value pairs are the wrong way for my need
# so i swap them =)
CharSetA = swap_dictionary(CharSetA)
CharSetB = swap_dictionary(CharSetB)
CharSetC = swap_dictionary(CharSetC)
ValueEncodings = swap_dictionary(ValueEncodings)


# read in image
im_file = Image.open(argv[1])
im = im_file.getdata()
width = im.size[0]
height = im.size[1] / 2

# convert to 1 pixel high stripe in the middle of the image
cropped = im.crop((0,height,width,height+1))

# translate to 0's and 1's
code = ''
for pixel in cropped:
    try: # if is RGB picture
        pix = pixel[0]
    except: # if is greyscale picture
        pix = pixel
    if pix >200:
        pix = 0
    else:
        pix = 1
    code += str(pix)


# remove leading and trailing 0's
code = code.lstrip('0').rstrip('0')
   
   
# pop first 11 bits from the code
# these 11 bits stand for a char
def get_char(code):
    char = code[:11]
    code = code[11:]
    return char, code


out_buff = ""
# determine the encoding
first, code = get_char(code)
encoding = ValueEncodings[first]

if encoding == 103:
    charset = CharSetA
    out_buff += 'START A '
elif encoding == 104:
    charset = CharSetB
    out_buff += 'START B '
elif encoding == 105:
    charset = CharSetC
    out_buff += 'START C '
else:
    print "Encoding unknown"
    exit(0)


# decypher the message
while(len(code) >= 11):
    next_char, code = get_char(code)
    encoding_number = ValueEncodings[next_char]
    out_buff += charset[encoding_number]

# display the message
print out_buff

Einfach als barcode.py speichern und von der Konsole aus mit:

1
python barcode.py BarcodeBild.jpg

starten. Das Ganze funktiniert allerdings nur unter bestimmten Voraussetzungen. Der Barcode muss vom Typ 128 sein und das Bild des Barcodes muss eine 1 mit einem ein Pixel breiten Strich kodieren.