Mercurial > hg > nsaunier > traffic-intelligence
comparison python/cvutils.py @ 795:a34ec862371f
merged with dev branch
| author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
|---|---|
| date | Mon, 09 May 2016 15:33:11 -0400 |
| parents | 5b970a5bc233 |
| children | 5b99b676265e |
comparison
equal
deleted
inserted
replaced
| 758:0a05883216cf | 795:a34ec862371f |
|---|---|
| 1 #! /usr/bin/env python | 1 #! /usr/bin/env python |
| 2 '''Image/Video utilities''' | 2 '''Image/Video utilities''' |
| 3 | 3 |
| 4 import utils | 4 import utils, moving |
| 5 | 5 |
| 6 try: | 6 try: |
| 7 import cv2 | 7 import cv2 |
| 8 opencvAvailable = True | 8 opencvAvailable = True |
| 9 except ImportError: | 9 except ImportError: |
| 14 skimageAvailable = True | 14 skimageAvailable = True |
| 15 except ImportError: | 15 except ImportError: |
| 16 print('Scikit-image library could not be loaded (HoG-based classification methods will not be available)') | 16 print('Scikit-image library could not be loaded (HoG-based classification methods will not be available)') |
| 17 skimageAvailable = False | 17 skimageAvailable = False |
| 18 | 18 |
| 19 from sys import stdout | 19 from sys import stdout, maxint |
| 20 from numpy import dot, array, append, float32 | 20 from os import listdir |
| 21 from copy import deepcopy | |
| 22 from math import floor, log10, ceil | |
| 23 | |
| 24 from numpy import dot, array, append, float32, loadtxt, savetxt, append, zeros, ones, identity, abs as npabs, logical_and, unravel_index, sum as npsum, isnan, mgrid, median, floor as npfloor, ceil as npceil | |
| 25 from matplotlib.mlab import find | |
| 26 from matplotlib.pyplot import imread, imsave | |
| 27 | |
| 28 | |
| 21 | 29 |
| 22 #import aggdraw # agg on top of PIL (antialiased drawing) | 30 #import aggdraw # agg on top of PIL (antialiased drawing) |
| 23 | 31 |
| 24 | 32 |
| 25 cvRed = (0,0,255) | 33 cvRed = (0,0,255) |
| 75 return dot(rgb[...,:3], [0.299, 0.587, 0.144]) | 83 return dot(rgb[...,:3], [0.299, 0.587, 0.144]) |
| 76 | 84 |
| 77 def matlab2PointCorrespondences(filename): | 85 def matlab2PointCorrespondences(filename): |
| 78 '''Loads and converts the point correspondences saved | 86 '''Loads and converts the point correspondences saved |
| 79 by the matlab camera calibration tool''' | 87 by the matlab camera calibration tool''' |
| 80 from numpy.lib.io import loadtxt, savetxt | |
| 81 from numpy.lib.function_base import append | |
| 82 points = loadtxt(filename, delimiter=',') | 88 points = loadtxt(filename, delimiter=',') |
| 83 savetxt(utils.removeExtension(filename)+'-point-correspondences.txt',append(points[:,:2].T, points[:,3:].T, axis=0)) | 89 savetxt(utils.removeExtension(filename)+'-point-correspondences.txt',append(points[:,:2].T, points[:,3:].T, axis=0)) |
| 84 | 90 |
| 85 def loadPointCorrespondences(filename): | 91 def loadPointCorrespondences(filename): |
| 86 '''Loads and returns the corresponding points in world (first 2 lines) and image spaces (last 2 lines)''' | 92 '''Loads and returns the corresponding points in world (first 2 lines) and image spaces (last 2 lines)''' |
| 87 from numpy import loadtxt, float32 | |
| 88 points = loadtxt(filename, dtype=float32) | 93 points = loadtxt(filename, dtype=float32) |
| 89 return (points[:2,:].T, points[2:,:].T) # (world points, image points) | 94 return (points[:2,:].T, points[2:,:].T) # (world points, image points) |
| 90 | 95 |
| 91 def cvMatToArray(cvmat): | 96 def cvMatToArray(cvmat): |
| 92 '''Converts an OpenCV CvMat to numpy array.''' | 97 '''Converts an OpenCV CvMat to numpy array.''' |
| 93 print('Deprecated, use new interface') | 98 print('Deprecated, use new interface') |
| 94 from numpy import zeros | |
| 95 a = zeros((cvmat.rows, cvmat.cols))#array([[0.0]*cvmat.width]*cvmat.height) | 99 a = zeros((cvmat.rows, cvmat.cols))#array([[0.0]*cvmat.width]*cvmat.height) |
| 96 for i in xrange(cvmat.rows): | 100 for i in xrange(cvmat.rows): |
| 97 for j in xrange(cvmat.cols): | 101 for j in xrange(cvmat.cols): |
| 98 a[i,j] = cvmat[i,j] | 102 a[i,j] = cvmat[i,j] |
| 99 return a | 103 return a |
| 104 | |
| 105 def createWhiteImage(height, width, filename): | |
| 106 img = ones((height, width, 3), uint8)*255 | |
| 107 imsave(filename, img) | |
| 100 | 108 |
| 101 if opencvAvailable: | 109 if opencvAvailable: |
| 102 def computeHomography(srcPoints, dstPoints, method=0, ransacReprojThreshold=3.0): | 110 def computeHomography(srcPoints, dstPoints, method=0, ransacReprojThreshold=3.0): |
| 103 '''Returns the homography matrix mapping from srcPoints to dstPoints (dimension Nx2)''' | 111 '''Returns the homography matrix mapping from srcPoints to dstPoints (dimension Nx2)''' |
| 104 H, mask = cv2.findHomography(srcPoints, dstPoints, method, ransacReprojThreshold) | 112 H, mask = cv2.findHomography(srcPoints, dstPoints, method, ransacReprojThreshold) |
| 130 cv2.imshow(windowName, resizedImg) | 138 cv2.imshow(windowName, resizedImg) |
| 131 else: | 139 else: |
| 132 cv2.imshow(windowName, img) | 140 cv2.imshow(windowName, img) |
| 133 | 141 |
| 134 def computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients): | 142 def computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients): |
| 135 from copy import deepcopy | |
| 136 from numpy import identity | |
| 137 newImgSize = (int(round(width*undistortedImageMultiplication)), int(round(height*undistortedImageMultiplication))) | 143 newImgSize = (int(round(width*undistortedImageMultiplication)), int(round(height*undistortedImageMultiplication))) |
| 138 newCameraMatrix = deepcopy(intrinsicCameraMatrix) | 144 newCameraMatrix = deepcopy(intrinsicCameraMatrix) |
| 139 newCameraMatrix[0,2] = newImgSize[0]/2. | 145 newCameraMatrix[0,2] = newImgSize[0]/2. |
| 140 newCameraMatrix[1,2] = newImgSize[1]/2. | 146 newCameraMatrix[1,2] = newImgSize[1]/2. |
| 141 return cv2.initUndistortRectifyMap(intrinsicCameraMatrix, array(distortionCoefficients), identity(3), newCameraMatrix, newImgSize, cv2.CV_32FC1) | 147 return cv2.initUndistortRectifyMap(intrinsicCameraMatrix, array(distortionCoefficients), identity(3), newCameraMatrix, newImgSize, cv2.CV_32FC1) |
| 153 capture = cv2.VideoCapture(filename) | 159 capture = cv2.VideoCapture(filename) |
| 154 if capture.isOpened(): | 160 if capture.isOpened(): |
| 155 key = -1 | 161 key = -1 |
| 156 ret = True | 162 ret = True |
| 157 frameNum = firstFrameNum | 163 frameNum = firstFrameNum |
| 158 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) | 164 capture.set(cv2.CAP_PROP_POS_FRAMES, firstFrameNum) |
| 159 while ret and not quitKey(key): | 165 while ret and not quitKey(key): |
| 160 #ret, img = capture.read() | 166 #ret, img = capture.read() |
| 161 for i in xrange(step): | 167 for i in xrange(step): |
| 162 ret, img = capture.read() | 168 ret, img = capture.read() |
| 163 if ret: | 169 if ret: |
| 164 if printFrames: | 170 if printFrames: |
| 165 print('frame {0}'.format(frameNum)) | 171 print('frame {0}'.format(frameNum)) |
| 166 frameNum+=step | 172 frameNum+=step |
| 167 if text is not None: | 173 if text is not None: |
| 168 cv2.putText(img, text, (10,50), cv2.cv.CV_FONT_HERSHEY_PLAIN, 1, cvRed) | 174 cv2.putText(img, text, (10,50), cv2.FONT_HERSHEY_PLAIN, 1, cvRed) |
| 169 cvImshow(windowName, img, rescale) | 175 cvImshow(windowName, img, rescale) |
| 170 key = cv2.waitKey(wait) | 176 key = cv2.waitKey(wait) |
| 171 if saveKey(key): | 177 if saveKey(key): |
| 172 cv2.imwrite('image-{}.png'.format(frameNum), img) | 178 cv2.imwrite('image-{}.png'.format(frameNum), img) |
| 173 cv2.destroyAllWindows() | 179 cv2.destroyAllWindows() |
| 174 else: | 180 else: |
| 175 print('Video capture for {} failed'.format(filename)) | 181 print('Video capture for {} failed'.format(filename)) |
| 176 | 182 |
| 177 def infoVideo(filename): | 183 def infoVideo(filename): |
| 178 '''Provides all available info on video ''' | 184 '''Provides all available info on video ''' |
| 179 cvPropertyNames = {cv2.cv.CV_CAP_PROP_FORMAT: "format", | 185 cvPropertyNames = {cv2.CAP_PROP_FORMAT: "format", |
| 180 cv2.cv.CV_CAP_PROP_FOURCC: "codec (fourcc)", | 186 cv2.CAP_PROP_FOURCC: "codec (fourcc)", |
| 181 cv2.cv.CV_CAP_PROP_FPS: "fps", | 187 cv2.CAP_PROP_FPS: "fps", |
| 182 cv2.cv.CV_CAP_PROP_FRAME_COUNT: "number of frames", | 188 cv2.CAP_PROP_FRAME_COUNT: "number of frames", |
| 183 cv2.cv.CV_CAP_PROP_FRAME_HEIGHT: "heigh", | 189 cv2.CAP_PROP_FRAME_HEIGHT: "heigh", |
| 184 cv2.cv.CV_CAP_PROP_FRAME_WIDTH: "width", | 190 cv2.CAP_PROP_FRAME_WIDTH: "width", |
| 185 cv2.cv.CV_CAP_PROP_RECTIFICATION: "rectification", | 191 cv2.CAP_PROP_RECTIFICATION: "rectification", |
| 186 cv2.cv.CV_CAP_PROP_SATURATION: "saturation"} | 192 cv2.CAP_PROP_SATURATION: "saturation"} |
| 187 capture = cv2.VideoCapture(filename) | 193 capture = cv2.VideoCapture(filename) |
| 188 if capture.isOpened(): | 194 if capture.isOpened(): |
| 189 for cvprop in [#cv2.cv.CV_CAP_PROP_BRIGHTNESS | 195 for cvprop in [#cv2.CAP_PROP_BRIGHTNESS |
| 190 #cv2.cv.CV_CAP_PROP_CONTRAST | 196 #cv2.CAP_PROP_CONTRAST |
| 191 #cv2.cv.CV_CAP_PROP_CONVERT_RGB | 197 #cv2.CAP_PROP_CONVERT_RGB |
| 192 #cv2.cv.CV_CAP_PROP_EXPOSURE | 198 #cv2.CAP_PROP_EXPOSURE |
| 193 cv2.cv.CV_CAP_PROP_FORMAT, | 199 cv2.CAP_PROP_FORMAT, |
| 194 cv2.cv.CV_CAP_PROP_FOURCC, | 200 cv2.CAP_PROP_FOURCC, |
| 195 cv2.cv.CV_CAP_PROP_FPS, | 201 cv2.CAP_PROP_FPS, |
| 196 cv2.cv.CV_CAP_PROP_FRAME_COUNT, | 202 cv2.CAP_PROP_FRAME_COUNT, |
| 197 cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, | 203 cv2.CAP_PROP_FRAME_HEIGHT, |
| 198 cv2.cv.CV_CAP_PROP_FRAME_WIDTH, | 204 cv2.CAP_PROP_FRAME_WIDTH, |
| 199 #cv2.cv.CV_CAP_PROP_GAIN, | 205 #cv2.CAP_PROP_GAIN, |
| 200 #cv2.cv.CV_CAP_PROP_HUE | 206 #cv2.CAP_PROP_HUE |
| 201 #cv2.cv.CV_CAP_PROP_MODE | 207 #cv2.CAP_PROP_MODE |
| 202 #cv2.cv.CV_CAP_PROP_POS_AVI_RATIO | 208 #cv2.CAP_PROP_POS_AVI_RATIO |
| 203 #cv2.cv.CV_CAP_PROP_POS_FRAMES | 209 #cv2.CAP_PROP_POS_FRAMES |
| 204 #cv2.cv.CV_CAP_PROP_POS_MSEC | 210 #cv2.CAP_PROP_POS_MSEC |
| 205 #cv2.cv.CV_CAP_PROP_RECTIFICATION, | 211 #cv2.CAP_PROP_RECTIFICATION, |
| 206 #cv2.cv.CV_CAP_PROP_SATURATION | 212 #cv2.CAP_PROP_SATURATION |
| 207 ]: | 213 ]: |
| 208 prop = capture.get(cvprop) | 214 prop = capture.get(cvprop) |
| 209 if cvprop == cv2.cv.CV_CAP_PROP_FOURCC and prop > 0: | 215 if cvprop == cv2.CAP_PROP_FOURCC and prop > 0: |
| 210 prop = int2FOURCC(int(prop)) | 216 prop = int2FOURCC(int(prop)) |
| 211 print('Video {}: {}'.format(cvPropertyNames[cvprop], prop)) | 217 print('Video {}: {}'.format(cvPropertyNames[cvprop], prop)) |
| 212 else: | 218 else: |
| 213 print('Video capture for {} failed'.format(filename)) | 219 print('Video capture for {} failed'.format(filename)) |
| 214 | 220 |
| 215 def getImagesFromVideo(videoFilename, firstFrameNum = 0, nFrames = 1, saveImage = False, outputPrefix = 'image'): | 221 def getImagesFromVideo(videoFilename, firstFrameNum = 0, nFrames = 1, saveImage = False, outputPrefix = 'image'): |
| 216 '''Returns nFrames images from the video sequence''' | 222 '''Returns nFrames images from the video sequence''' |
| 217 from math import floor, log10 | |
| 218 images = [] | 223 images = [] |
| 219 capture = cv2.VideoCapture(videoFilename) | 224 capture = cv2.VideoCapture(videoFilename) |
| 220 if capture.isOpened(): | 225 if capture.isOpened(): |
| 221 rawCount = capture.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT) | 226 rawCount = capture.get(cv2.CAP_PROP_FRAME_COUNT) |
| 222 if rawCount < 0: | 227 if rawCount < 0: |
| 223 rawCount = firstFrameNum+nFrames+1 | 228 rawCount = firstFrameNum+nFrames+1 |
| 224 nDigits = int(floor(log10(rawCount)))+1 | 229 nDigits = int(floor(log10(rawCount)))+1 |
| 225 ret = False | 230 ret = False |
| 226 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) | 231 capture.set(cv2.CAP_PROP_POS_FRAMES, firstFrameNum) |
| 227 imgNum = 0 | 232 imgNum = 0 |
| 228 while imgNum<nFrames: | 233 while imgNum<nFrames: |
| 229 ret, img = capture.read() | 234 ret, img = capture.read() |
| 230 i = 0 | 235 i = 0 |
| 231 while not ret and i<10: | 236 while not ret and i<10: |
| 244 return images | 249 return images |
| 245 | 250 |
| 246 def getFPS(videoFilename): | 251 def getFPS(videoFilename): |
| 247 capture = cv2.VideoCapture(videoFilename) | 252 capture = cv2.VideoCapture(videoFilename) |
| 248 if capture.isOpened(): | 253 if capture.isOpened(): |
| 249 fps = capture.get(cv2.cv.CV_CAP_PROP_FPS) | 254 fps = capture.get(cv2.CAP_PROP_FPS) |
| 250 capture.release() | 255 capture.release() |
| 251 return fps | 256 return fps |
| 252 else: | 257 else: |
| 253 print('Video capture for {} failed'.format(videoFilename)) | 258 print('Video capture for {} failed'.format(videoFilename)) |
| 254 return None | 259 return None |
| 281 return croppedImg, yCropMin, yCropMax, xCropMin, xCropMax | 286 return croppedImg, yCropMin, yCropMax, xCropMin, xCropMax |
| 282 | 287 |
| 283 | 288 |
| 284 def displayTrajectories(videoFilename, objects, boundingBoxes = {}, homography = None, firstFrameNum = 0, lastFrameNumArg = None, printFrames = True, rescale = 1., nFramesStep = 1, saveAllImages = False, undistort = False, intrinsicCameraMatrix = None, distortionCoefficients = None, undistortedImageMultiplication = 1., annotations = [], gtMatches = {}, toMatches = {}): | 289 def displayTrajectories(videoFilename, objects, boundingBoxes = {}, homography = None, firstFrameNum = 0, lastFrameNumArg = None, printFrames = True, rescale = 1., nFramesStep = 1, saveAllImages = False, undistort = False, intrinsicCameraMatrix = None, distortionCoefficients = None, undistortedImageMultiplication = 1., annotations = [], gtMatches = {}, toMatches = {}): |
| 285 '''Displays the objects overlaid frame by frame over the video ''' | 290 '''Displays the objects overlaid frame by frame over the video ''' |
| 286 from moving import userTypeNames | |
| 287 from math import ceil, log10 | |
| 288 | |
| 289 capture = cv2.VideoCapture(videoFilename) | 291 capture = cv2.VideoCapture(videoFilename) |
| 290 width = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)) | 292 width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)) |
| 291 height = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)) | 293 height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
| 292 | 294 |
| 293 windowName = 'frame' | 295 windowName = 'frame' |
| 294 if rescale == 1.: | 296 if rescale == 1.: |
| 295 cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) | 297 cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) |
| 296 | 298 |
| 298 [map1, map2] = computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients) | 300 [map1, map2] = computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients) |
| 299 if capture.isOpened(): | 301 if capture.isOpened(): |
| 300 key = -1 | 302 key = -1 |
| 301 ret = True | 303 ret = True |
| 302 frameNum = firstFrameNum | 304 frameNum = firstFrameNum |
| 303 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) | 305 capture.set(cv2.CAP_PROP_POS_FRAMES, firstFrameNum) |
| 304 if lastFrameNumArg is None: | 306 if lastFrameNumArg is None: |
| 305 from sys import maxint | |
| 306 lastFrameNum = maxint | 307 lastFrameNum = maxint |
| 307 else: | 308 else: |
| 308 lastFrameNum = lastFrameNumArg | 309 lastFrameNum = lastFrameNumArg |
| 309 nZerosFilename = int(ceil(log10(lastFrameNum))) | 310 nZerosFilename = int(ceil(log10(lastFrameNum))) |
| 310 objectToDeleteIds = [] | 311 objectToDeleteIds = [] |
| 331 cvPlot(img, obj.projectedPositions, cvColors[obj.getNum()], frameNum-obj.getFirstInstant()) | 332 cvPlot(img, obj.projectedPositions, cvColors[obj.getNum()], frameNum-obj.getFirstInstant()) |
| 332 if frameNum not in boundingBoxes.keys() and obj.hasFeatures(): | 333 if frameNum not in boundingBoxes.keys() and obj.hasFeatures(): |
| 333 imgcrop, yCropMin, yCropMax, xCropMin, xCropMax = imageBox(img, obj, frameNum, homography, width, height) | 334 imgcrop, yCropMin, yCropMax, xCropMin, xCropMax = imageBox(img, obj, frameNum, homography, width, height) |
| 334 cv2.rectangle(img, (xCropMin, yCropMin), (xCropMax, yCropMax), cvBlue, 1) | 335 cv2.rectangle(img, (xCropMin, yCropMin), (xCropMax, yCropMax), cvBlue, 1) |
| 335 objDescription = '{} '.format(obj.num) | 336 objDescription = '{} '.format(obj.num) |
| 336 if userTypeNames[obj.userType] != 'unknown': | 337 if moving.userTypeNames[obj.userType] != 'unknown': |
| 337 objDescription += userTypeNames[obj.userType][0].upper() | 338 objDescription += moving.userTypeNames[obj.userType][0].upper() |
| 338 if len(annotations) > 0: # if we loaded annotations, but there is no match | 339 if len(annotations) > 0: # if we loaded annotations, but there is no match |
| 339 if frameNum not in toMatches[obj.getNum()]: | 340 if frameNum not in toMatches[obj.getNum()]: |
| 340 objDescription += " FA" | 341 objDescription += " FA" |
| 341 cv2.putText(img, objDescription, obj.projectedPositions[frameNum-obj.getFirstInstant()].asint().astuple(), cv2.cv.CV_FONT_HERSHEY_PLAIN, 1, cvColors[obj.getNum()]) | 342 cv2.putText(img, objDescription, obj.projectedPositions[frameNum-obj.getFirstInstant()].asint().astuple(), cv2.FONT_HERSHEY_PLAIN, 1, cvColors[obj.getNum()]) |
| 342 # plot object bounding boxes | 343 # plot object bounding boxes |
| 343 if frameNum in boundingBoxes.keys(): | 344 if frameNum in boundingBoxes.keys(): |
| 344 for rect in boundingBoxes[frameNum]: | 345 for rect in boundingBoxes[frameNum]: |
| 345 cv2.rectangle(img, rect[0].asint().astuple(), rect[1].asint().astuple(), cvColors[obj.getNum()]) | 346 cv2.rectangle(img, rect[0].asint().astuple(), rect[1].asint().astuple(), cvColors[obj.getNum()]) |
| 346 # plot ground truth | 347 # plot ground truth |
| 349 if gt.existsAtInstant(frameNum): | 350 if gt.existsAtInstant(frameNum): |
| 350 if frameNum in gtMatches[gt.getNum()]: | 351 if frameNum in gtMatches[gt.getNum()]: |
| 351 color = cvColors[gtMatches[gt.getNum()][frameNum]] # same color as object | 352 color = cvColors[gtMatches[gt.getNum()][frameNum]] # same color as object |
| 352 else: | 353 else: |
| 353 color = cvRed | 354 color = cvRed |
| 354 cv2.putText(img, 'Miss', gt.topLeftPositions[frameNum-gt.getFirstInstant()].asint().astuple(), cv2.cv.CV_FONT_HERSHEY_PLAIN, 1, cvRed) | 355 cv2.putText(img, 'Miss', gt.topLeftPositions[frameNum-gt.getFirstInstant()].asint().astuple(), cv2.FONT_HERSHEY_PLAIN, 1, cvRed) |
| 355 cv2.rectangle(img, gt.topLeftPositions[frameNum-gt.getFirstInstant()].asint().astuple(), gt.bottomRightPositions[frameNum-gt.getFirstInstant()].asint().astuple(), color) | 356 cv2.rectangle(img, gt.topLeftPositions[frameNum-gt.getFirstInstant()].asint().astuple(), gt.bottomRightPositions[frameNum-gt.getFirstInstant()].asint().astuple(), color) |
| 356 # saving images and going to next | 357 # saving images and going to next |
| 357 if not saveAllImages: | 358 if not saveAllImages: |
| 358 cvImshow(windowName, img, rescale) | 359 cvImshow(windowName, img, rescale) |
| 359 key = cv2.waitKey() | 360 key = cv2.waitKey() |
| 360 if saveAllImages or saveKey(key): | 361 if saveAllImages or saveKey(key): |
| 361 cv2.imwrite('image-{{:0{}}}.png'.format(nZerosFilename).format(frameNum), img) | 362 cv2.imwrite('image-{{:0{}}}.png'.format(nZerosFilename).format(frameNum), img) |
| 362 frameNum += nFramesStep | 363 frameNum += nFramesStep |
| 363 if nFramesStep > 1: | 364 if nFramesStep > 1: |
| 364 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, frameNum) | 365 capture.set(cv2.CAP_PROP_POS_FRAMES, frameNum) |
| 365 cv2.destroyAllWindows() | 366 cv2.destroyAllWindows() |
| 366 else: | 367 else: |
| 367 print 'Cannot load file ' + videoFilename | 368 print('Cannot load file ' + videoFilename) |
| 368 | 369 |
| 369 def computeHomographyFromPDTV(camera): | 370 def computeHomographyFromPDTV(camera): |
| 370 '''Returns the homography matrix at ground level from PDTV camera | 371 '''Returns the homography matrix at ground level from PDTV camera |
| 371 https://bitbucket.org/hakanardo/pdtv''' | 372 https://bitbucket.org/hakanardo/pdtv''' |
| 372 # camera = pdtv.load(cameraFilename) | 373 # camera = pdtv.load(cameraFilename) |
| 381 def undistortedCoordinates(map1, map2, x, y, maxDistance = 1.): | 382 def undistortedCoordinates(map1, map2, x, y, maxDistance = 1.): |
| 382 '''Returns the coordinates of a point in undistorted image | 383 '''Returns the coordinates of a point in undistorted image |
| 383 map1 and map2 are the mapping functions from undistorted image | 384 map1 and map2 are the mapping functions from undistorted image |
| 384 to distorted (original image) | 385 to distorted (original image) |
| 385 map1(x,y) = originalx, originaly''' | 386 map1(x,y) = originalx, originaly''' |
| 386 from numpy import abs, logical_and, unravel_index, sum | 387 distx = npabs(map1-x) |
| 387 from matplotlib.mlab import find | 388 disty = npabs(map2-y) |
| 388 distx = abs(map1-x) | |
| 389 disty = abs(map2-y) | |
| 390 indices = logical_and(distx<maxDistance, disty<maxDistance) | 389 indices = logical_and(distx<maxDistance, disty<maxDistance) |
| 391 closeCoordinates = unravel_index(find(indices), distx.shape) # returns i,j, ie y,x | 390 closeCoordinates = unravel_index(find(indices), distx.shape) # returns i,j, ie y,x |
| 392 xWeights = 1-distx[indices] | 391 xWeights = 1-distx[indices] |
| 393 yWeights = 1-disty[indices] | 392 yWeights = 1-disty[indices] |
| 394 return dot(xWeights, closeCoordinates[1])/sum(xWeights), dot(yWeights, closeCoordinates[0])/sum(yWeights) | 393 return dot(xWeights, closeCoordinates[1])/npsum(xWeights), dot(yWeights, closeCoordinates[0])/npsum(yWeights) |
| 395 | 394 |
| 396 def undistortTrajectoryFromCVMapping(map1, map2, t): | 395 def undistortTrajectoryFromCVMapping(map1, map2, t): |
| 397 '''test 'perfect' inversion''' | 396 '''test 'perfect' inversion''' |
| 398 from moving import Trajectory | 397 undistortedTrajectory = moving.Trajectory() |
| 399 from numpy import isnan | |
| 400 undistortedTrajectory = Trajectory() | |
| 401 for i,p in enumerate(t): | 398 for i,p in enumerate(t): |
| 402 res = undistortedCoordinates(map1, map2, p.x,p.y) | 399 res = undistortedCoordinates(map1, map2, p.x,p.y) |
| 403 if not isnan(res).any(): | 400 if not isnan(res).any(): |
| 404 undistortedTrajectory.addPositionXY(res[0], res[1]) | 401 undistortedTrajectory.addPositionXY(res[0], res[1]) |
| 405 else: | 402 else: |
| 406 print i,p,res | 403 print('{} {} {}'.format(i,p,res)) |
| 407 return undistortedTrajectory | 404 return undistortedTrajectory |
| 408 | 405 |
| 409 def computeInverseMapping(originalImageSize, map1, map2): | 406 def computeInverseMapping(originalImageSize, map1, map2): |
| 410 'Computes inverse mapping from maps provided by cv2.initUndistortRectifyMap' | 407 'Computes inverse mapping from maps provided by cv2.initUndistortRectifyMap' |
| 411 from numpy import ones, isnan | |
| 412 invMap1 = -ones(originalImageSize) | 408 invMap1 = -ones(originalImageSize) |
| 413 invMap2 = -ones(originalImageSize) | 409 invMap2 = -ones(originalImageSize) |
| 414 for x in range(0,originalImageSize[1]): | 410 for x in range(0,originalImageSize[1]): |
| 415 for y in range(0,originalImageSize[0]): | 411 for y in range(0,originalImageSize[0]): |
| 416 res = undistortedCoordinates(x,y, map1, map2) | 412 res = undistortedCoordinates(x,y, map1, map2) |
| 430 | 426 |
| 431 The code below is based off of: | 427 The code below is based off of: |
| 432 https://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html | 428 https://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html |
| 433 Modified by Paul St-Aubin | 429 Modified by Paul St-Aubin |
| 434 ''' | 430 ''' |
| 435 from numpy import zeros, mgrid, float32, savetxt | |
| 436 import glob, os | 431 import glob, os |
| 437 | 432 |
| 438 # termination criteria | 433 # termination criteria |
| 439 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) | 434 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) |
| 440 | 435 |
| 455 # Find the chess board corners | 450 # Find the chess board corners |
| 456 ret, corners = cv2.findChessboardCorners(gray, (checkerBoardSize[1],checkerBoardSize[0]), None) | 451 ret, corners = cv2.findChessboardCorners(gray, (checkerBoardSize[1],checkerBoardSize[0]), None) |
| 457 | 452 |
| 458 # If found, add object points, image points (after refining them) | 453 # If found, add object points, image points (after refining them) |
| 459 if ret: | 454 if ret: |
| 460 print 'Found pattern in '+fname | 455 print('Found pattern in '+fname) |
| 461 | 456 |
| 462 if(secondPassSearch): | 457 if secondPassSearch: |
| 463 corners = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) | 458 corners = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) |
| 464 | 459 |
| 465 objpoints.append(objp) | 460 objpoints.append(objp) |
| 466 imgpoints.append(corners) | 461 imgpoints.append(corners) |
| 467 | 462 |
| 468 # Draw and display the corners | 463 # Draw and display the corners |
| 469 if(display): | 464 if display: |
| 470 img = cv2.drawChessboardCorners(img, (checkerBoardSize[1],checkerBoardSize[0]), corners, ret) | 465 img = cv2.drawChessboardCorners(img, (checkerBoardSize[1],checkerBoardSize[0]), corners, ret) |
| 471 if(img): | 466 if img is not None: |
| 472 cv2.imshow('img',img) | 467 cv2.imshow('img',img) |
| 473 cv2.waitKey(0) | 468 cv2.waitKey(0) |
| 474 | 469 else: |
| 470 print('Pattern not found in '+fname) | |
| 475 ## Close up image loading and calibrate | 471 ## Close up image loading and calibrate |
| 476 cv2.destroyAllWindows() | 472 cv2.destroyAllWindows() |
| 477 if len(objpoints) == 0 or len(imgpoints) == 0: | 473 if len(objpoints) == 0 or len(imgpoints) == 0: |
| 478 return False | 474 return False |
| 479 try: | 475 try: |
| 531 invH = inv(homography) | 527 invH = inv(homography) |
| 532 invH /= invH[2,2] | 528 invH /= invH[2,2] |
| 533 return invH | 529 return invH |
| 534 | 530 |
| 535 def undistortTrajectory(invMap1, invMap2, positions): | 531 def undistortTrajectory(invMap1, invMap2, positions): |
| 536 from numpy import floor, ceil | 532 floorPositions = npfloor(positions) |
| 537 floorPositions = floor(positions) | 533 #ceilPositions = npceil(positions) |
| 538 #ceilPositions = ceil(positions) | |
| 539 undistortedTrajectory = [[],[]] | 534 undistortedTrajectory = [[],[]] |
| 540 for i in xrange(len(positions[0])): | 535 for i in xrange(len(positions[0])): |
| 541 x,y = None, None | 536 x,y = None, None |
| 542 if positions[0][i]+1 < invMap1.shape[1] and positions[1][i]+1 < invMap1.shape[0]: | 537 if positions[0][i]+1 < invMap1.shape[1] and positions[1][i]+1 < invMap1.shape[0]: |
| 543 floorX = invMap1[floorPositions[1][i], floorPositions[0][i]] | 538 floorX = invMap1[floorPositions[1][i], floorPositions[0][i]] |
| 561 '''Computes the translation of img2 with respect to img1 | 556 '''Computes the translation of img2 with respect to img1 |
| 562 (loaded using OpenCV as numpy arrays) | 557 (loaded using OpenCV as numpy arrays) |
| 563 img1Points are used to compute the translation | 558 img1Points are used to compute the translation |
| 564 | 559 |
| 565 TODO add diagnostic if data is all over the place, and it most likely is not a translation (eg zoom, other non linear distortion)''' | 560 TODO add diagnostic if data is all over the place, and it most likely is not a translation (eg zoom, other non linear distortion)''' |
| 566 from numpy import median, sum | |
| 567 | 561 |
| 568 nextPoints = array([]) | 562 nextPoints = array([]) |
| 569 (img2Points, status, track_error) = cv2.calcOpticalFlowPyrLK(img1, img2, img1Points, nextPoints, winSize=windowSize, maxLevel=level, criteria=criteria) | 563 (img2Points, status, track_error) = cv2.calcOpticalFlowPyrLK(img1, img2, img1Points, nextPoints, winSize=windowSize, maxLevel=level, criteria=criteria) |
| 570 # calcOpticalFlowPyrLK(prevImg, nextImg, prevPts[, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, derivLambda[, flags]]]]]]]]) -> nextPts, status, err | 564 # calcOpticalFlowPyrLK(prevImg, nextImg, prevPts[, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, derivLambda[, flags]]]]]]]]) -> nextPts, status, err |
| 571 delta = [] | 565 delta = [] |
| 572 for (k, (p1,p2)) in enumerate(zip(img1Points, img2Points)): | 566 for (k, (p1,p2)) in enumerate(zip(img1Points, img2Points)): |
| 573 if status[k] == 1: | 567 if status[k] == 1: |
| 574 dp = p2-p1 | 568 dp = p2-p1 |
| 575 d = sum(dp**2) | 569 d = npsum(dp**2) |
| 576 if d < maxTranslation2: | 570 if d < maxTranslation2: |
| 577 delta.append(dp) | 571 delta.append(dp) |
| 578 if len(delta) >= minNMatches: | 572 if len(delta) >= minNMatches: |
| 579 return median(delta, axis=0) | 573 return median(delta, axis=0) |
| 580 else: | 574 else: |
| 599 subplot(1,2,2) | 593 subplot(1,2,2) |
| 600 imshow(hogViz) | 594 imshow(hogViz) |
| 601 return float32(features) | 595 return float32(features) |
| 602 | 596 |
| 603 def createHOGTrainingSet(imageDirectory, classLabel, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False): | 597 def createHOGTrainingSet(imageDirectory, classLabel, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False): |
| 604 from os import listdir | |
| 605 from matplotlib.pyplot import imread | |
| 606 | |
| 607 inputData = [] | 598 inputData = [] |
| 608 for filename in listdir(imageDirectory): | 599 for filename in listdir(imageDirectory): |
| 609 img = imread(imageDirectory+filename) | 600 img = imread(imageDirectory+filename) |
| 610 features = HOG(img, rescaleSize, orientations, pixelsPerCell, cellsPerBlock, visualize, normalize) | 601 features = HOG(img, rescaleSize, orientations, pixelsPerCell, cellsPerBlock, visualize, normalize) |
| 611 inputData.append(features) | 602 inputData.append(features) |
| 612 | 603 |
| 613 nImages = len(inputData) | 604 nImages = len(inputData) |
| 614 return array(inputData, dtype = float32), array([classLabel]*nImages, dtype = float32) | 605 return array(inputData, dtype = float32), array([classLabel]*nImages) |
| 615 | 606 |
| 616 | 607 |
