You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
8.0 KiB
221 lines
8.0 KiB
"""
|
|
Programmer : EOF
|
|
File : detector.py
|
|
E-mail : jasonleaster@163.com
|
|
Date : 2016.01.18
|
|
"""
|
|
|
|
from config import TRAINING_IMG_WIDTH
|
|
from config import TRAINING_IMG_HEIGHT
|
|
from config import HAAR_FEATURE_TYPE_I
|
|
from config import HAAR_FEATURE_TYPE_II
|
|
from config import HAAR_FEATURE_TYPE_III
|
|
from config import HAAR_FEATURE_TYPE_IV
|
|
from config import AB_TH
|
|
from config import SEARCH_WIN_STEP
|
|
|
|
from image import Image
|
|
from haarFeature import Feature
|
|
from matplotlib import pyplot
|
|
from adaboost import getCachedAdaBoost
|
|
import pylab
|
|
import numpy
|
|
|
|
|
|
class Detector:
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
def scanImgAtScale(self, model, image, scale):
|
|
assert isinstance(image, numpy.ndarray)
|
|
|
|
ImgHeight, ImgWidth = image.shape
|
|
|
|
SEARCH_WIN_WIDTH = int(TRAINING_IMG_WIDTH * scale)
|
|
SEARCH_WIN_HEIGHT = int(TRAINING_IMG_HEIGHT * scale)
|
|
|
|
width = ImgWidth - SEARCH_WIN_WIDTH - 10
|
|
height = ImgHeight - SEARCH_WIN_HEIGHT - 10
|
|
|
|
step = SEARCH_WIN_WIDTH // SEARCH_WIN_STEP
|
|
|
|
subWinNum = (width // step + 1) * (height // step + 1)
|
|
|
|
subImages = numpy.zeros(subWinNum, dtype=object)
|
|
subWins = numpy.zeros(subWinNum, dtype=object)
|
|
|
|
idx = 0
|
|
for x in range(0, width, step):
|
|
for y in range(0, height, step):
|
|
subWins[idx] = (x, y, SEARCH_WIN_WIDTH, SEARCH_WIN_HEIGHT)
|
|
|
|
subImages[idx] = Image(Mat=image[y:y + SEARCH_WIN_HEIGHT, x:x + SEARCH_WIN_WIDTH])
|
|
idx += 1
|
|
|
|
assert idx <= subWinNum
|
|
|
|
subImgNum = idx
|
|
|
|
selFeatures = numpy.zeros(model.N, dtype=object)
|
|
|
|
haar_scaled = Feature(SEARCH_WIN_WIDTH, SEARCH_WIN_HEIGHT)
|
|
haar_train = Feature(TRAINING_IMG_WIDTH, TRAINING_IMG_HEIGHT)
|
|
|
|
for n in range(model.N):
|
|
selFeatures[n] = haar_train.features[model.G[n].opt_dimension] + tuple([model.G[n].opt_dimension])
|
|
|
|
mat = numpy.zeros((haar_train.featuresNum, subImgNum), dtype=numpy.float16)
|
|
|
|
for feature in selFeatures:
|
|
(types, x, y, w, h, dim) = feature
|
|
|
|
x = int(x * scale)
|
|
y = int(y * scale)
|
|
w = int(w * scale)
|
|
h = int(h * scale)
|
|
|
|
for i in range(subImgNum):
|
|
if types == HAAR_FEATURE_TYPE_I:
|
|
mat[dim][i] = haar_scaled.VecFeatureTypeI(subImages[i].vecImg, x, y, w, h)
|
|
elif types == HAAR_FEATURE_TYPE_II:
|
|
mat[dim][i] = haar_scaled.VecFeatureTypeII(subImages[i].vecImg, x, y, w, h)
|
|
elif types == HAAR_FEATURE_TYPE_III:
|
|
mat[dim][i] = haar_scaled.VecFeatureTypeIII(subImages[i].vecImg, x, y, w, h)
|
|
elif types == HAAR_FEATURE_TYPE_IV:
|
|
mat[dim][i] = haar_scaled.VecFeatureTypeIV(subImages[i].vecImg, x, y, w, h)
|
|
|
|
output = model.grade(mat)
|
|
|
|
rectangle = []
|
|
for i in range(len(output)):
|
|
if output[i] > AB_TH:
|
|
candidate = numpy.array(subWins[i])
|
|
x, y, w, h = candidate
|
|
rectangle.append((x, y, w, h, output[i]))
|
|
|
|
return rectangle
|
|
|
|
def scanImgOverScale(self, image):
|
|
|
|
from config import DETECT_START
|
|
from config import DETECT_END
|
|
from config import DETECT_STEP
|
|
from config import ADABOOST_CACHE_FILE
|
|
from config import ADABOOST_LIMIT
|
|
|
|
model = getCachedAdaBoost(filename=ADABOOST_CACHE_FILE + str(0), limit=ADABOOST_LIMIT)
|
|
|
|
rectangles = []
|
|
|
|
for scale in numpy.arange(DETECT_START, DETECT_END, DETECT_STEP):
|
|
rectangles += self.scanImgAtScale(model, image, scale)
|
|
|
|
return self.optimalRectangle(rectangles)
|
|
|
|
def optimalRectangle(self, rectangles):
|
|
# number of rectangles
|
|
numRec = len(rectangles)
|
|
|
|
for i in range(numRec):
|
|
for j in range(i + 1, numRec):
|
|
if rectangles[i][4] < rectangles[j][4]:
|
|
rectangles[i], rectangles[j] = \
|
|
tuple(rectangles[j]), tuple(rectangles[i])
|
|
|
|
"""
|
|
(x1, y1, w1, h1) represent as the first rectangle.
|
|
(x2, y2, w2, h2) represent as the second rectangle.
|
|
|-------> x
|
|
| _______
|
|
|| 1 __|____
|
|
||____|__| |
|
|
| |____2__|
|
|
\/ y
|
|
"""
|
|
reduced = [i for i in range(numRec)]
|
|
for i in range(numRec):
|
|
x1, y1, w1, h1, score1 = rectangles[i]
|
|
area_1 = w1 * h1
|
|
for j in range(i + 1, numRec):
|
|
x2, y2, w2, h2, score2 = rectangles[j]
|
|
area_2 = h2 * w2
|
|
|
|
if (self.pointInRectangle((x2, y2), rectangles[i]) or
|
|
self.pointInRectangle((x2 + w2, y2), rectangles[i]) or
|
|
self.pointInRectangle((x2, y2 + h2), rectangles[i]) or
|
|
self.pointInRectangle((x2 + w2, y2 + h2), rectangles[i]) or
|
|
self.pointInRectangle((x2 + w2 / 2, y2), rectangles[i]) or
|
|
self.pointInRectangle((x2, y2 + h2 / 2), rectangles[i]) or
|
|
self.pointInRectangle((x2 + w2, y2 + h2 / 2), rectangles[i]) or
|
|
self.pointInRectangle((x2 + w2 / 2, y2 + h2), rectangles[i])) is True:
|
|
reduced[j] = reduced[i]
|
|
|
|
if (self.pointInRectangle((x1, y1), rectangles[j]) or
|
|
self.pointInRectangle((x1 + w1, y1), rectangles[j]) or
|
|
self.pointInRectangle((x1, y1 + h1), rectangles[j]) or
|
|
self.pointInRectangle((x1 + w1, y1 + h1), rectangles[j]) or
|
|
self.pointInRectangle((x1 + w1 / 2, y1), rectangles[j]) or
|
|
self.pointInRectangle((x1, y1 + h1 / 2), rectangles[j]) or
|
|
self.pointInRectangle((x1 + w1, y1 + h1 / 2), rectangles[j]) or
|
|
self.pointInRectangle((x1 + w1 / 2, y1 + h1), rectangles[j])) is True:
|
|
reduced[j] = reduced[i]
|
|
|
|
reducedRectangels = []
|
|
for i in numpy.unique(reduced):
|
|
reducedRectangels.append(rectangles[i])
|
|
|
|
return reducedRectangels
|
|
|
|
def pointInRectangle(self, point, rectangle):
|
|
m, n = point
|
|
x, y, w, h, _ = rectangle
|
|
|
|
if ((x < m and m < x + w) and (y < n and n < y + h)):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def drawRectangle(self, image, x, y, width, height):
|
|
assert isinstance(image, numpy.ndarray)
|
|
|
|
if len(image.shape) != 2:
|
|
Row, Col, _ = image.shape
|
|
if x + width >= Col or y + height >= Row:
|
|
return
|
|
image[y:y + height, x - 1:x + 1, 0] = 0
|
|
image[y:y + height, x - 1:x + 1, 1] = 255
|
|
image[y:y + height, x - 1:x + 1, 2] = 0
|
|
|
|
image[y:y + height, (x - 1 + width):(x + 1 + width), 0] = 0
|
|
image[y:y + height, (x - 1 + width):(x + 1 + width), 1] = 255
|
|
image[y:y + height, (x - 1 + width):(x + 1 + width), 2] = 0
|
|
|
|
image[y - 1:y + 1, x:x + width, 0] = 0
|
|
image[y - 1:y + 1, x:x + width, 1] = 255
|
|
image[y - 1:y + 1, x:x + width, 2] = 0
|
|
|
|
image[(y - 1 + height):(y + height + 1), x:x + width, 0] = 0
|
|
image[(y - 1 + height):(y + height + 1), x:x + width, 1] = 255
|
|
image[(y - 1 + height):(y + height + 1), x:x + width, 2] = 0
|
|
else:
|
|
Row, Col = image.shape
|
|
if x + width >= Col or y + height >= Row:
|
|
return
|
|
|
|
image[y:y + height, x - 1:x + 1] = 255
|
|
image[y:y + height, x - 1 + width:x + 1 + width] = 255
|
|
image[y - 1:y + 1, x:x + width] = 255
|
|
image[y - 1 + height:y + 1 + height, x:x + width] = 255
|
|
|
|
pyplot.imshow(image)
|
|
pylab.show()
|
|
|
|
def showResult(self, image, rectangles):
|
|
|
|
for rectangle in rectangles:
|
|
x, y, width, height, score = rectangle
|
|
|
|
print(rectangle)
|
|
self.drawRectangle(image, x, y, width, height)
|