changeset 904:8f60ecfc2f06

work in progress, almost ready
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 22 Jun 2017 18:08:46 -0400
parents 81ee5aaf213d
children 0e017178f7ab
files python/cvutils.py python/moving.py scripts/classify-objects.py scripts/extract-appearance-images.py
diffstat 4 files changed, 53 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/python/cvutils.py	Thu Jun 22 17:02:03 2017 -0400
+++ b/python/cvutils.py	Thu Jun 22 18:08:46 2017 -0400
@@ -258,9 +258,9 @@
         else:
             print('Video capture for {} failed'.format(videoFilename))
             return None
-
-    def imageBox(img, obj, frameNum, homography, width, height, px = 0.2, py = 0.2, minNPixels = 800):
-        'Computes the bounding box of object at frameNum'
+        
+    def imageBoxSize(obj, frameNum, homography, width, height, px = 0.2, py = 0.2):
+        'Computes the bounding box size of object at frameNum'
         x = []
         y = []
         if obj.hasFeatures():
@@ -280,12 +280,15 @@
         yCropMax = int(min(height - 1, .5 * (ymin + ymax + a)))
         xCropMin = int(max(0, .5 * (xmin + xmax - a)))
         xCropMax = int(min(width - 1, .5 * (xmin + xmax + a)))
+        return yCropMin, yCropMax, xCropMin, xCropMax
+        
+    def imageBox(img, obj, frameNum, homography, width, height, px = 0.2, py = 0.2, minNPixels = 800):
+        'Computes the bounding box of object at frameNum'
+        yCropMin, yCropMax, xCropMin, xCropMax = imageBoxSize(obj, frameNum, homography, width, height, px, py)
         if yCropMax != yCropMin and xCropMax != xCropMin and (yCropMax - yCropMin) * (xCropMax - xCropMin) > minNPixels:
-            croppedImg = img[yCropMin : yCropMax, xCropMin : xCropMax]
+            return img[yCropMin : yCropMax, xCropMin : xCropMax]
         else:
-            croppedImg = None
-        return croppedImg, yCropMin, yCropMax, xCropMin, xCropMax
-
+            return None
 
     def displayTrajectories(videoFilename, objects, boundingBoxes = {}, homography = None, firstFrameNum = 0, lastFrameNumArg = None, printFrames = True, rescale = 1., nFramesStep = 1, saveAllImages = False, nZerosFilenameArg = None, undistort = False, intrinsicCameraMatrix = None, distortionCoefficients = None, undistortedImageMultiplication = 1., annotations = [], gtMatches = {}, toMatches = {}, colorBlind = False):
         '''Displays the objects overlaid frame by frame over the video '''
@@ -334,7 +337,7 @@
                                     obj.projectedPositions = obj.positions
                             cvPlot(img, obj.projectedPositions, cvColors[colorType][obj.getNum()], frameNum-obj.getFirstInstant())
                             if frameNum not in boundingBoxes.keys() and obj.hasFeatures():
-                                imgcrop, yCropMin, yCropMax, xCropMin, xCropMax = imageBox(img, obj, frameNum, homography, width, height)
+                                yCropMin, yCropMax, xCropMin, xCropMax = imageBoxSize(obj, frameNum, homography, width, height)
                                 cv2.rectangle(img, (xCropMin, yCropMin), (xCropMax, yCropMax), cvBlue[colorType], 1)
                             objDescription = '{} '.format(obj.num)
                             if moving.userTypeNames[obj.userType] != 'unknown':
