#!/usr/bin/env python
'''
Simple example of stereo image matching and point cloud generation.
Resulting .ply file cam be easily viewed using MeshLab ( http://m...content-available-to-author-only...e.net/ )
'''
import numpy as np
import cv2
ply_header = '''ply
format ascii 1.0
element vertex %(vert_num)d
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
end_header
'''
def write_ply( fn, verts, colors) :
verts = verts.reshape ( -1 , 3 )
colors = colors.reshape ( -1 , 3 )
verts = np.hstack ( [ verts, colors] )
with open ( fn, 'w' ) as f:
f.write ( ply_header % dict ( vert_num= len ( verts) ) )
np.savetxt ( f, verts, '%f %f %f %d %d %d' )
if __name__ == '__main__' :
print 'loading images...'
imgL = cv2.pyrDown ( cv2.imread ( '../gpu/aloeL.jpg' ) ) # downscale images for faster processing
imgR = cv2.pyrDown ( cv2.imread ( '../gpu/aloeR.jpg' ) )
# disparity range is tuned for 'aloe' image pair
window_size = 3
min_disp = 16
num_disp = 112 -min_disp
stereo = cv2.StereoSGBM ( minDisparity = min_disp,
numDisparities = num_disp,
SADWindowSize = window_size,
uniquenessRatio = 10 ,
speckleWindowSize = 100 ,
speckleRange = 32 ,
disp12MaxDiff = 1 ,
P1 = 8 *3 *window_size**2 ,
P2 = 32 *3 *window_size**2 ,
fullDP = False
)
print 'computing disparity...'
disp = stereo.compute ( imgL, imgR) .astype ( np.float32 ) / 16.0
print 'generating 3d point cloud...' ,
h, w = imgL.shape [ :2 ]
f = 0.8 *w # guess for focal length
Q = np.float32 ( [ [ 1 , 0 , 0 , -0.5 *w] ,
[ 0 , -1 , 0 , 0.5 *h] , # turn points 180 deg around x-axis,
[ 0 , 0 , 0 , -f] , # so that y-axis looks up
[ 0 , 0 , 1 , 0 ] ] )
points = cv2.reprojectImageTo3D ( disp, Q)
colors = cv2.cvtColor ( imgL, cv2.COLOR_BGR2RGB )
mask = disp > disp.min ( )
out_points = points[ mask]
out_colors = colors[ mask]
out_fn = 'out.ply'
write_ply( 'out.ply' , out_points, out_colors)
print '%s saved' % 'out.ply'
cv2.imshow ( 'left' , imgL)
cv2.imshow ( 'disparity' , ( disp-min_disp) /num_disp)
cv2.waitKey ( )
cv2.destroyAllWindows ( )
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uCiAKCiAKJycnCiAKU2ltcGxlIGV4YW1wbGUgb2Ygc3RlcmVvIGltYWdlIG1hdGNoaW5nIGFuZCBwb2ludCBjbG91ZCBnZW5lcmF0aW9uLgogCgogClJlc3VsdGluZyAucGx5IGZpbGUgY2FtIGJlIGVhc2lseSB2aWV3ZWQgdXNpbmcgTWVzaExhYiAoIGh0dHA6Ly9tLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5lLm5ldC8gKQogCicnJwogCgogCmltcG9ydCBudW1weSBhcyBucAogCmltcG9ydCBjdjIKIAoKIApwbHlfaGVhZGVyID0gJycncGx5CiAKZm9ybWF0IGFzY2lpIDEuMAogCmVsZW1lbnQgdmVydGV4ICUodmVydF9udW0pZAogCnByb3BlcnR5IGZsb2F0IHgKIApwcm9wZXJ0eSBmbG9hdCB5CiAKcHJvcGVydHkgZmxvYXQgegogCnByb3BlcnR5IHVjaGFyIHJlZAogCnByb3BlcnR5IHVjaGFyIGdyZWVuCiAKcHJvcGVydHkgdWNoYXIgYmx1ZQogCmVuZF9oZWFkZXIKIAonJycKIAoKIApkZWYgd3JpdGVfcGx5KGZuLCB2ZXJ0cywgY29sb3JzKToKIAogICAgdmVydHMgPSB2ZXJ0cy5yZXNoYXBlKC0xLCAzKQogCiAgICBjb2xvcnMgPSBjb2xvcnMucmVzaGFwZSgtMSwgMykKIAogICAgdmVydHMgPSBucC5oc3RhY2soW3ZlcnRzLCBjb2xvcnNdKQogCiAgICB3aXRoIG9wZW4oZm4sICd3JykgYXMgZjoKIAogICAgICAgIGYud3JpdGUocGx5X2hlYWRlciAlIGRpY3QodmVydF9udW09bGVuKHZlcnRzKSkpCiAKICAgICAgICBucC5zYXZldHh0KGYsIHZlcnRzLCAnJWYgJWYgJWYgJWQgJWQgJWQnKQogCgogCgogCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAKICAgIHByaW50ICdsb2FkaW5nIGltYWdlcy4uLicKIAogICAgaW1nTCA9IGN2Mi5weXJEb3duKCBjdjIuaW1yZWFkKCcuLi9ncHUvYWxvZUwuanBnJykgKSAgIyBkb3duc2NhbGUgaW1hZ2VzIGZvciBmYXN0ZXIgcHJvY2Vzc2luZwogCiAgICBpbWdSID0gY3YyLnB5ckRvd24oIGN2Mi5pbXJlYWQoJy4uL2dwdS9hbG9lUi5qcGcnKSApCiAKCiAKICAgICMgZGlzcGFyaXR5IHJhbmdlIGlzIHR1bmVkIGZvciAnYWxvZScgaW1hZ2UgcGFpcgogCiAgICB3aW5kb3dfc2l6ZSA9IDMKIAogICAgbWluX2Rpc3AgPSAxNgogCiAgICBudW1fZGlzcCA9IDExMi1taW5fZGlzcAogCiAgICBzdGVyZW8gPSBjdjIuU3RlcmVvU0dCTShtaW5EaXNwYXJpdHkgPSBtaW5fZGlzcCwKIAogICAgICAgIG51bURpc3Bhcml0aWVzID0gbnVtX2Rpc3AsCiAKICAgICAgICBTQURXaW5kb3dTaXplID0gd2luZG93X3NpemUsCiAKICAgICAgICB1bmlxdWVuZXNzUmF0aW8gPSAxMCwKIAogICAgICAgIHNwZWNrbGVXaW5kb3dTaXplID0gMTAwLAogCiAgICAgICAgc3BlY2tsZVJhbmdlID0gMzIsCiAKICAgICAgICBkaXNwMTJNYXhEaWZmID0gMSwKIAogICAgICAgIFAxID0gOCozKndpbmRvd19zaXplKioyLAogCiAgICAgICAgUDIgPSAzMiozKndpbmRvd19zaXplKioyLAogCiAgICAgICAgZnVsbERQID0gRmFsc2UKIAogICAgKQogCgogCiAgICBwcmludCAnY29tcHV0aW5nIGRpc3Bhcml0eS4uLicKIAogICAgZGlzcCA9IHN0ZXJlby5jb21wdXRlKGltZ0wsIGltZ1IpLmFzdHlwZShucC5mbG9hdDMyKSAvIDE2LjAKIAoKIAogICAgcHJpbnQgJ2dlbmVyYXRpbmcgM2QgcG9pbnQgY2xvdWQuLi4nLAogCiAgICBoLCB3ID0gaW1nTC5zaGFwZVs6Ml0KIAogICAgZiA9IDAuOCp3ICAgICAgICAgICAgICAgICAgICAgICAgICAjIGd1ZXNzIGZvciBmb2NhbCBsZW5ndGgKIAogICAgUSA9IG5wLmZsb2F0MzIoW1sxLCAwLCAwLCAtMC41KnddLAogCiAgICAgICAgICAgICAgICAgICAgWzAsLTEsIDAsICAwLjUqaF0sICMgdHVybiBwb2ludHMgMTgwIGRlZyBhcm91bmQgeC1heGlzLAogCiAgICAgICAgICAgICAgICAgICAgWzAsIDAsIDAsICAgICAtZl0sICMgc28gdGhhdCB5LWF4aXMgbG9va3MgdXAKIAogICAgICAgICAgICAgICAgICAgIFswLCAwLCAxLCAgICAgIDBdXSkKIAogICAgcG9pbnRzID0gY3YyLnJlcHJvamVjdEltYWdlVG8zRChkaXNwLCBRKQogCiAgICBjb2xvcnMgPSBjdjIuY3Z0Q29sb3IoaW1nTCwgY3YyLkNPTE9SX0JHUjJSR0IpCiAKICAgIG1hc2sgPSBkaXNwID4gZGlzcC5taW4oKQogCiAgICBvdXRfcG9pbnRzID0gcG9pbnRzW21hc2tdCiAKICAgIG91dF9jb2xvcnMgPSBjb2xvcnNbbWFza10KIAogICAgb3V0X2ZuID0gJ291dC5wbHknCiAKICAgIHdyaXRlX3BseSgnb3V0LnBseScsIG91dF9wb2ludHMsIG91dF9jb2xvcnMpCiAKICAgIHByaW50ICclcyBzYXZlZCcgJSAnb3V0LnBseScKIAoKIAogICAgY3YyLmltc2hvdygnbGVmdCcsIGltZ0wpCiAKICAgIGN2Mi5pbXNob3coJ2Rpc3Bhcml0eScsIChkaXNwLW1pbl9kaXNwKS9udW1fZGlzcCkKIAogICAgY3YyLndhaXRLZXkoKQogCiAgICBjdjIuZGVzdHJveUFsbFdpbmRvd3MoKQogCg==