forked from BVLC/caffe
-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
""" Example of wrapping a C function that takes C float arrays as input using | ||
the Numpy declarations from Cython """ | ||
|
||
# import both numpy and the Cython declarations for numpy | ||
import numpy as np | ||
cimport numpy as np | ||
cimport cython | ||
|
||
np.import_array() | ||
|
||
# cdefine the signature of our c function | ||
cdef extern from "group_rectangles_with_aux.h": | ||
int groupRectanglesWithAux(float* input, int group_threshold, float eps, \ | ||
float* output, int* scores, int nrows, int ncols) | ||
|
||
def execute(list linput, int group_threshold, float eps = 0.2): | ||
cdef int nrows = len(linput) | ||
cdef int ncols = np.PyArray_DIM(linput[0], 0) | ||
cdef np.ndarray[float, ndim=2, mode="c"] input = np.empty((nrows, ncols), dtype=np.float32) | ||
for i in range(nrows): | ||
input[i, :] = linput[i] | ||
cdef np.ndarray[float, ndim=2, mode="c"] output = np.empty((nrows, ncols), dtype=np.float32) | ||
cdef np.ndarray[np.int32_t, ndim=2, mode="c"] scores = np.empty((nrows, 1), dtype=np.int32) | ||
|
||
cdef int num_output = groupRectanglesWithAux( | ||
<float*> np.PyArray_DATA(input), | ||
group_threshold, | ||
eps, | ||
<float*> np.PyArray_DATA(output), | ||
<int*> np.PyArray_DATA(scores), | ||
nrows, | ||
ncols) | ||
|
||
if ncols > 4: | ||
aux = output[:num_output, 4:] | ||
else: | ||
aux = None | ||
return (np.rint(output[:num_output, :4]).astype(np.int32), aux, scores[:num_output]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from distutils.core import setup, Extension | ||
|
||
# define the extension module | ||
gr_module = Extension('group_rect_module', sources=['groupRectangles.cpp']) | ||
|
||
# run the setup | ||
setup(ext_modules=[gr_module]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#include <vector> | ||
#include <iostream> | ||
|
||
#include <opencv2/objdetect/objdetect.hpp> | ||
|
||
using namespace std; | ||
|
||
using cv::Rect; | ||
|
||
class SimilarRects { | ||
public: | ||
SimilarRects(double _eps) : eps(_eps) {} | ||
inline bool operator() (const vector<float>& r1, const vector<float>& r2) const { | ||
double delta = eps * (std::min(r1[2], r2[2]) + std::min(r1[3], r2[3])) * 0.5; | ||
return std::abs(r1[0] - r2[0]) <= delta && | ||
std::abs(r1[1] - r2[1]) <= delta && | ||
std::abs(r1[0] + r1[2] - r2[0] - r2[2]) <= delta && | ||
std::abs(r1[1] + r1[3] - r2[1] - r2[3]) <= delta; | ||
} | ||
double eps; | ||
}; | ||
|
||
int groupRectanglesWithAux(float* input, int groupThreshold, float eps, | ||
float* output, int* scores, int nrows, int ncols) { | ||
if (groupThreshold <= 0 || nrows == 0) { | ||
return 0; | ||
} | ||
|
||
vector<vector<float> > rectList(nrows, vector<float>(ncols)); | ||
for (int i = 0; i < nrows; ++i) { | ||
int base_index = i * ncols; | ||
for (int j = 0; j < ncols; ++j) { | ||
if (j < 4) { | ||
rectList[i][j] = cv::saturate_cast<int>(input[base_index + j]); | ||
} else { | ||
rectList[i][j] = input[base_index + j]; | ||
} | ||
} | ||
} | ||
|
||
vector<int> labels; | ||
int nclasses = cv::partition(rectList, labels, SimilarRects(eps)); | ||
vector<vector<float> > frects(nclasses, vector<float>(ncols)); | ||
vector<int> rweights(nclasses, 0); | ||
int nlabels = (int) labels.size(); | ||
for (int i = 0; i < nlabels; i++) { | ||
int cls = labels[i]; | ||
for (int j = 0; j < ncols; ++j) { | ||
frects[cls][j] += rectList[i][j]; | ||
} | ||
rweights[cls]++; | ||
} | ||
|
||
for (int i = 0; i < nclasses; i++) { | ||
float s = 1.f / rweights[i]; | ||
for (int j = 0; j < ncols; ++j) { | ||
float scaled = frects[i][j] * s; | ||
if (j < 4) { | ||
frects[i][j] = cv::saturate_cast<int>(scaled); | ||
} else { | ||
frects[i][j] = scaled; | ||
} | ||
} | ||
} | ||
|
||
int j; | ||
int num_output = 0; | ||
for (int i = 0; i < nclasses; i++) { | ||
int r1 = i; | ||
int n1 = rweights[i]; | ||
if (n1 <= groupThreshold) | ||
continue; | ||
// filter out small face rectangles inside large rectangles | ||
for (j = 0; j < nclasses; j++) { | ||
int n2 = rweights[j]; | ||
|
||
if (j == i || n2 <= groupThreshold) | ||
continue; | ||
int r2 = j; | ||
int dx = cv::saturate_cast<int>(frects[r2][2] * eps); | ||
int dy = cv::saturate_cast<int>(frects[r2][3] * eps); | ||
|
||
if (i != j && | ||
frects[r1][0] >= frects[r2][0] - dx && | ||
frects[r1][1] >= frects[r2][1] - dy && | ||
frects[r1][0] + frects[r1][2] <= frects[r2][0] + frects[r2][2] + dx && | ||
frects[r1][1] + frects[r1][3] <= frects[r2][1] + frects[r2][3] + dy && | ||
(n2 > std::max(3, n1) || n1 < 3)) | ||
break; | ||
} | ||
|
||
if (j == nclasses) { | ||
for (int k = 0; k < ncols; ++k) { | ||
output[num_output * ncols + k] = frects[r1][k]; | ||
} | ||
scores[num_output] = n1; | ||
num_output++; | ||
} | ||
} | ||
|
||
return num_output; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
int groupRectanglesWithAux(float* input, int group_threshold, float eps, | ||
float* output, int* scores, int nrows, int ncols); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from distutils.core import setup | ||
from distutils.extension import Extension | ||
from Cython.Distutils import build_ext | ||
from Cython.Build import cythonize | ||
import numpy | ||
import subprocess | ||
|
||
process = subprocess.Popen( | ||
['pkg-config', '--libs', 'opencv'], | ||
stdout=subprocess.PIPE) | ||
out, err = process.communicate() | ||
libs = [lib for lib in str(out).split() if '.' in lib] | ||
opencv_path = set(['/'.join(lib.split('/')[:-2]) for lib in libs]).pop() | ||
print 'Your opencv path:', opencv_path | ||
|
||
setup( | ||
cmdclass = {'build_ext': build_ext}, | ||
ext_modules = [Extension( | ||
"group_rectangles_with_aux", | ||
language = "c++", | ||
sources = ["_group_rectangles_with_aux.pyx", "group_rectangles_with_aux.cpp"], | ||
include_dirs=[numpy.get_include(), opencv_path + '/include'], | ||
extra_link_args=libs)] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import numpy as np | ||
import cv2 | ||
import group_rectangles_with_aux | ||
import random | ||
|
||
num_trials = 10000 | ||
num_rectangles = 500 | ||
arena_size = 100.0 | ||
square_size = 10.0 | ||
gt = 1 | ||
eps = 0.8 | ||
use_aux = True | ||
|
||
for t in range(num_trials): | ||
opencv_gr = [] | ||
my_gr = [] | ||
for r in range(num_rectangles): | ||
e = np.array([ | ||
random.random() * arena_size, random.random() * arena_size, | ||
random.random() * square_size, random.random() * square_size]) | ||
ec = np.concatenate([e, np.array([random.random(), random.random()])]) | ||
opencv_gr.append(e) | ||
my_gr.append(ec if use_aux else e) | ||
|
||
output1, scores1 = cv2.groupRectangles(opencv_gr, gt, eps) | ||
output2, aux2, scores2 = group_rectangles_with_aux.execute(my_gr, gt, eps) | ||
if len(output1) == 0: | ||
assert len(output2) == 0 | ||
else: | ||
try: | ||
assert (output1 == output2).all() | ||
except: | ||
print 'opencv' | ||
print output1 | ||
print 'mine' | ||
print output2 | ||
print 'diff' | ||
print output1.shape, output2.shape | ||
print output1 - output2 | ||
raise | ||
if len(scores1) == 0: | ||
assert len(scores2) == 0 | ||
else: | ||
try: | ||
assert (scores1 == scores2).all() | ||
except: | ||
print 'opencv' | ||
print scores1 | ||
print 'mine' | ||
print scores2 | ||
print 'diff' | ||
print scores1.shape, scores2.shape | ||
print scores1 - scores2 | ||
raise | ||
if t % (num_trials / 20) == 0: | ||
print 'passed', t |