--- a/python/moving.py	Thu Jun 22 17:02:03 2017 -0400
+++ b/python/moving.py	Thu Jun 22 18:08:46 2017 -0400
@@ -1583,7 +1583,7 @@
         with an added px or py for width and height (around the box))
         computes HOG on this cropped image (with parameters rescaleSize, orientations, pixelsPerCell, cellsPerBlock)
         and applies the SVM model on it'''
-        croppedImg, yCropMin, yCropMax, xCropMin, xCropMax = cvutils.imageBox(img, self, instant, homography, width, height, px, py, minNPixels)
+        croppedImg = cvutils.imageBox(img, self, instant, homography, width, height, px, py, minNPixels)
         if croppedImg is not None and len(croppedImg) > 0:
             hog = cvutils.HOG(croppedImg, rescaleSize, orientations, pixelsPerCell, cellsPerBlock, blockNorm, visualize=False, normalize=False)
             self.userTypes[instant] = int(self.appearanceClassifier.predict(hog))
--- a/scripts/classify-objects.py	Thu Jun 22 17:02:03 2017 -0400
+++ b/scripts/classify-objects.py	Thu Jun 22 18:08:46 2017 -0400
@@ -71,10 +71,11 @@
 width = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH))
 height = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT))
 
+if undistort: # setup undistortion
+    [map1, map2] = cvutils.computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients)
+
 pastObjects = []
 currentObjects = []
-if undistort: # setup undistortion
-    [map1, map2] = cvutils.computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients)
 if capture.isOpened():
     ret = True
     frameNum = timeInterval.first
--- a/scripts/extract-appearance-images.py	Thu Jun 22 17:02:03 2017 -0400
+++ b/scripts/extract-appearance-images.py	Thu Jun 22 18:08:46 2017 -0400
@@ -1,9 +1,9 @@
 #! /usr/bin/env python
 
-import numpy as np
-import argparse
-from cv2 import SVM_RBF, SVM_C_SVC
-#from cv2.ml import SVM_RBF, SVM_C_SVC, ROW_SAMPLE # row_sample for layout in cv2.ml.SVM_load
+import numpy as np, cv2
+import argparse, os
+from pandas import read_csv
+from matplotlib.pyplot import imsave
 
 import cvutils, moving, ml, storage
 
@@ -12,8 +12,12 @@
 parser.add_argument('-d', dest = 'databaseFilename', help = 'name of the Sqlite database file (overrides the configuration file)')
 parser.add_argument('-i', dest = 'videoFilename', help = 'name of the video file (overrides the configuration file)')
 parser.add_argument('--gt', dest = 'classificationAnnotationFilename', help = 'name of the file containing the correct classes (user types)', required = True)
+parser.add_argument('--delimiter', dest = 'classificationAnnotationFilenameDelimiter', help = 'delimiter for the fields in the correct classification file', default= ' ')
 parser.add_argument('-s', dest = 'nFramesStep', help = 'number of frames between each saved patch', default = 50, type = int)
 parser.add_argument('-n', dest = 'nObjects', help = 'number of objects to use to extract patches from', type = int, default = None)
+parser.add_argument('--extract-all', dest = 'extractAllObjectImages', help = 'extracts the images for all objects, well classified or not (otherwise, extracts only for the misclassified)', action = 'store_true')
+parser.add_argument('--prefix', dest = 'imagePrefix', help = 'image prefix', default = 'img')
+parser.add_argument('--ouput', dest = 'directoryName', help = 'parent directory name for the directories containing the samples for the different road users', default = '.')
 parser.add_argument('--compute-speed-distributions', dest = 'computeSpeedDistribution', help = 'computes the distribution of the road users of each type and fits parameters to each', action = 'store_true')
 
 
@@ -23,34 +27,55 @@
 params, videoFilename, databaseFilename, invHomography, intrinsicCameraMatrix, distortionCoefficients, undistortedImageMultiplication, undistort, firstFrameNum = storage.processVideoArguments(args)
 classifierParams = storage.ClassifierParameters(params.classifierFilename)
 
-objects = storage.loadTrajectoriesFromSqlite(databaseFilename, 'object', args.nObjects, withFeatures = True)
+classificationAnnotations = read_csv(args.classificationAnnotationFilename, index_col=0, delimiter = args.classificationAnnotationFilenameDelimiter, names = ["object_num", "road_user_type"])
+annotatedObjectNumbers = classificationAnnotations.index.tolist()
+
+# objects has the objects for which we want to extract labeled images
+if args.extractAllObjectImages:
+    objects = storage.loadTrajectoriesFromSqlite(databaseFilename, 'object', args.nObjects, withFeatures = True)
+else:
+    if len(annotatedObjectNumbers) > args.nObjects:
+        classificationAnnotations = classificationAnnotations[:args.nObjects]
+        annotatedObjectNumbers = classificationAnnotations.index.tolist()
+    objects = storage.loadTrajectoriesFromSqlite(databaseFilename, 'object', annotatedObjectNumbers, withFeatures = True)
+for obj in objects:
+    if obj.getNum() in annotatedObjectNumbers:
+        obj.setUserType(classificationAnnotations.loc[obj.getNum(), 'road_user_type'])
 timeInterval = moving.TimeInterval.unionIntervals([obj.getTimeInterval() for obj in objects])
 
+for userType in classificationAnnotations['road_user_type'].unique():
+    if not os.path.exists(args.directoryName+os.sep+moving.userTypeNames[userType]):
+        os.mkdir(args.directoryName+os.sep+moving.userTypeNames[userType])
+
 capture = cv2.VideoCapture(videoFilename)
 width = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH))
 height = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT))
 
 if undistort: # setup undistortion
     [map1, map2] = cvutils.computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients)
+
+print(timeInterval)
 if capture.isOpened():
     ret = True
     frameNum = timeInterval.first
     capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, frameNum)
     lastFrameNum = timeInterval.last
-    while ret and frameNum <= lastFrameNum:
+    while ret and frameNum <= timeInterval.last:
         ret, img = capture.read()
         if ret:
             if frameNum%50 == 0:
                 print('frame number: {}'.format(frameNum))
-            if undistort:
+            if undistort: # undistort only if necessary
                 img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR)
-
-
+            for obj in objects:
+                if obj.existsAtInstant(frameNum):
+                    if (obj.getFirstInstant()-frameNum)%args.nFramesStep == 0: # todo find next non zero image if none
+                        croppedImg = cvutils.imageBox(img, obj, frameNum, invHomography, width, height, classifierParams.percentIncreaseCrop, classifierParams.percentIncreaseCrop, classifierParams.minNPixels)
+                        if croppedImg is not None:
+                            imsave(args.directoryName+os.sep+moving.userTypeNames[obj.getUserType()]+args.imagePrefix+'-{}-{}.png'.format(obj.getNum(), frameNum), croppedImg)
+                    elif obj.getLastInstant() == frameNum:
+                        objects.remove(obj)
         frameNum += 1
 
-
-
 # todo speed info: distributions AND min speed equiprobable
 
-# provide csv delimiter for the classification file as arg
-