這個演算法基本上是去利用 老鼠的顏色和消去背景法去判斷出老鼠...
同時再利用老鼠的形狀幾何再判斷一次...
可以調的參數
1. binary_thr_tor : 老鼠顏色的容忍度,
2. subtract_background_frame_cnt: 幾張之後背景演算法才會穩定
3. area_thr : 老鼠面積的低標
4. area_thr_max : 老鼠面積的高標
5. dist_thr : 距離的高標
6. mouse_end_en : 老鼠跑到終點後要不要停止
7. mouse_end_point_dist_thr : 老鼠到終點的距離半徑, 越大越容易停止
程式碼的說明
一開始會先去抓 老鼠的顏色thr value
binary_thr = get_mouse_grayval(frame,sx,sy) + binary_thr_tor
binary_thr_tor = 20;
這個數值是 可以手動調整的
def get_mouse_grayval(frame,sx,sy):
image = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
val_c = image[sy,sx]
val_r = image[sy,sx+1]
val_l = image[sy,sx-1]
val_t = image[sy-1,sx]
val_b = image[sy+1,sx]
val = (int(val_c) + int(val_r) + int(val_l) + int(val_t) + int(val_b))/5
這個類似一個low pass 取平均的做法...抓到老鼠的灰階數值...
接下來就一個大的loop
去掃每一張 frame
while(1):
ret, frame = cap.read() -> frame 就是input frame的地方
if(ret == False):
break
# 利用 thr 去判斷老鼠在那裏
im = image_preprocess(frame,file_index,binary_thr)
# 利用 opencv subbackground algorithm 去除背景
im2 = image_background_subtract(frame,file_index)
# 把上述兩個方法一起判斷
im_and = image_and(im,im2,file_index)
(get_mouse, cx,cy,area) = draw_contour(im_and,area_thr,area_thr_max,dist_thr,sx,sy)
.....
def image_preprocess(frame,file_index,thr):
global kernel
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
filename = "./bg_subtract/source/out{0:05d}.jpg".format(file_index)
cv2.imwrite(filename,frame) # debug used
# thr 就是一開始算出來的 thr,
ret,fgmask = cv2.threshold(frame,thr,255,cv2.THRESH_BINARY_INV)
# THRESH_BINARY_INV, 就是說小於這個thr的pixel留下來, 大於這個thr移除掉
# remove noise
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
# dilate
fgmask = cv2.dilate(fgmask,kernel,iterations = 1)
filename = "./bg_subtract/result_binary/out{0:05d}.jpg".format(file_index)
cv2.imwrite(filename,fgmask)
return fgmask
def image_background_subtract(frame,file_index):
global kernel
global fgbg
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(frame)
# remove noise
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
# dilate
fgmask = cv2.dilate(fgmask,kernel,iterations = 1)
# remove some shadow
ret,fgmask = cv2.threshold(fgmask,140,255,cv2.THRESH_BINARY)
filename = "./bg_subtract/result_subtract/out{0:05d}.jpg".format(file_index)
cv2.imwrite(filename,fgmask)
return fgmask
def image_background_subtract(frame,file_index):
global kernel
global fgbg
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(frame)
# remove noise
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
# dilate
fgmask = cv2.dilate(fgmask,kernel,iterations = 1)
# remove some shadow
# 這邊也是一個可以調的參數, 建議是不要去動他
ret,fgmask = cv2.threshold(fgmask,140,255,cv2.THRESH_BINARY)
filename = "./bg_subtract/result_subtract/out{0:05d}.jpg".format(file_index)
cv2.imwrite(filename,fgmask)
return fgmask
#
def image_and(frame1,frame2,file_index):
global subtract_background_frame_cnt
# 這個演算法是利用iteration的方式找出不會動的背景,
# 所以一開始會找不到老鼠
# 只好小於subtract_background_frame_cnt 的frame都判斷可以找到老鼠
if(file_index < subtract_background_frame_cnt):
fgmask = frame1
else:
ret,mask = cv2.threshold(frame1,10,255,cv2.THRESH_BINARY)
fgmask = cv2.bitwise_and(frame2,frame2,mask = mask)
filename = "./bg_subtract/result_and/out{0:05d}.jpg".format(file_index)
cv2.imwrite(filename,fgmask)
return fgmask
# 找出老鼠, 這裡還會用面積的方是在判斷一次
def draw_contour(im,area_thr,area_thr_max,dist_thr,sx,sy):
dst ,contours, hierarchy = cv2.findContours(im,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
get_mouse = 0
cx = 0
cy = 0
area = 0
for i in range(len(contours)):
cnt = contours[i]
M = cv2.moments(cnt)
area = cv2.contourArea(cnt)
perimeter = cv2.arcLength(cnt,True)
x,y,w,h = cv2.boundingRect(cnt)
(cx,cy),radius = cv2.minEnclosingCircle(cnt)
center = (int(cx),int(cy))
start = (sx,sy)
radius = int(radius)
dist = distance(sx,sy,int(cx),int(cy))
# area_thr -> 一定要大於 area_thr,
# 這裏我假設老鼠有慣性, 不會這張找到的老鼠和上一張找到得老鼠
# 跳太遠, 設了一個 高標 dist_thr, 一定要小於這個 dist_thr
# area_thr_max, 但是老鼠也不能太大隻, 所以設了一個thr
if( (area > area_thr) & (dist < dist_thr) & (area < area_thr_max) ):
print "area : " + str(area)
get_mouse = 1