In [8]:
import cv2
import numpy as np
import pickle
In [19]:
def nothing(x):
pass
def hist_equalize_bgr(frame):
'''
Converts to YCrCb colorspace and applies histogram equalization to help with contrast.
Only applies to Y channel. Returns an RGB image.'''
#Convert to
frame = cv2.cvtColor(frame,cv2.COLOR_RGB2YCrCb)
frame[:,:,0] = cv2.equalizeHist(frame[:,:,0])
frame = cv2.cvtColor(frame,cv2.COLOR_YCrCb2RGB)
return frame
def smooth(frame, kern=(3,3)):
'''
Smooth an image using gaussian blur:
kern:Shape of the gaussian kernel, larger numbers make the image more blurred.
'''
return cv2.blur(frame, kern)
def resize_show(frame, params, window='Unmanipulated'):
'''
Resizes and image and displays it.
params: dictionary containing the resize ratio for the x direction, 'fx' and y direction 'fy'
window: name of opencv2 window to display image. See cv2.imshow doc for more info.
'''
frame = cv2.resize(frame,None,fx=params['fx'], fy=params['fy'], interpolation = cv2.INTER_CUBIC)
cv2.imshow(window,frame)
cv2.waitKey(1)
def convert_color(frame, conversion=cv2.COLOR_RGB2HSV):
'''
Convenience function to wrap converstion from RGB to HSV
'''
return cv2.cvtColor(frame, conversion)
def apply_adaptive_thresh(frame,params):
'''
Equalizes the intensity values of a frame, converts to gray, uses adaptive thresholding and applies
morphological opening to remove small bits of noise.
frame: image frame, assumed to be recently read from a video (bgr)
params: dictionary containing
kern: size of structuring element for mophological opening
BS: Block size, defines the area by which
'''
#Create a kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(params['kern'],params['kern']))
#Equalize histogram
frame = hist_equalize_bgr(frame)
#Convert to Grayscale
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
#Threshold and remove small peices of noise. ADAPTIVE_THRESH_GAUSSIAN_C could be used... slightly better results
#but nontrivial cost in terms of processing speed.
frame = cv2.adaptiveThreshold(frame,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY_INV,params['BS'],params['C'])
frame = cv2.morphologyEx(frame, cv2.MORPH_OPEN, kernel)
#Show Image, resized
return frame
def get_thresh_contours(frame, params):
im2, contours, hierarchy = cv2.findContours(frame,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
goodCont = []
for cnt in contours:
area = cv2.contourArea(cnt)
if params['amin'] < area < params['amax']:
goodCont.append(cnt)
return goodCont
class TrackVideo():
def __init__(self,video, params):
'''
Starts an instance of a video tracking objects.
keyword arguments:
video: The video file to be tracked
params: a dictionary containing the following
fx:resize ratio in the x direction for display
fy:resize ratio in the y direction for display
'''
self.video = video
self.params = params
self.init()
'''
for idx in range(100):
frame = self.update()
'''
def test_settings_adaptivethresh(self, nframes=1000):
'''
Runs nframes of adaptive thresholding and allows you to play with the key paramters.
Use save parameters method to save paramters after the window closes.
'''
cv2.namedWindow('TestSettings')
cv2.createTrackbar('Block Size','TestSettings',3,255,nothing)
cv2.createTrackbar('C','TestSettings',1,255,nothing)
cv2.createTrackbar('KERN','TestSettings',1,25,nothing)
#Start with some OK defaults
cv2.setTrackbarPos('Block Size', 'TestSettings', self.params['BS'])
cv2.setTrackbarPos('C','TestSettings',self.params['C'])
cv2.setTrackbarPos('KERN', 'TestSettings',self.params['kern'])
for idx in range(nframes):
#Get Settings, clean them and store
self.params['BS'] = cv2.getTrackbarPos('Block Size','TestSettings')
if self.params['BS'] % 2 ==0:
self.params['BS'] +=1 #Needs to be odd
cv2.setTrackbarPos('Block Size', 'TestSettings', self.params['BS'])
if self.params['BS'] < 3:
self.params['BS'] == 3
cv2.setTrackbarPos('Block Size', 'TestSettings', self.params['BS'])
self.params['C'] = cv2.getTrackbarPos('C','TestSettings')
self.params['kern'] = cv2.getTrackbarPos('KERN','TestSettings')
if self.params['kern'] % 2 == 0:
self.params['kern'] +=1
cv2.setTrackbarPos('KERN', 'TestSettings',self.params['kern'])
if self.params['kern'] < 3:
self.params['kern'] == 3
cv2.setTrackbarPos('KERN', 'TestSettings',self.params['kern'])
#Proceses and display Frame
ret, frame = self.cap.read()
frame = apply_adaptive_thresh(frame, self.params)
resizedFrame = resize_show(frame,self.params,'TestSettings')
cv2.destroyWindow('TestSettings')
cv2.waitKey(1)
def test_settings_ath(self,segment, nframes=500, amaxPossible=500, aminPossible=0):
'''
Allows you to test area threshold
segment: function used to transform image into binary image
nframes: how long to allow you to play with settings
amaxPossible: largest value for the scroll bar to search for a good amax
aminPossible: smallest value for the scroll bar to search for a good amin
'''
#Make a window
cv2.namedWindow('TestSettings')
#add track bars, set them based on params
cv2.createTrackbar('A Min','TestSettings',params['amin'],amaxPossible,nothing)
cv2.createTrackbar('A Max','TestSettings',params['amax'],amaxPossible,nothing)
#Run segmentation, get values, and show results.
for idx in range(nframes):
self.params['amin'] = cv2.getTrackbarPos('A Min', 'TestSettings')
self.params['amax'] = cv2.getTrackbarPos('A Max', 'TestSettings')
ret, unmanipulatedFrame = self.cap.read()
frame = segment(unmanipulatedFrame,self.params)
#Find contours
cnts = get_thresh_contours(frame, self.params)
out = cv2.drawContours(unmanipulatedFrame, cnts, -1, (0,255,255), 2)
resizedFrame = resize_show(out,self.params,'TestSettings')
cv2.destroyWindow('TestSettings')
cv2.waitKey(1)
def process_adaptive_thresh(self,show=True,save='pickle',saveLoc='./test.p'):
self.cap.release()
self.cap = cv2.VideoCapture(self.video)
allCnts = []
#while(cap.isOpened())
for ii in range(300):
ret, unmanipulatedFrame = self.cap.read()
frame = apply_adaptive_thresh(unmanipulatedFrame, self.params)
cnts = get_thresh_contours(frame, self.params)
allCnts.append(cnts)
if show:
out = cv2.drawContours(unmanipulatedFrame, cnts, -1, (0,255,255), 2)
resizedFrame = resize_show(out,self.params,'Processing')
if cv2.waitKey(1) & 0xFF == ord('q'):
break
self.cap.release()
#Refresh the cap incase it needs to be used later.
self.cap = cv2.VideoCapture(self.video)
save(self,cnt)
def save(self,cnt):
pass
def save_params(self):
pass
def load_params(self):
pass
def init(self):
#Clean Params
if self.params['method'] == 'adaptiveThresh':
if self.params['BS'] % 2 ==0:
self.params['BS'] +=1 #Needs to be odd
if self.params['BS'] < 3:
self.params['BS'] == 3
if self.params['kern'] % 2 == 0:
self.params['kern'] +=1
if self.params['kern'] < 3:
self.params['kern'] == 3
#Start a cap and grab a frame.
self.cap = cv2.VideoCapture(self.video)
ret, self.testImg = self.cap.read()
def kill_all(self):
self.cap.release()
cv2.destroyAllWindows()
cv2.waitKey(1)
In [ ]:
In [20]:
#Use:
floc = ('../TestVideos/testOutput.mkv')
params = {'fx':.5, #Rezise in x direction
'fy':.5, #Resize in y direction
'method':'adaptiveThresh', #Currently only adaptiveThresh is supported
'BS': 60, #Block size for adaptive threshold
'C': 30, #Added constant for adaptive threshold (See opencv doc for details)
'kern':3, #Size of kernel used for opening (see opencv doc for details)
'amin':0, #Minimum area size for something to be included
'amax':300, #Maximum area size for something to be included
}
f = TrackVideo(floc, params)
#f.test_settings_adaptivethresh()
#f.test_settings_ath(apply_adaptive_thresh)
In [ ]:
f.process_adaptive_thresh()
In [ ]: