201 lines
6.2 KiB
Python
201 lines
6.2 KiB
Python
import os, sys
|
|
import Image
|
|
from random import sample
|
|
|
|
'''
|
|
IMPORTANT:
|
|
- When printing images generated with this code you HAVE to ignore page margins! (use GIMP)
|
|
- Markers on a board must be separated by white borders or ArUco won't detect them
|
|
'''
|
|
|
|
ARUCO_MARKER_CREATOR = '/home/mmbrian/temp/aruco-1.3.0/build/utils/aruco_create_marker '
|
|
DESTINATION_DIR = '/home/mmbrian/HiWi/etra2016_mohsen/code/recording/util/markers/'
|
|
DEFAULT_MARKER_SIZE_IN_PIXELS = 64
|
|
DEFAULT_MARKER_BORDER_IN_PIXELS = 7 # only applies for random boards
|
|
DEFAULT_MARKER_SIZE_IN_MM = 40
|
|
A4_PADDING_IN_PIXELS = 50
|
|
|
|
|
|
def createMarker(marker_id, size_in_pixels, format = 'png'):
|
|
assert marker_id >= 0 and marker_id < 1024, 'Invalid Marker ID. Must be in Range 0-1023'
|
|
cmd = ARUCO_MARKER_CREATOR + '{0} ' + DESTINATION_DIR + '{0}.' + format + ' {1} 0'
|
|
os.popen(cmd.format(marker_id, size_in_pixels))
|
|
|
|
def handleMarkers():
|
|
'''
|
|
Usage:
|
|
marker.py num_of_markers size_in_pixels
|
|
marker.py -i marker_id size_in_pixels
|
|
'''
|
|
if len(sys.argv) > 3:
|
|
try:
|
|
createMarker(int(sys.argv[2]), int(sys.argv[3]))
|
|
except:
|
|
print 'Usage: marker.py -i marker_id size_in_pixels'
|
|
else:
|
|
try:
|
|
num = int(sys.argv[1])
|
|
assert num>0 and num<=1024
|
|
except:
|
|
print 'Invalid number of markers. please specify a number between 1 and 1024'
|
|
return
|
|
|
|
size = DEFAULT_MARKER_SIZE_IN_PIXELS
|
|
try:
|
|
size = int(sys.argv[2])
|
|
print 'Marker size set to', size, 'px'
|
|
except:
|
|
print 'Marker size set to default size', size, 'px'
|
|
|
|
print 'Creating', num, 'random markers...'
|
|
|
|
generateRandomMarkers(num, size)
|
|
|
|
def generateRandomMarkers(num, size):
|
|
# for i in range(num):
|
|
for i, _id in enumerate(sorted(sample(range(1024), num))):
|
|
createMarker(_id, size)
|
|
print i+1, '/', num
|
|
print 'Finished.'
|
|
|
|
def computeDimensions():
|
|
A4W, A4H = 210, 297 # A4 dimension in millimeters
|
|
MM2IN = 25.4 # millimeters per inch
|
|
dpi = -1 # Must be given (use xdpyinfo under linux)
|
|
marker_width = -1 # Arbitrary value which must be given by user (in millimeters)
|
|
|
|
try:
|
|
dpi = int(sys.argv[2])
|
|
assert dpi>0
|
|
except:
|
|
print sys.argv
|
|
print 'Invalid dpi.'
|
|
return
|
|
|
|
marker_width = DEFAULT_MARKER_SIZE_IN_MM
|
|
try:
|
|
marker_width = int(sys.argv[3])
|
|
print 'Marker size set to', marker_width, 'mm'
|
|
except:
|
|
print 'Marker size set to default size', marker_width, 'mm'
|
|
|
|
# Width and Height of A4 image in pixels
|
|
xWidth = A4W / MM2IN * dpi
|
|
yWidth = A4H / MM2IN * dpi
|
|
# Marker width in pixels
|
|
mWidth = marker_width / MM2IN * dpi
|
|
|
|
e = mWidth - int(mWidth) # subpixel error in marker width
|
|
eMM = e / dpi * MM2IN # subpixel error in millimeters (report to user)
|
|
print 'Marker size finally set to', marker_width - eMM, 'mm'
|
|
|
|
# Converting pixel values to real integers
|
|
xWidth, yWidth, mWidth = int(xWidth), int(yWidth), int(mWidth)
|
|
return xWidth, yWidth, mWidth
|
|
|
|
def removeMarkers():
|
|
print 'Removing old markers...'
|
|
os.popen('rm ' + DESTINATION_DIR + '*.png') # Removing previous markers
|
|
|
|
def generateGrid():
|
|
'''
|
|
Generates a picture of a 9-point calibration grid using random markers, the size of which is
|
|
calculated such that after printing the marker size is of a specified length in millimeters
|
|
|
|
Usage: marker.py dpi marker_size_in_mm
|
|
'''
|
|
xWidth, yWidth, mWidth = computeDimensions()
|
|
|
|
# Create markers with this pixel size
|
|
removeMarkers()
|
|
print 'Generating new markers...'
|
|
generateRandomMarkers(9, mWidth)
|
|
|
|
# Stitch markers and generate grid
|
|
print 'Creating grid...'
|
|
markers = []
|
|
for f in os.listdir(DESTINATION_DIR):
|
|
if f.endswith('.png'):
|
|
markers.append(Image.open(f))
|
|
|
|
grid = Image.new("RGB", (xWidth, yWidth), (255, 255, 255))
|
|
for row in range(3):
|
|
if row == 0:
|
|
y = A4_PADDING_IN_PIXELS
|
|
elif row == 1:
|
|
y = (yWidth - mWidth) / 2
|
|
else:
|
|
y = yWidth - A4_PADDING_IN_PIXELS - mWidth
|
|
for col in range(3):
|
|
if col == 0:
|
|
x = A4_PADDING_IN_PIXELS
|
|
elif col == 1:
|
|
x = (xWidth - mWidth) / 2
|
|
else:
|
|
x = xWidth - A4_PADDING_IN_PIXELS - mWidth
|
|
|
|
grid.paste(markers[row*3+col], (x, y))
|
|
|
|
grid.save(DESTINATION_DIR + 'grid_board/grid.jpg')
|
|
print 'Finished.'
|
|
|
|
def generateRandomBoard():
|
|
xWidth, yWidth, mWidth = computeDimensions()
|
|
# Get number of random markers
|
|
try:
|
|
n = int(sys.argv[4])
|
|
assert n>0 and n<150 # no more than 150 markers allowed
|
|
except:
|
|
print 'Please choose between 1 to 20 markers'
|
|
return
|
|
|
|
# Create markers with this pixel size
|
|
removeMarkers()
|
|
print 'Generating new markers...'
|
|
generateRandomMarkers(n, mWidth)
|
|
|
|
# Stitch markers and generate board
|
|
print 'Creating board...'
|
|
markers = []
|
|
for f in os.listdir(DESTINATION_DIR):
|
|
if f.endswith('.png'):
|
|
markers.append(Image.open(f))
|
|
|
|
board = Image.new("RGB", (xWidth, yWidth), (255, 255, 255))
|
|
# Now we have to randomly append markers to board in a way that they do not collide
|
|
# To simplify this, we gridify the image based on marker size and choose a random sample
|
|
# of grids (not entirely random but in case markers are small enough it gives a good sample)
|
|
w = (xWidth - 2*A4_PADDING_IN_PIXELS) / mWidth
|
|
h = (yWidth - 2*A4_PADDING_IN_PIXELS) / mWidth
|
|
w, h = int(w), int(h) # w and h are maximum row and column size for the grid
|
|
# Now markers would take w*mWidth pixels in a row with no borders, applying border size:
|
|
w = ((xWidth - 2*A4_PADDING_IN_PIXELS) - (w-1)*DEFAULT_MARKER_BORDER_IN_PIXELS) / mWidth
|
|
h = ((yWidth - 2*A4_PADDING_IN_PIXELS) - (h-1)*DEFAULT_MARKER_BORDER_IN_PIXELS) / mWidth
|
|
w, h = int(w), int(h) # w and h now also count for marker borders
|
|
|
|
xOffset = A4_PADDING_IN_PIXELS + ((xWidth - 2*A4_PADDING_IN_PIXELS) - w*mWidth - (w-1)*DEFAULT_MARKER_BORDER_IN_PIXELS)/2
|
|
yOffset = A4_PADDING_IN_PIXELS + ((yWidth - 2*A4_PADDING_IN_PIXELS) - h*mWidth - (h-1)*DEFAULT_MARKER_BORDER_IN_PIXELS)/2
|
|
grids = [(xOffset + c*mWidth + c*DEFAULT_MARKER_BORDER_IN_PIXELS,
|
|
yOffset + r*mWidth + r*DEFAULT_MARKER_BORDER_IN_PIXELS) for r in xrange(h) for c in xrange(w)]
|
|
print len(grids), 'possible positions exist for markers...'
|
|
|
|
n = min(n, len(grids))
|
|
for i, pos in enumerate(sample(grids, n)):
|
|
board.paste(markers[i], pos)
|
|
|
|
board.save(DESTINATION_DIR + 'random_board/board.jpg')
|
|
print 'Finished.'
|
|
|
|
def main():
|
|
assert len(sys.argv) > 1, 'Invalid number of arguments.'
|
|
|
|
if sys.argv[1] == 'grid':
|
|
generateGrid()
|
|
elif sys.argv[1] == 'rand':
|
|
generateRandomBoard()
|
|
else:
|
|
handleMarkers()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main() |