def filtered_dict(img, low =SNS(h=15, vx=20, vx_yel=10, sx=10, s=75, v=175), #bad @4sec challenge if s=80,v=180 high=SNS(h=35, vx=120,vx_yel=60, sx=100)): ''' Returns dict of 7 filtered channels on img of: 'yel': yellow filter via h channel 'white': white filter via s channel 'white2': white filter with narrower thresholds 'posEdge': possitive sobelx via v channel 'negEdge': negative sobelx via v channel 'yelPos': possitive sobelx via s channel for yellow 'yelNeg': negative sobelx via s channel for yellow (all h,s,v channels are of hsv space) ''' d = {} hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV).astype(np.float) h_ch = hsv[:,:,0] s_ch = hsv[:,:,1] v_ch = hsv[:,:,2] ## color thresholds d['yel'] = np.zeros_like(h_ch) d['yel'][(h_ch >= low.h) & (h_ch <= high.h) & (s_ch >= low.s)] = 1 d['white'] = np.zeros_like(v_ch) d['white'][(v_ch >= low.v+s_ch+20)] = 1 d['white2'] = np.copy(d['white']) d['white2'][v_ch >= low.v+s_ch] = 1 ## edge with sobel vx_pos = cv2.Sobel(v_ch, cv2.CV_64F, 1, 0, ksize=3) vx_pos[vx_pos <= 0] = 0 vx_pos = scale_255(vx_pos) vx_neg = np.copy(vx_pos) vx_neg[vx_neg > 0] = 0 vx_neg = np.absolute(vx_neg) vx_neg = scale_255(vx_neg) d['posEdge'] = np.zeros_like(vx_pos) d['posEdge'][(vx_pos >= low.vx) & (vx_pos <= high.vx)] = 1 d['negEdge'] = np.zeros_like(vx_neg) d['negEdge'][(vx_neg >= low.vx) & (vx_neg <= high.vx)] = 1 sobelx = cv2.Sobel(s_ch, cv2.CV_64F, 1, 0, ksize=3) sobelx = np.absolute(sobelx) sobelx = scale_255(sobelx) d['yelPos'] = np.zeros_like(sobelx) d['yelPos'][(sobelx >= low.sx) & (sobelx <= high.sx) & (vx_pos >= low.vx_yel) & (vx_pos <= high.vx_yel)] = 1 d['yelNeg'] = np.zeros_like(sobelx) d['yelNeg'][(sobelx >= low.sx) & (sobelx <= high.sx) & (vx_neg >= low.vx_yel) & (vx_neg <= high.vx_yel)] = 1 return d
def fixClassHook(): aRecord = [] class C1(BaseClass): @hook('hook1') def f2(self, a=0): aRecord.append(self) aRecord.append(a + 2) class C2(BaseClass): @hook('hook1') def f3(self, a=0): aRecord.append(self) aRecord.append(a + 3) class C1a(C2, C1): @hook('hook1') def f1(self, a=0): aRecord.append(self) aRecord.append(a + 1) class C1b(C1a): @hook('hook1', atTop=True) def f6(self, a=0): aRecord.append(self) aRecord.append(a + 6) return SNS(aRecord=aRecord, C1=C1, C2=C2, C1a=C1a, C1b=C1b)
def fixLogger(fs, request): class ClassLog(UnladenWithLogging): def args(cls, parser): parser.add_argument('--num', type=int, default=0) def main(self, ns): self.logger.debug('maindebug.{:d}'.format(ns.num)) return SNS(fs=fs, ClassLog=ClassLog, fname=request.param)
def color_hist(img, bins=32, ranges=[(0,256)]*3): ch1 = np.histogram(img[:, :, 0], bins=bins, range=ranges[0]) ch2 = np.histogram(img[:, :, 1], bins=bins, range=ranges[1]) ch3 = np.histogram(img[:, :, 2], bins=bins, range=ranges[2]) chs = [ch1, ch2, ch3] return SNS( hist=np.concatenate([ch[0] for ch in chs]), bin_edges=np.concatenate([ch[1] for ch in chs]), )
def runcmd(self, args=()): # Deliberately not putting this into args, so there won't be default value in args if len(args) > 0 and args[0] == '--version': print(get_distribution('unladen-chant').version) sys.exit(0) self.invokeHook('preParse', args) ns = self.parser.parse_args(args, namespace=SNS(**self._defaults)) self.run(**vars(ns))
def fixTimer(fs, request): class ClassTimer(UnladenWithTiming): def main(self, ns): pass class ClassTimer2(UnladenWithTiming): def main(self, ns): ClassTimer().runcmd(('--colorful-header', )) return SNS(fs=fs, ClassTimer=ClassTimer, ClassTimer2=ClassTimer2)
def filteredPixels(filtereds): ''' Returns nonzero pixels object for filters in filtereds in x and y dims. filtereds: warped filters dict (see filtered_dict() for list of filters) ''' o = SNS(x={}, y={}) for fltr in filtereds: nonzero = filtereds[fltr].nonzero() o.x[fltr] = np.array(nonzero[1]) o.y[fltr] = np.array(nonzero[0]) return o
def fixReturnHook(): class C(BaseClass): @hook('hook1') def f(self): return self @hook('hook1') def f2(self): return "f2" return SNS(C=C, o=C())
def pxObj(): ''' Returns object of: x: array of L/R pixels in x coordinates y: array of L/R pixels in y coordinates found: array of L/R line found boolean ''' return SNS( x = [None, None], y = [None, None], found = [False, False] )
def fixListNs(): mNs = {} class ClassListNs(UnladenWithCmdline): def main(self, ns): mNs.update(vars(ns)) class ClassParse(ClassListNs): def args(cls, parser): parser.add_argument('--option', '-o', type=int, default=15) return SNS(mNs=mNs, ClassListNs=ClassListNs, ClassParse=ClassParse)
def fixSimpleHook(): aRecord = [] class C(BaseClass): @hook('hook1') def f(self): aRecord.append(self) def f0(self, a=0): aRecord.append(0) return SNS(aRecord=aRecord, C=C, o=C(), f0=f0)
def hog_vis(img, orientations=8, pxs_per_cell=8, cells_per_blk=2, feature_vector=False): ''' Histogram of Oriented Gradients, visualise=True ''' result = skFeat.hog(img, orientations=orientations, pixels_per_cell=(pxs_per_cell,pxs_per_cell), cells_per_block=(cells_per_blk,cells_per_blk), transform_sqrt=True, visualise=True, feature_vector=feature_vector ) return SNS( features=result[0], images=result[1], )
def fixtureFlowCheck(): aRecord = [] class TaskBasic(UnladenTaskBase): def main(self, ns): aRecord.append('main' + str(getattr(ns, 'a', 0))) return True class TaskWithHooks(TaskBasic): @hook('preMain') def preMain1(self, ns): aRecord.append('pre' + str(getattr(ns, 'a', 0))) return True @hook('postMain') def postMain1(self, ns): aRecord.append('post' + str(getattr(ns, 'a', 0))) return True return SNS(aRecord=aRecord, TaskBasic=TaskBasic, TaskWithHooks=TaskWithHooks)
import numpy as np import cv2, time from sklearn.externals import joblib from lib.detection import * from config import pklpath, default, defaults from types import SimpleNamespace as SNS from moviepy.editor import VideoFileClip t = time.time() model = SNS( classifier=joblib.load(pklpath.svc), scaler=joblib.load(pklpath.scaler), train_size=default.train_size, defaults=defaults, ) detector = CarDetector(model, (720, 1280)) def process_image(img): return detector.detected_image(img) # video_in = False # video_in = 'video-in/test1.mp4' # video_in = 'video-in/prob6.mp4' #ffmpeg -i project_video.mp4 -ss 00:00:13 -codec copy -t 6 prob6.mp4 # video_in = 'video-in/prob8.mp4' #ffmpeg -i project_video.mp4 -ss 00:00:38.4 -codec copy -t 8 prob8.mp4 # video_in = 'video-in/prob9.mp4' #ffmpeg -i project_video.mp4 -ss 00:00:10.8 -codec copy -t 9 prob9.mp4 # video_in = 'video-in/prob10.mp4' #ffmpeg -i project_video.mp4 -ss 00:00:22.8 -codec copy -t 10 prob10.mp4 video_in = 'video-in/project_video.mp4'
self.fit += coef[poly_order] # one more += for _0_to_ht**0 self.coef = coef if self.fit_MA == None: self.set_all(False) self.set_center_and_curve_radius(self.coef) def fit_vs_MA(self): ''' Returns norm of difference of current fit x positions vs. its MA ''' return linNorm(self.fit - self.fit_MA) _max = SNS( fitdiff=1700, # poor left lane fit if < 1700 on project vid @38sec fit_err=80, fail=2, ) def bad_fit_diff(lf_coef, rt_coef, lf_radius, rt_radius, min_radm=1000): ''' Returns if the difference between coefs of left and right fits are more than an order of magnitude than expected. min_radm: Min expected radius in meters. Adjust to actual min of road radius. ''' lf_coef = np.array(lf_coef) rt_coef = np.array(rt_coef) fitdiff = lf_coef - rt_coef min_of_2 = np.minimum(np.absolute(lf_coef), np.absolute(rt_coef)) expected = (min_radm * 2) / (abs(lf_radius) + abs(rt_radius)) return linNorm(fitdiff[:2] / min_of_2[:2]) * expected > 10
from glob import glob from os.path import join from types import SimpleNamespace as SNS pklpath = SNS( svc='models/svc-all3-hog12-luv.pkl', scaler='models/scaler-all3-hog12-luv.pkl', # svc='models/svc.pkl', # scaler='models/scaler.pkl', ) imgspath = '../data' cars_imgspath = glob(join(imgspath, 'vehicles', '*/*.png')) notcars_imgspath = glob(join(imgspath, 'non-vehicles', '*/*.png')) default = SNS( # color_space='YCrCb', # Can be RGB, HSV, LUV, HLS, YUV, YCrCb(tried, not good) # orient = 10, # HOG orientations, 10 misses much more than 12 color_space='LUV', # Can be RGB, HSV, LUV, HLS, YUV, YCrCb(tried, not good) orient=12, # HOG orientations, 10 misses much more than 12 pix_per_cell=8, # HOG pixels per cell cell_per_block=2, # HOG cells per block hog_channel='ALL', # Can be 0, 1, 2, or "ALL" train_size=(64, 64), # train image size spatial_size=(32, 32), # Spatial binning dimensions hist_bins=32, # Number of histogram bins hog_feat=True, hist_feat=True, # worst if no hist spatial_feat=True, # much worst if no spatial ) defaults = { 'color_space': default.color_space,
import numpy as np import cv2, json from types import SimpleNamespace as SNS with open('camera_cal.json', 'r') as f: global cam camera = json.load(f) cam = SNS( mtx=np.array(camera['mtx']), dist=np.array(camera['dist']), ) def undistort(img): return cv2.undistort(img, cam.mtx, cam.dist, None, cam.mtx)
def run(self, **kwargs): return self.runWithNs(SNS(**kwargs))
def cars_coords_str(cars): return ' '.join([car.coords_str for car in cars]) def coords_gen(wins, txt=''): return ('; '.join(['x0=%d, wd=%d' % (_x0(win), _wd(win)) for win in wins])) ## Settings for side wins dbg = SNS( crop = { # these settings work with 4,6,7 lines of btm text, fails on 5 lines 'top':350, 'btm':30, 'left':0, 'right':0, }, wins_cnt = 3, ) _colors = [(255, 0, 0), (0, 0, 255), (0, 255, 0)] def _color(i): return _colors[i % len(_colors)] car_labels = string.ascii_uppercase[:26]
def xyfound(roi, filtereds, filteredPxs, img, windows=True, minpct={'cnt':.011, 'white':.011, 'yel':.032}, maxpct={'cnt':1.1, 'white2':.88, 'white2InWins':.22, 'white':.55, 'whiteInWins':.055}, minpxs=None, maxpxs=None): ''' Returns tuple of (x-coords, y-coords, found, filters-used) of lane detection roi: ROI of dict of different filtered pixels filtereds: warped filters dict (see filtered_dict() for list of filters) filteredPxs: filteredPixels() result windows: full detection via windows or not minpct, maxpct: min/max pixels % of total image pixels thresholds dict minpxs, maxpxs: min/max pixels thresholds dict, overrides minpct/maxpct ''' nPixels = img.shape[0]*img.shape[1] # calc min and max pxs from pct params if not minpxs: minpxs = {} for k,v in minpct.items(): minpxs[k] = int(v*.01*nPixels) minpx = SNS(**minpxs) if not maxpxs: maxpxs = {} for k,v in maxpct.items(): maxpxs[k] = int(v*.01*nPixels) maxpx = SNS(**maxpxs) # global printThresholds # if printThresholds: # print('Min Thresholds used:', minpxs) # print('Max Thresholds used:', maxpxs) # printThresholds = False pxCnt, mean, stdev = {}, {}, {} for fltr in filtereds: _pxCnt = np.sum(roi[fltr]) if _pxCnt < minpx.cnt or (windows and _pxCnt > maxpx.cnt): continue pxCnt[fltr] = _pxCnt mean[fltr] = np.mean(filteredPxs.x[fltr][roi[fltr]]) stdev[fltr] = np.std(filteredPxs.x[fltr][roi[fltr]]) filters = pxCnt.keys() pxCnt = SNS(**pxCnt) if windows: used = [c for c in filters if stdev[c]<35] else: used = [c for c in filters] # remove poor filters if 'posEdge' in used: if 'negEdge' not in filters: used.remove('posEdge') if 'yelPos' in used: if 'yelNeg' not in filters: used.remove('yelPos') if ('white2' in used): if 'white' in used: used.remove('white') if pxCnt.white2 > maxpx.white2 or (windows and pxCnt.white2 > maxpx.white2InWins): used.remove('white2') if 'white' in used and (pxCnt.white < minpx.white or pxCnt.white > maxpx.white): used.remove('white') if windows and 'white' in used and pxCnt.white > maxpx.whiteInWins: used.remove('white') if 'yel' in used and pxCnt.yel < minpx.yel: used.remove('yel') # combine all used channels combine_x, combine_y = [],[] for fltr in used: combine_x.append(filteredPxs.x[fltr][roi[fltr]]) combine_y.append(filteredPxs.y[fltr][roi[fltr]]) if combine_x: return np.concatenate(combine_x), np.concatenate(combine_y), True, used else: return None, None, False, used
def findlinepixs(self, nwindows=10): ''' Find lane lines with mean and stddev via sliding windows Sets self.pxs to pxsObj() of result ''' filtereds, wht, yel = warpedChannels(filtered_dict(self.img), self) self.init_side_wins(wht, yel) win_ht = self.img_ht//nwindows qtr_wd = self.img_wd//4 _3qtrs = qtr_wd*3 default_margin = 150 margin = [qtr_wd, qtr_wd] x_mean = [qtr_wd, _3qtrs] prvx_mean = [qtr_wd, _3qtrs] prvx = [None, None] # save prvx_mean if it's good pixels = filteredPixels(filtereds) pxs = pxsObj() lanes_gap = self.img_wd//2 momentum = [0, 0] last_update = [0, 0] # Step through the windows one by one for i in range(nwindows): # window boundaries wb = SNS( x0 = [int(x_mean[side] - margin[side]) for side in LR], x1 = [int(x_mean[side] + margin[side]) for side in LR], y0 = self.img_ht - (i+1)*win_ht, y1 = self.img_ht - i*win_ht, ) px, used = filteredBoundsPxObj(wb, filtereds, pixels, self.img) if noLaneFound(lanes_gap, x_mean, self.img_wd): break gap = min(lanes_gap, self.img_wd//2) if px.found[L] or px.found[R]: margin[L] = 50 if px.found[L] else 150 margin[R] = 50 if px.found[R] else 150 x_mean[L] = np.mean(px.x[L]) if px.found[L] else np.mean(px.x[R]) - gap x_mean[R] = np.mean(px.x[R]) if px.found[R] else np.mean(px.x[L]) + gap for side in LR: x_mean[side] = np.int(x_mean[side]) if px.found[L] or px.found[R]: lanes_gap = (lanes_gap + prvx_mean[R] - prvx_mean[L])/2 else: margin[L] = default_margin margin[R] = default_margin for side in LR: # Add good pixels to list if px.found[side]: pxs.x[side].append(px.x[side]) pxs.y[side].append(px.y[side]) prvx_mean[side] = x_mean[side] # Draw the windows on the visualization image draw.rect(self.side_wins[0], ((wb.x0[side],wb.y0), (wb.x1[side],wb.y1)), (0,255,side*255)) draw.rect(self.side_wins[1], ((wb.x0[side],wb.y0), (wb.x1[side],wb.y1)), (0,255,side*255)) self.side_wins[2][px.y[side], px.x[side], 2] = 255 if px.found[side]: txt = '%d'%x_mean[side] txtpos = x_mean[side]-130 if len(txt)==3 else x_mean[side]-175 cv2.putText(self.side_wins[2], txt, (txtpos, wb.y0+win_ht-13), font, fontsize, (0,255,255), txtwd, linetype) # decide window centers based on previous windows last_update[side] += 1 if prvx[side]: momentum[side] = np.int(momentum[side]) if px.found[side]: momentum[side] += ((x_mean[side] - prvx[side])/(last_update[side]))//2 if px.found[side]: prvx[side] = x_mean[side] last_update[side] = 0 x_mean[side] += momentum[side] for side in LR: if pxs.x[side]: pxs.found[side] = True pxs.x[side] = np.concatenate(pxs.x[side]) pxs.y[side] = np.concatenate(pxs.y[side]) else: pxs.x[side] = None pxs.y[side] = None self.pxs = pxs