Mercurial > hg > nsaunier > traffic-intelligence
comparison python/cvutils.py @ 614:5e09583275a4
Merged Nicolas/trafficintelligence into default
| author | Mohamed Gomaa <eng.m.gom3a@gmail.com> |
|---|---|
| date | Fri, 05 Dec 2014 12:13:53 -0500 |
| parents | b5525249eda1 |
| children | 9202628a4130 |
comparison
equal
deleted
inserted
replaced
| 598:11f96bd08552 | 614:5e09583275a4 |
|---|---|
| 1 #! /usr/bin/env python | 1 #! /usr/bin/env python |
| 2 '''Image/Video utilities''' | 2 '''Image/Video utilities''' |
| 3 | 3 |
| 4 import Image, ImageDraw # PIL | |
| 5 try: | 4 try: |
| 6 import cv2 | 5 import cv2 |
| 7 opencvExists = True | 6 opencvAvailable = True |
| 8 except ImportError: | 7 except ImportError: |
| 9 print('OpenCV library could not be loaded') | 8 print('OpenCV library could not be loaded (video replay functions will not be available)') # TODO change to logging module |
| 10 opencvExists = False | 9 opencvAvailable = False |
| 10 try: | |
| 11 import skimage | |
| 12 skimageAvailable = True | |
| 13 except ImportError: | |
| 14 print('Scikit-image library could not be loaded (HoG-based classification methods will not be available)') | |
| 15 skimageAvailable = False | |
| 16 | |
| 11 from sys import stdout | 17 from sys import stdout |
| 12 | 18 |
| 13 import utils | 19 import utils |
| 14 | 20 |
| 15 #import aggdraw # agg on top of PIL (antialiased drawing) | 21 #import aggdraw # agg on top of PIL (antialiased drawing) |
| 28 return chr(key&255)== 'q' or chr(key&255) == 'Q' | 34 return chr(key&255)== 'q' or chr(key&255) == 'Q' |
| 29 | 35 |
| 30 def saveKey(key): | 36 def saveKey(key): |
| 31 return chr(key&255) == 's' | 37 return chr(key&255) == 's' |
| 32 | 38 |
| 33 def drawLines(filename, origins, destinations, w = 1, resultFilename='image.png'): | 39 def plotLines(filename, origins, destinations, w = 1, resultFilename='image.png'): |
| 34 '''Draws lines over the image ''' | 40 '''Draws lines over the image ''' |
| 41 import Image, ImageDraw # PIL | |
| 35 | 42 |
| 36 img = Image.open(filename) | 43 img = Image.open(filename) |
| 37 | 44 |
| 38 draw = ImageDraw.Draw(img) | 45 draw = ImageDraw.Draw(img) |
| 39 #draw = aggdraw.Draw(img) | 46 #draw = aggdraw.Draw(img) |
| 40 #pen = aggdraw.Pen("red", width) | 47 #pen = aggdraw.Pen("red", width) |
| 41 for p1, p2 in zip(origins, destinations): | 48 for p1, p2 in zip(origins, destinations): |
| 42 draw.line([p1.x, p1.y, p2.x, p2.y], width = w, fill = (256,0,0)) | 49 draw.line([p1.x, p1.y, p2.x, p2.y], width = w, fill = (256,0,0)) |
| 43 #draw.line([p1.x, p1.y, p2.x, p2.y], pen) | 50 #draw.line([p1.x, p1.y, p2.x, p2.y], pen) |
| 44 del draw | 51 del draw |
| 45 | 52 |
| 46 #out = utils.openCheck(resultFilename) | 53 #out = utils.openCheck(resultFilename) |
| 47 img.save(resultFilename) | 54 img.save(resultFilename) |
| 48 | 55 |
| 49 def matlab2PointCorrespondences(filename): | 56 def matlab2PointCorrespondences(filename): |
| 61 points = loadtxt(filename, dtype=float32) | 68 points = loadtxt(filename, dtype=float32) |
| 62 return (points[:2,:].T, points[2:,:].T) # (world points, image points) | 69 return (points[:2,:].T, points[2:,:].T) # (world points, image points) |
| 63 | 70 |
| 64 def cvMatToArray(cvmat): | 71 def cvMatToArray(cvmat): |
| 65 '''Converts an OpenCV CvMat to numpy array.''' | 72 '''Converts an OpenCV CvMat to numpy array.''' |
| 73 print('Deprecated, use new interface') | |
| 66 from numpy.core.multiarray import zeros | 74 from numpy.core.multiarray import zeros |
| 67 a = zeros((cvmat.rows, cvmat.cols))#array([[0.0]*cvmat.width]*cvmat.height) | 75 a = zeros((cvmat.rows, cvmat.cols))#array([[0.0]*cvmat.width]*cvmat.height) |
| 68 for i in xrange(cvmat.rows): | 76 for i in xrange(cvmat.rows): |
| 69 for j in xrange(cvmat.cols): | 77 for j in xrange(cvmat.cols): |
| 70 a[i,j] = cvmat[i,j] | 78 a[i,j] = cvmat[i,j] |
| 71 return a | 79 return a |
| 72 | 80 |
| 73 if opencvExists: | 81 if opencvAvailable: |
| 74 def computeHomography(srcPoints, dstPoints, method=0, ransacReprojThreshold=0.0): | 82 def computeHomography(srcPoints, dstPoints, method=0, ransacReprojThreshold=3.0): |
| 75 '''Returns the homography matrix mapping from srcPoints to dstPoints (dimension Nx2)''' | 83 '''Returns the homography matrix mapping from srcPoints to dstPoints (dimension Nx2)''' |
| 76 H, mask = cv2.findHomography(srcPoints, dstPoints, method, ransacReprojThreshold) | 84 H, mask = cv2.findHomography(srcPoints, dstPoints, method, ransacReprojThreshold) |
| 77 return H | 85 return H |
| 78 | 86 |
| 79 def arrayToCvMat(a, t = cv2.cv.CV_64FC1): | 87 def arrayToCvMat(a, t = cv2.CV_64FC1): |
| 80 '''Converts a numpy array to an OpenCV CvMat, with default type CV_64FC1.''' | 88 '''Converts a numpy array to an OpenCV CvMat, with default type CV_64FC1.''' |
| 89 print('Deprecated, use new interface') | |
| 81 cvmat = cv2.cv.CreateMat(a.shape[0], a.shape[1], t) | 90 cvmat = cv2.cv.CreateMat(a.shape[0], a.shape[1], t) |
| 82 for i in range(cvmat.rows): | 91 for i in range(cvmat.rows): |
| 83 for j in range(cvmat.cols): | 92 for j in range(cvmat.cols): |
| 84 cvmat[i,j] = a[i,j] | 93 cvmat[i,j] = a[i,j] |
| 85 return cvmat | 94 return cvmat |
| 86 | 95 |
| 87 def draw(img, positions, color, lastCoordinate = None): | 96 def cvPlot(img, positions, color, lastCoordinate = None): |
| 88 last = lastCoordinate+1 | 97 last = lastCoordinate+1 |
| 89 if lastCoordinate != None and lastCoordinate >=0: | 98 if lastCoordinate != None and lastCoordinate >=0: |
| 90 last = min(positions.length()-1, lastCoordinate) | 99 last = min(positions.length()-1, lastCoordinate) |
| 91 for i in range(0, last-1): | 100 for i in range(0, last-1): |
| 92 cv2.line(img, positions[i].asint().astuple(), positions[i+1].asint().astuple(), color) | 101 cv2.line(img, positions[i].asint().astuple(), positions[i+1].asint().astuple(), color) |
| 93 | 102 |
| 94 def playVideo(filename, firstFrameNum = 0, frameRate = -1): | 103 def cvImshow(windowName, img, rescale = 1.0): |
| 104 'Rescales the image (in particular if too large)' | |
| 105 from cv2 import resize | |
| 106 if rescale != 1.: | |
| 107 size = (int(round(img.shape[1]*rescale)), int(round(img.shape[0]*rescale))) | |
| 108 resizedImg = resize(img, size) | |
| 109 cv2.imshow(windowName, resizedImg) | |
| 110 else: | |
| 111 cv2.imshow(windowName, img) | |
| 112 | |
| 113 def computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients): | |
| 114 from copy import deepcopy | |
| 115 from numpy import identity, array | |
| 116 newImgSize = (int(round(width*undistortedImageMultiplication)), int(round(height*undistortedImageMultiplication))) | |
| 117 newCameraMatrix = deepcopy(intrinsicCameraMatrix) | |
| 118 newCameraMatrix[0,2] = newImgSize[0]/2. | |
| 119 newCameraMatrix[1,2] = newImgSize[1]/2. | |
| 120 return cv2.initUndistortRectifyMap(intrinsicCameraMatrix, array(distortionCoefficients), identity(3), newCameraMatrix, newImgSize, cv2.CV_32FC1) | |
| 121 | |
| 122 def playVideo(filename, firstFrameNum = 0, frameRate = -1, interactive = False, printFrames = True, text = None, rescale = 1.): | |
| 95 '''Plays the video''' | 123 '''Plays the video''' |
| 124 windowName = 'frame' | |
| 125 cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) | |
| 96 wait = 5 | 126 wait = 5 |
| 97 if frameRate > 0: | 127 if frameRate > 0: |
| 98 wait = int(round(1000./frameRate)) | 128 wait = int(round(1000./frameRate)) |
| 129 if interactive: | |
| 130 wait = 0 | |
| 99 capture = cv2.VideoCapture(filename) | 131 capture = cv2.VideoCapture(filename) |
| 100 if capture.isOpened(): | 132 if capture.isOpened(): |
| 101 key = -1 | 133 key = -1 |
| 102 ret = True | 134 ret = True |
| 103 frameNum = firstFrameNum | 135 frameNum = firstFrameNum |
| 104 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) | 136 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) |
| 105 while ret and not quitKey(key): | 137 while ret and not quitKey(key): |
| 106 ret, img = capture.read() | 138 ret, img = capture.read() |
| 107 if ret: | 139 if ret: |
| 108 print('frame {0}'.format(frameNum)) | 140 if printFrames: |
| 141 print('frame {0}'.format(frameNum)) | |
| 109 frameNum+=1 | 142 frameNum+=1 |
| 110 cv2.imshow('frame', img) | 143 if text != None: |
| 144 cv2.putText(img, text, (10,50), cv2.cv.CV_FONT_HERSHEY_PLAIN, 1, cvRed) | |
| 145 cvImshow(windowName, img, rescale) | |
| 111 key = cv2.waitKey(wait) | 146 key = cv2.waitKey(wait) |
| 112 | 147 cv2.destroyAllWindows() |
| 113 def getImagesFromVideo(filename, nImages = 1, saveImage = False): | 148 else: |
| 114 '''Returns nImages images from the video sequence''' | 149 print('Video capture for {} failed'.format(filename)) |
| 150 | |
| 151 def getImagesFromVideo(videoFilename, firstFrameNum = 0, nFrames = 1, saveImage = False, outputPrefix = 'image'): | |
| 152 '''Returns nFrames images from the video sequence''' | |
| 153 from math import floor, log10 | |
| 115 images = [] | 154 images = [] |
| 116 capture = cv2.VideoCapture(filename) | 155 capture = cv2.VideoCapture(videoFilename) |
| 117 if capture.isOpened(): | 156 if capture.isOpened(): |
| 157 nDigits = int(floor(log10(capture.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))))+1 | |
| 118 ret = False | 158 ret = False |
| 119 numImg = 0 | 159 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) |
| 120 while numImg<nImages: | 160 imgNum = 0 |
| 161 while imgNum<nFrames: | |
| 121 ret, img = capture.read() | 162 ret, img = capture.read() |
| 122 i = 0 | 163 i = 0 |
| 123 while not ret and i<10: | 164 while not ret and i<10: |
| 124 ret, img = capture.read() | 165 ret, img = capture.read() |
| 125 i += 1 | 166 i += 1 |
| 126 if img.size>0: | 167 if img.size>0: |
| 127 numImg +=1 | |
| 128 if saveImage: | 168 if saveImage: |
| 129 cv2.imwrite('image{0:04d}.png'.format(numImg), img) | 169 imgNumStr = format(firstFrameNum+imgNum, '0{}d'.format(nDigits)) |
| 170 cv2.imwrite(outputPrefix+imgNumStr+'.png', img) | |
| 130 else: | 171 else: |
| 131 images.append(img) | 172 images.append(img) |
| 173 imgNum +=1 | |
| 174 capture.release() | |
| 175 else: | |
| 176 print('Video capture for {} failed'.format(videoFilename)) | |
| 132 return images | 177 return images |
| 133 | 178 |
| 134 def displayTrajectories(videoFilename, objects, homography = None, firstFrameNum = 0, lastFrameNumArg = None): | 179 def getFPS(videoFilename): |
| 180 capture = cv2.VideoCapture(videoFilename) | |
| 181 if capture.isOpened(): | |
| 182 fps = capture.get(cv2.cv.CV_CAP_PROP_FPS) | |
| 183 capture.release() | |
| 184 return fps | |
| 185 else: | |
| 186 print('Video capture for {} failed'.format(videoFilename)) | |
| 187 return None | |
| 188 | |
| 189 def imageBox(img, obj, frameNum, homography, width, height, px = 0.2, py = 0.2, pixelThreshold = 800): | |
| 190 'Computes the bounding box of object at frameNum' | |
| 191 x = [] | |
| 192 y = [] | |
| 193 for f in obj.features: | |
| 194 if f.existsAtInstant(frameNum): | |
| 195 projectedPosition = f.getPositionAtInstant(frameNum).project(homography) | |
| 196 x.append(projectedPosition.x) | |
| 197 y.append(projectedPosition.y) | |
| 198 xmin = min(x) | |
| 199 xmax = max(x) | |
| 200 ymin = min(y) | |
| 201 ymax = max(y) | |
| 202 xMm = px * (xmax - xmin) | |
| 203 yMm = py * (ymax - ymin) | |
| 204 a = max(ymax - ymin + (2 * yMm), xmax - (xmin + 2 * xMm)) | |
| 205 yCropMin = int(max(0, .5 * (ymin + ymax - a))) | |
| 206 yCropMax = int(min(height - 1, .5 * (ymin + ymax + a))) | |
| 207 xCropMin = int(max(0, .5 * (xmin + xmax - a))) | |
| 208 xCropMax = int(min(width - 1, .5 * (xmin + xmax + a))) | |
| 209 if yCropMax != yCropMin and xCropMax != xCropMin and (yCropMax - yCropMin) * (xCropMax - xCropMin) > pixelThreshold: | |
| 210 croppedImg = img[yCropMin : yCropMax, xCropMin : xCropMax] | |
| 211 else: | |
| 212 croppedImg = [] | |
| 213 return croppedImg, yCropMin, yCropMax, xCropMin, xCropMax | |
| 214 | |
| 215 | |
| 216 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.): | |
| 135 '''Displays the objects overlaid frame by frame over the video ''' | 217 '''Displays the objects overlaid frame by frame over the video ''' |
| 218 from moving import userTypeNames | |
| 219 from math import ceil, log10 | |
| 220 | |
| 136 capture = cv2.VideoCapture(videoFilename) | 221 capture = cv2.VideoCapture(videoFilename) |
| 222 width = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)) | |
| 223 height = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)) | |
| 224 | |
| 225 windowName = 'frame' | |
| 226 #cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) | |
| 227 | |
| 228 if undistort: # setup undistortion | |
| 229 [map1, map2] = computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients) | |
| 137 if capture.isOpened(): | 230 if capture.isOpened(): |
| 138 key = -1 | 231 key = -1 |
| 139 ret = True | 232 ret = True |
| 140 frameNum = firstFrameNum | 233 frameNum = firstFrameNum |
| 141 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) | 234 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) |
| 142 if not lastFrameNumArg: | 235 if lastFrameNumArg == None: |
| 143 from sys import maxint | 236 from sys import maxint |
| 144 lastFrameNum = maxint | 237 lastFrameNum = maxint |
| 145 else: | 238 else: |
| 146 lastFrameNum = lastFrameNumArg | 239 lastFrameNum = lastFrameNumArg |
| 240 nZerosFilename = int(ceil(log10(lastFrameNum))) | |
| 147 while ret and not quitKey(key) and frameNum < lastFrameNum: | 241 while ret and not quitKey(key) and frameNum < lastFrameNum: |
| 148 ret, img = capture.read() | 242 ret, img = capture.read() |
| 149 if ret: | 243 if ret: |
| 150 print('frame {0}'.format(frameNum)) | 244 if undistort: |
| 245 img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR) | |
| 246 if printFrames: | |
| 247 print('frame {0}'.format(frameNum)) | |
| 151 for obj in objects: | 248 for obj in objects: |
| 152 if obj.existsAtInstant(frameNum): | 249 if obj.existsAtInstant(frameNum): |
| 153 if not hasattr(obj, 'projectedPositions'): | 250 if not hasattr(obj, 'projectedPositions'): |
| 154 if homography != None: | 251 if homography != None: |
| 155 obj.projectedPositions = obj.positions.project(homography) | 252 obj.projectedPositions = obj.positions.project(homography) |
| 156 else: | 253 else: |
| 157 obj.projectedPositions = obj.positions | 254 obj.projectedPositions = obj.positions |
| 158 draw(img, obj.projectedPositions, cvRed, frameNum-obj.getFirstInstant()) | 255 cvPlot(img, obj.projectedPositions, cvRed, frameNum-obj.getFirstInstant()) |
| 159 cv2.putText(img, '{0}'.format(obj.num), obj.projectedPositions[frameNum-obj.getFirstInstant()].asint().astuple(), cv2.FONT_HERSHEY_PLAIN, 1, cvRed) | 256 if frameNum in boundingBoxes.keys(): |
| 160 cv2.imshow('frame', img) | 257 for rect in boundingBoxes[frameNum]: |
| 161 key = cv2.waitKey() | 258 cv2.rectangle(img, rect[0].asint().astuple(), rect[1].asint().astuple(), cvRed) |
| 162 if saveKey(key): | 259 elif len(obj.features) != 0: |
| 163 cv2.imwrite('image.png', img) | 260 imgcrop, yCropMin, yCropMax, xCropMin, xCropMax = imageBox(img, obj, frameNum, homography, width, height) |
| 164 frameNum += 1 | 261 cv2.rectangle(img, (xCropMin, yCropMin), (xCropMax, yCropMax), cvBlue, 1) |
| 165 | 262 objDescription = '{} '.format(obj.num) |
| 263 if userTypeNames[obj.userType] != 'unknown': | |
| 264 objDescription += userTypeNames[obj.userType][0].upper() | |
| 265 cv2.putText(img, objDescription, obj.projectedPositions[frameNum-obj.getFirstInstant()].asint().astuple(), cv2.cv.CV_FONT_HERSHEY_PLAIN, 1, cvRed) | |
| 266 if not saveAllImages: | |
| 267 cvImshow(windowName, img, rescale) | |
| 268 key = cv2.waitKey() | |
| 269 if saveAllImages or saveKey(key): | |
| 270 cv2.imwrite('image-{{:0{}}}.png'.format(nZerosFilename).format(frameNum), img) | |
| 271 frameNum += nFramesStep | |
| 272 if nFramesStep > 1: | |
| 273 capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, frameNum) | |
| 274 cv2.destroyAllWindows() | |
| 275 else: | |
| 276 print 'Cannot load file ' + videoFilename | |
| 277 | |
| 278 def computeHomographyFromPDTV(cameraFilename, method=0, ransacReprojThreshold=3.0): | |
| 279 '''Returns the homography matrix at ground level from PDTV format | |
| 280 https://bitbucket.org/hakanardo/pdtv''' | |
| 281 import pdtv | |
| 282 from numpy import array | |
| 283 camera = pdtv.load(cameraFilename) | |
| 284 srcPoints = [[x,y] for x, y in zip([1.,2.,2.,1.],[1.,1.,2.,2.])] # need floats!! | |
| 285 dstPoints = [] | |
| 286 for srcPoint in srcPoints: | |
| 287 projected = camera.image_to_world(tuple(srcPoint)) | |
| 288 dstPoints.append([projected[0], projected[1]]) | |
| 289 H, mask = cv2.findHomography(array(srcPoints), array(dstPoints), method, ransacReprojThreshold) | |
| 290 return H | |
| 291 | |
| 292 def undistortedCoordinates(map1, map2, x, y, maxDistance = 1.): | |
| 293 '''Returns the coordinates of a point in undistorted image | |
| 294 map1 and map2 are the mapping functions from undistorted image | |
| 295 to distorted (original image) | |
| 296 map1(x,y) = originalx, originaly''' | |
| 297 from numpy import abs, logical_and, unravel_index, dot, sum | |
| 298 from matplotlib.mlab import find | |
| 299 distx = abs(map1-x) | |
| 300 disty = abs(map2-y) | |
| 301 indices = logical_and(distx<maxDistance, disty<maxDistance) | |
| 302 closeCoordinates = unravel_index(find(indices), distx.shape) # returns i,j, ie y,x | |
| 303 xWeights = 1-distx[indices] | |
| 304 yWeights = 1-disty[indices] | |
| 305 return dot(xWeights, closeCoordinates[1])/sum(xWeights), dot(yWeights, closeCoordinates[0])/sum(yWeights) | |
| 306 | |
| 307 def undistortTrajectoryFromCVMapping(map1, map2, t): | |
| 308 '''test 'perfect' inversion''' | |
| 309 from moving import Trajectory | |
| 310 from numpy import isnan | |
| 311 undistortedTrajectory = Trajectory() | |
| 312 for i,p in enumerate(t): | |
| 313 res = undistortedCoordinates(map1, map2, p.x,p.y) | |
| 314 if not isnan(res).any(): | |
| 315 undistortedTrajectory.addPositionXY(res[0], res[1]) | |
| 316 else: | |
| 317 print i,p,res | |
| 318 return undistortedTrajectory | |
| 319 | |
| 320 def computeInverseMapping(originalImageSize, map1, map2): | |
| 321 'Computes inverse mapping from maps provided by cv2.initUndistortRectifyMap' | |
| 322 from numpy import ones, isnan | |
| 323 invMap1 = -ones(originalImageSize) | |
| 324 invMap2 = -ones(originalImageSize) | |
| 325 for x in range(0,originalImageSize[1]): | |
| 326 for y in range(0,originalImageSize[0]): | |
| 327 res = undistortedCoordinates(x,y, map1, map2) | |
| 328 if not isnan(res).any(): | |
| 329 invMap1[y,x] = res[0] | |
| 330 invMap2[y,x] = res[1] | |
| 331 return invMap1, invMap2 | |
| 332 | |
| 333 def cameraIntrinsicCalibration(path, checkerBoardSize=[6,7], secondPassSearch=False, display=False): | |
| 334 ''' Camera calibration searches through all the images (jpg or png) located | |
| 335 in _path_ for matches to a checkerboard pattern of size checkboardSize. | |
| 336 These images should all be of the same camera with the same resolution. | |
| 337 | |
| 338 For best results, use an asymetric board and ensure that the image has | |
| 339 very high contrast, including the background. Suitable checkerboard: | |
| 340 http://ftp.isr.ist.utl.pt/pub/roswiki/attachments/camera_calibration(2f)Tutorials(2f)StereoCalibration/check-108.png | |
| 341 | |
| 342 The code below is based off of: | |
| 343 https://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html | |
| 344 Modified by Paul St-Aubin | |
| 345 ''' | |
| 346 from numpy import zeros, mgrid, float32, savetxt | |
| 347 import glob, os | |
| 348 | |
| 349 # termination criteria | |
| 350 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) | |
| 351 | |
| 352 # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) | |
| 353 objp = zeros((checkerBoardSize[0]*checkerBoardSize[1],3), float32) | |
| 354 objp[:,:2] = mgrid[0:checkerBoardSize[1],0:checkerBoardSize[0]].T.reshape(-1,2) | |
| 355 | |
| 356 # Arrays to store object points and image points from all the images. | |
| 357 objpoints = [] # 3d point in real world space | |
| 358 imgpoints = [] # 2d points in image plane. | |
| 359 | |
| 360 ## Loop throuhg all images in _path_ | |
| 361 images = glob.glob(os.path.join(path,'*.[jJ][pP][gG]'))+glob.glob(os.path.join(path,'*.[jJ][pP][eE][gG]'))+glob.glob(os.path.join(path,'*.[pP][nN][gG]')) | |
| 362 for fname in images: | |
| 363 img = cv2.imread(fname) | |
| 364 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
| 365 | |
| 366 # Find the chess board corners | |
| 367 ret, corners = cv2.findChessboardCorners(gray, (checkerBoardSize[1],checkerBoardSize[0]), None) | |
| 368 | |
| 369 # If found, add object points, image points (after refining them) | |
| 370 if ret: | |
| 371 print 'Found pattern in '+fname | |
| 372 | |
| 373 if(secondPassSearch): | |
| 374 corners = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) | |
| 375 | |
| 376 objpoints.append(objp) | |
| 377 imgpoints.append(corners) | |
| 378 | |
| 379 # Draw and display the corners | |
| 380 if(display): | |
| 381 img = cv2.drawChessboardCorners(img, (checkerBoardSize[1],checkerBoardSize[0]), corners, ret) | |
| 382 if(img): | |
| 383 cv2.imshow('img',img) | |
| 384 cv2.waitKey(0) | |
| 385 | |
| 386 ## Close up image loading and calibrate | |
| 387 cv2.destroyAllWindows() | |
| 388 if len(objpoints) == 0 or len(imgpoints) == 0: | |
| 389 return False | |
| 390 try: | |
| 391 ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) | |
| 392 except NameError: | |
| 393 return False | |
| 394 savetxt('intrinsic-camera.txt', camera_matrix) | |
| 395 return camera_matrix, dist_coeffs | |
| 396 | |
| 397 def undistortImage(img, intrinsicCameraMatrix = None, distortionCoefficients = None, undistortedImageMultiplication = 1., interpolation=cv2.INTER_LINEAR): | |
| 398 '''Undistorts the image passed in argument''' | |
| 399 width = img.shape[1] | |
| 400 height = img.shape[0] | |
| 401 [map1, map2] = computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients) | |
| 402 return cv2.remap(img, map1, map2, interpolation=interpolation) | |
| 403 | |
| 404 | |
| 166 def printCvMat(cvmat, out = stdout): | 405 def printCvMat(cvmat, out = stdout): |
| 167 '''Prints the cvmat to out''' | 406 '''Prints the cvmat to out''' |
| 407 print('Deprecated, use new interface') | |
| 168 for i in xrange(cvmat.rows): | 408 for i in xrange(cvmat.rows): |
| 169 for j in xrange(cvmat.cols): | 409 for j in xrange(cvmat.cols): |
| 170 out.write('{0} '.format(cvmat[i,j])) | 410 out.write('{0} '.format(cvmat[i,j])) |
| 171 out.write('\n') | 411 out.write('\n') |
| 172 | 412 |
| 173 def projectArray(homography, points): | 413 def projectArray(homography, points): |
| 174 '''Returns the coordinates of the projected points (format 2xN points) | 414 '''Returns the coordinates of the projected points through homography |
| 175 through homography''' | 415 (format: array 2xN points)''' |
| 176 from numpy.core._dotblas import dot | 416 from numpy.core import dot |
| 177 from numpy.core.multiarray import array | 417 from numpy.core.multiarray import array |
| 178 from numpy.lib.function_base import append | 418 from numpy.lib.function_base import append |
| 179 | 419 |
| 180 if points.shape[0] != 2: | 420 if points.shape[0] != 2: |
| 181 raise Exception('points of dimension {0} {1}'.format(points.shape[0], points.shape[1])) | 421 raise Exception('points of dimension {0} {1}'.format(points.shape[0], points.shape[1])) |
| 183 if (homography!=None) and homography.size>0: | 423 if (homography!=None) and homography.size>0: |
| 184 augmentedPoints = append(points,[[1]*points.shape[1]], 0) | 424 augmentedPoints = append(points,[[1]*points.shape[1]], 0) |
| 185 prod = dot(homography, augmentedPoints) | 425 prod = dot(homography, augmentedPoints) |
| 186 return prod[0:2]/prod[2] | 426 return prod[0:2]/prod[2] |
| 187 else: | 427 else: |
| 188 return p | 428 return points |
| 189 | 429 |
| 190 def project(homography, p): | 430 def project(homography, p): |
| 191 '''Returns the coordinates of the projection of the point p | 431 '''Returns the coordinates of the projection of the point p with coordinates p[0], p[1] |
| 192 through homography''' | 432 through homography''' |
| 193 from numpy import array | 433 from numpy import array |
| 194 return projectArray(homography, array([[p[0]],[p[1]]])) | 434 return projectArray(homography, array([[p[0]],[p[1]]])) |
| 195 | 435 |
| 196 def projectTrajectory(homography, trajectory): | 436 def projectTrajectory(homography, trajectory): |
| 199 [y1, y2, ...]]''' | 439 [y1, y2, ...]]''' |
| 200 from numpy.core.multiarray import array | 440 from numpy.core.multiarray import array |
| 201 return projectArray(homography, array(trajectory)) | 441 return projectArray(homography, array(trajectory)) |
| 202 | 442 |
| 203 def invertHomography(homography): | 443 def invertHomography(homography): |
| 204 'Returns an inverted homography' | 444 '''Returns an inverted homography |
| 445 Unnecessary for reprojection over camera image''' | |
| 205 from numpy.linalg.linalg import inv | 446 from numpy.linalg.linalg import inv |
| 206 invH = inv(homography) | 447 invH = inv(homography) |
| 207 invH /= invH[2,2] | 448 invH /= invH[2,2] |
| 208 return invH | 449 return invH |
| 209 | 450 |
| 210 if opencvExists: | 451 def undistortTrajectory(invMap1, invMap2, positions): |
| 452 from numpy import floor, ceil | |
| 453 floorPositions = floor(positions) | |
| 454 #ceilPositions = ceil(positions) | |
| 455 undistortedTrajectory = [[],[]] | |
| 456 for i in xrange(len(positions[0])): | |
| 457 x,y = None, None | |
| 458 if positions[0][i]+1 < invMap1.shape[1] and positions[1][i]+1 < invMap1.shape[0]: | |
| 459 floorX = invMap1[floorPositions[1][i], floorPositions[0][i]] | |
| 460 floorY = invMap2[floorPositions[1][i], floorPositions[0][i]] | |
| 461 ceilX = invMap1[floorPositions[1][i]+1, floorPositions[0][i]+1] | |
| 462 ceilY = invMap2[floorPositions[1][i]+1, floorPositions[0][i]+1] | |
| 463 #ceilX = invMap1[ceilPositions[1][i], ceilPositions[0][i]] | |
| 464 #ceilY = invMap2[ceilPositions[1][i], ceilPositions[0][i]] | |
| 465 if floorX >=0 and floorY >=0 and ceilX >=0 and ceilY >=0: | |
| 466 x = floorX+(positions[0][i]-floorPositions[0][i])*(ceilX-floorX) | |
| 467 y = floorY+(positions[1][i]-floorPositions[1][i])*(ceilY-floorY) | |
| 468 undistortedTrajectory[0].append(x) | |
| 469 undistortedTrajectory[1].append(y) | |
| 470 return undistortedTrajectory | |
| 471 | |
| 472 def projectGInputPoints(homography, points): | |
| 473 from numpy import array | |
| 474 return projectTrajectory(homography, array(points+[points[0]]).T) | |
| 475 | |
| 476 if opencvAvailable: | |
| 211 def computeTranslation(img1, img2, img1Points, maxTranslation2, minNMatches, windowSize = (5,5), level = 5, criteria = (cv2.TERM_CRITERIA_EPS, 0, 0.01)): | 477 def computeTranslation(img1, img2, img1Points, maxTranslation2, minNMatches, windowSize = (5,5), level = 5, criteria = (cv2.TERM_CRITERIA_EPS, 0, 0.01)): |
| 212 '''Computes the translation of img2 with respect to img1 | 478 '''Computes the translation of img2 with respect to img1 |
| 213 (loaded using OpenCV as numpy arrays) | 479 (loaded using OpenCV as numpy arrays) |
| 214 img1Points are used to compute the translation | 480 img1Points are used to compute the translation |
| 215 | 481 |
| 231 if len(delta) >= minNMatches: | 497 if len(delta) >= minNMatches: |
| 232 return median(delta, axis=0) | 498 return median(delta, axis=0) |
| 233 else: | 499 else: |
| 234 print(dp) | 500 print(dp) |
| 235 return None | 501 return None |
| 502 | |
| 503 if skimageAvailable: | |
| 504 def HOG(image, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False): | |
| 505 from skimage.feature import hog | |
| 506 from skimage import color, transform | |
| 507 | |
| 508 bwImg = color.rgb2gray(image) | |
| 509 inputImg = transform.resize(bwImg, rescaleSize) | |
| 510 features = hog(inputImg, orientations, pixelsPerCell, cellsPerBlock, visualize, normalize) | |
| 511 if visualize: | |
| 512 from matplotlib.pyplot import imshow, figure, subplot | |
| 513 hogViz = features[1] | |
| 514 features = features[0] | |
| 515 figure() | |
| 516 subplot(1,2,1) | |
| 517 imshow(img) | |
| 518 subplot(1,2,2) | |
| 519 imshow(hogViz) | |
| 520 return features | |
| 521 | |
| 522 def createHOGTrainingSet(imageDirectory, classLabel, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False): | |
| 523 from os import listdir | |
| 524 from numpy import array, float32 | |
| 525 from matplotlib.pyplot import imread | |
| 526 | |
| 527 inputData = [] | |
| 528 for filename in listdir(imageDirectory): | |
| 529 img = imread(imageDirectory+filename) | |
| 530 features = HOG(img, rescaleSize, orientations, pixelsPerCell, cellsPerBlock, visualize, normalize) | |
| 531 inputData.append(features) | |
| 532 | |
| 533 nImages = len(inputData) | |
| 534 return array(inputData, dtype = float32), array([classLabel]*nImages, dtype = float32) | |
| 535 | |
| 536 |
