Add new tests on python
This commit is contained in:
parent
bc6ed1467b
commit
ab4d375349
53
modules/python/test/test.py
Normal file → Executable file
53
modules/python/test/test.py
Normal file → Executable file
@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import unittest
|
||||
import random
|
||||
import time
|
||||
@ -17,51 +19,24 @@ import numpy as np
|
||||
import cv2
|
||||
import argparse
|
||||
|
||||
# local test modules
|
||||
from test_digits import digits_test
|
||||
from test_calibration import calibration_test
|
||||
from test_squares import squares_test
|
||||
from test_texture_flow import texture_flow_test
|
||||
from test_fitline import fitline_test
|
||||
from test_houghcircles import houghcircles_test
|
||||
from test_houghlines import houghlines_test
|
||||
from test_gaussian_mix import gaussian_mix_test
|
||||
from test_facedetect import facedetect_test
|
||||
|
||||
# Python 3 moved urlopen to urllib.requests
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib import urlopen
|
||||
|
||||
class NewOpenCVTests(unittest.TestCase):
|
||||
|
||||
# path to local repository folder containing 'samples' folder
|
||||
repoPath = None
|
||||
# github repository url
|
||||
repoUrl = 'https://raw.github.com/Itseez/opencv/master'
|
||||
|
||||
def get_sample(self, filename, iscolor = cv2.IMREAD_COLOR):
|
||||
if not filename in self.image_cache:
|
||||
filedata = None
|
||||
if NewOpenCVTests.repoPath is not None:
|
||||
candidate = NewOpenCVTests.repoPath + '/' + filename
|
||||
if os.path.isfile(candidate):
|
||||
with open(candidate, 'rb') as f:
|
||||
filedata = f.read()
|
||||
if filedata is None:
|
||||
filedata = urlopen(NewOpenCVTests.repoUrl + '/' + filename).read()
|
||||
self.image_cache[filename] = cv2.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor)
|
||||
return self.image_cache[filename]
|
||||
|
||||
def setUp(self):
|
||||
self.image_cache = {}
|
||||
|
||||
def hashimg(self, im):
|
||||
""" Compute a hash for an image, useful for image comparisons """
|
||||
return hashlib.md5(im.tostring()).digest()
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
def assertLess(self, a, b, msg=None):
|
||||
if not a < b:
|
||||
self.fail('%s not less than %s' % (repr(a), repr(b)))
|
||||
|
||||
def assertLessEqual(self, a, b, msg=None):
|
||||
if not a <= b:
|
||||
self.fail('%s not less than or equal to %s' % (repr(a), repr(b)))
|
||||
|
||||
def assertGreater(self, a, b, msg=None):
|
||||
if not a > b:
|
||||
self.fail('%s not greater than %s' % (repr(a), repr(b)))
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
# Tests to run first; check the handful of basic operations that the later tests rely on
|
||||
|
||||
|
69
modules/python/test/test_calibration.py
Normal file
69
modules/python/test/test_calibration.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
camera calibration for distorted images with chess board samples
|
||||
reads distorted images, calculates the calibration and write undistorted images
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class calibration_test(NewOpenCVTests):
|
||||
|
||||
def test_calibration(self):
|
||||
|
||||
from glob import glob
|
||||
|
||||
img_mask = '../../../samples/data/left*.jpg' # default
|
||||
img_names = glob(img_mask)
|
||||
|
||||
square_size = 1.0
|
||||
pattern_size = (9, 6)
|
||||
pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32)
|
||||
pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2)
|
||||
pattern_points *= square_size
|
||||
|
||||
obj_points = []
|
||||
img_points = []
|
||||
h, w = 0, 0
|
||||
img_names_undistort = []
|
||||
for fn in img_names:
|
||||
img = cv2.imread(fn, 0)
|
||||
if img is None:
|
||||
continue
|
||||
|
||||
h, w = img.shape[:2]
|
||||
found, corners = cv2.findChessboardCorners(img, pattern_size)
|
||||
if found:
|
||||
term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1)
|
||||
cv2.cornerSubPix(img, corners, (5, 5), (-1, -1), term)
|
||||
|
||||
if not found:
|
||||
continue
|
||||
|
||||
img_points.append(corners.reshape(-1, 2))
|
||||
obj_points.append(pattern_points)
|
||||
|
||||
# calculate camera distortion
|
||||
rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (w, h), None, None, flags = 0)
|
||||
|
||||
eps = 0.01
|
||||
normCamEps = 10.0
|
||||
normDistEps = 0.01
|
||||
|
||||
cameraMatrixTest = [[ 532.80992189, 0., 342.4952186 ],
|
||||
[ 0., 532.93346422, 233.8879292 ],
|
||||
[ 0., 0., 1. ]]
|
||||
|
||||
distCoeffsTest = [ -2.81325576e-01, 2.91130406e-02,
|
||||
1.21234330e-03, -1.40825372e-04, 1.54865844e-01]
|
||||
|
||||
self.assertLess(abs(rms - 0.196334638034), eps)
|
||||
self.assertLess(cv2.norm(camera_matrix - cameraMatrixTest, cv2.NORM_L1), normCamEps)
|
||||
self.assertLess(cv2.norm(dist_coefs - distCoeffsTest, cv2.NORM_L1), normDistEps)
|
197
modules/python/test/test_digits.py
Normal file
197
modules/python/test/test_digits.py
Normal file
@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
SVM and KNearest digit recognition.
|
||||
|
||||
Sample loads a dataset of handwritten digits from '../data/digits.png'.
|
||||
Then it trains a SVM and KNearest classifiers on it and evaluates
|
||||
their accuracy.
|
||||
|
||||
Following preprocessing is applied to the dataset:
|
||||
- Moment-based image deskew (see deskew())
|
||||
- Digit images are split into 4 10x10 cells and 16-bin
|
||||
histogram of oriented gradients is computed for each
|
||||
cell
|
||||
- Transform histograms to space with Hellinger metric (see [1] (RootSIFT))
|
||||
|
||||
|
||||
[1] R. Arandjelovic, A. Zisserman
|
||||
"Three things everyone should know to improve object retrieval"
|
||||
http://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf
|
||||
|
||||
'''
|
||||
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
# built-in modules
|
||||
from multiprocessing.pool import ThreadPool
|
||||
|
||||
import cv2
|
||||
|
||||
import numpy as np
|
||||
from numpy.linalg import norm
|
||||
|
||||
|
||||
SZ = 20 # size of each digit is SZ x SZ
|
||||
CLASS_N = 10
|
||||
DIGITS_FN = '../../../samples/data/digits.png'
|
||||
|
||||
def split2d(img, cell_size, flatten=True):
|
||||
h, w = img.shape[:2]
|
||||
sx, sy = cell_size
|
||||
cells = [np.hsplit(row, w//sx) for row in np.vsplit(img, h//sy)]
|
||||
cells = np.array(cells)
|
||||
if flatten:
|
||||
cells = cells.reshape(-1, sy, sx)
|
||||
return cells
|
||||
|
||||
def load_digits(fn):
|
||||
digits_img = cv2.imread(fn, 0)
|
||||
digits = split2d(digits_img, (SZ, SZ))
|
||||
labels = np.repeat(np.arange(CLASS_N), len(digits)/CLASS_N)
|
||||
return digits, labels
|
||||
|
||||
def deskew(img):
|
||||
m = cv2.moments(img)
|
||||
if abs(m['mu02']) < 1e-2:
|
||||
return img.copy()
|
||||
skew = m['mu11']/m['mu02']
|
||||
M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
|
||||
img = cv2.warpAffine(img, M, (SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)
|
||||
return img
|
||||
|
||||
class StatModel(object):
|
||||
def load(self, fn):
|
||||
self.model.load(fn) # Known bug: https://github.com/Itseez/opencv/issues/4969
|
||||
def save(self, fn):
|
||||
self.model.save(fn)
|
||||
|
||||
class KNearest(StatModel):
|
||||
def __init__(self, k = 3):
|
||||
self.k = k
|
||||
self.model = cv2.ml.KNearest_create()
|
||||
|
||||
def train(self, samples, responses):
|
||||
self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
|
||||
|
||||
def predict(self, samples):
|
||||
retval, results, neigh_resp, dists = self.model.findNearest(samples, self.k)
|
||||
return results.ravel()
|
||||
|
||||
class SVM(StatModel):
|
||||
def __init__(self, C = 1, gamma = 0.5):
|
||||
self.model = cv2.ml.SVM_create()
|
||||
self.model.setGamma(gamma)
|
||||
self.model.setC(C)
|
||||
self.model.setKernel(cv2.ml.SVM_RBF)
|
||||
self.model.setType(cv2.ml.SVM_C_SVC)
|
||||
|
||||
def train(self, samples, responses):
|
||||
self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
|
||||
|
||||
def predict(self, samples):
|
||||
return self.model.predict(samples)[1].ravel()
|
||||
|
||||
|
||||
def evaluate_model(model, digits, samples, labels):
|
||||
resp = model.predict(samples)
|
||||
err = (labels != resp).mean()
|
||||
|
||||
confusion = np.zeros((10, 10), np.int32)
|
||||
for i, j in zip(labels, resp):
|
||||
confusion[i, j] += 1
|
||||
|
||||
return err, confusion
|
||||
|
||||
def preprocess_simple(digits):
|
||||
return np.float32(digits).reshape(-1, SZ*SZ) / 255.0
|
||||
|
||||
def preprocess_hog(digits):
|
||||
samples = []
|
||||
for img in digits:
|
||||
gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
|
||||
gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
|
||||
mag, ang = cv2.cartToPolar(gx, gy)
|
||||
bin_n = 16
|
||||
bin = np.int32(bin_n*ang/(2*np.pi))
|
||||
bin_cells = bin[:10,:10], bin[10:,:10], bin[:10,10:], bin[10:,10:]
|
||||
mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
|
||||
hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
|
||||
hist = np.hstack(hists)
|
||||
|
||||
# transform to Hellinger kernel
|
||||
eps = 1e-7
|
||||
hist /= hist.sum() + eps
|
||||
hist = np.sqrt(hist)
|
||||
hist /= norm(hist) + eps
|
||||
|
||||
samples.append(hist)
|
||||
return np.float32(samples)
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class digits_test(NewOpenCVTests):
|
||||
|
||||
def test_digits(self):
|
||||
|
||||
digits, labels = load_digits(DIGITS_FN)
|
||||
|
||||
# shuffle digits
|
||||
rand = np.random.RandomState(321)
|
||||
shuffle = rand.permutation(len(digits))
|
||||
digits, labels = digits[shuffle], labels[shuffle]
|
||||
|
||||
digits2 = list(map(deskew, digits))
|
||||
samples = preprocess_hog(digits2)
|
||||
|
||||
train_n = int(0.9*len(samples))
|
||||
digits_train, digits_test = np.split(digits2, [train_n])
|
||||
samples_train, samples_test = np.split(samples, [train_n])
|
||||
labels_train, labels_test = np.split(labels, [train_n])
|
||||
errors = list()
|
||||
confusionMatrixes = list()
|
||||
|
||||
model = KNearest(k=4)
|
||||
model.train(samples_train, labels_train)
|
||||
error, confusion = evaluate_model(model, digits_test, samples_test, labels_test)
|
||||
errors.append(error)
|
||||
confusionMatrixes.append(confusion)
|
||||
|
||||
model = SVM(C=2.67, gamma=5.383)
|
||||
model.train(samples_train, labels_train)
|
||||
error, confusion = evaluate_model(model, digits_test, samples_test, labels_test)
|
||||
errors.append(error)
|
||||
confusionMatrixes.append(confusion)
|
||||
|
||||
eps = 0.001
|
||||
normEps = len(samples_test) * 0.02
|
||||
|
||||
confusionKNN = [[45, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 57, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 59, 1, 0, 0, 0, 0, 1, 0],
|
||||
[ 0, 0, 0, 43, 0, 0, 0, 1, 0, 0],
|
||||
[ 0, 0, 0, 0, 38, 0, 2, 0, 0, 0],
|
||||
[ 0, 0, 0, 2, 0, 48, 0, 0, 1, 0],
|
||||
[ 0, 1, 0, 0, 0, 0, 51, 0, 0, 0],
|
||||
[ 0, 0, 1, 0, 0, 0, 0, 54, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 1, 0, 0, 46, 0],
|
||||
[ 1, 1, 0, 1, 1, 0, 0, 0, 2, 42]]
|
||||
|
||||
confusionSVM = [[45, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 57, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 59, 2, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 43, 0, 0, 0, 1, 0, 0],
|
||||
[ 0, 0, 0, 0, 40, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 1, 0, 50, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 1, 0, 51, 0, 0, 0],
|
||||
[ 0, 0, 1, 0, 0, 0, 0, 54, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 47, 0],
|
||||
[ 0, 1, 0, 1, 0, 0, 0, 0, 1, 45]]
|
||||
|
||||
self.assertLess(cv2.norm(confusionMatrixes[0] - confusionKNN, cv2.NORM_L1), normEps)
|
||||
self.assertLess(cv2.norm(confusionMatrixes[1] - confusionSVM, cv2.NORM_L1), normEps)
|
||||
|
||||
self.assertLess(errors[0] - 0.034, eps)
|
||||
self.assertLess(errors[1] - 0.018, eps)
|
102
modules/python/test/test_facedetect.py
Normal file
102
modules/python/test/test_facedetect.py
Normal file
@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
face detection using haar cascades
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
def intersectionRate(s1, s2):
|
||||
|
||||
x1, y1, x2, y2 = s1
|
||||
s1 = [[x1, y1], [x2,y1], [x2, y2], [x1, y2] ]
|
||||
|
||||
x1, y1, x2, y2 = s2
|
||||
s2 = [[x1, y1], [x2,y1], [x2, y2], [x1, y2] ]
|
||||
|
||||
area, intersection = cv2.intersectConvexConvex(np.array(s1), np.array(s2))
|
||||
return 2 * area / (cv2.contourArea(np.array(s1)) + cv2.contourArea(np.array(s2)))
|
||||
|
||||
def detect(img, cascade):
|
||||
rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30),
|
||||
flags=cv2.CASCADE_SCALE_IMAGE)
|
||||
if len(rects) == 0:
|
||||
return []
|
||||
rects[:,2:] += rects[:,:2]
|
||||
return rects
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class facedetect_test(NewOpenCVTests):
|
||||
|
||||
def test_facedetect(self):
|
||||
import sys, getopt
|
||||
|
||||
cascade_fn = "../../../data/haarcascades/haarcascade_frontalface_alt.xml"
|
||||
nested_fn = "../../../data/haarcascades/haarcascade_eye.xml"
|
||||
|
||||
cascade = cv2.CascadeClassifier(cascade_fn)
|
||||
nested = cv2.CascadeClassifier(nested_fn)
|
||||
|
||||
dirPath = '../../../samples/data/'
|
||||
samples = ['lena.jpg', 'kate.jpg']
|
||||
|
||||
faces = []
|
||||
eyes = []
|
||||
|
||||
testFaces = [
|
||||
#lena
|
||||
[[218, 200, 389, 371],
|
||||
[ 244, 240, 294, 290],
|
||||
[ 309, 246, 352, 289]],
|
||||
|
||||
#kate
|
||||
[[207, 89, 436, 318],
|
||||
[245, 161, 294, 210],
|
||||
[343, 139, 389, 185]]
|
||||
]
|
||||
|
||||
for sample in samples:
|
||||
|
||||
img = cv2.imread(dirPath + sample)
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
gray = cv2.GaussianBlur(gray, (3, 3), 1.1)
|
||||
|
||||
rects = detect(gray, cascade)
|
||||
faces.append(rects)
|
||||
|
||||
if not nested.empty():
|
||||
for x1, y1, x2, y2 in rects:
|
||||
roi = gray[y1:y2, x1:x2]
|
||||
subrects = detect(roi.copy(), nested)
|
||||
|
||||
for rect in subrects:
|
||||
rect[0] += x1
|
||||
rect[2] += x1
|
||||
rect[1] += y1
|
||||
rect[3] += y1
|
||||
|
||||
eyes.append(subrects)
|
||||
|
||||
faces_matches = 0
|
||||
eyes_matches = 0
|
||||
|
||||
eps = 0.8
|
||||
|
||||
for i in range(len(faces)):
|
||||
for j in range(len(testFaces)):
|
||||
if intersectionRate(faces[i][0], testFaces[j][0]) > eps:
|
||||
faces_matches += 1
|
||||
#check eyes
|
||||
if len(eyes[i]) == 2:
|
||||
if intersectionRate(eyes[i][0], testFaces[j][1]) > eps and intersectionRate(eyes[i][1], testFaces[j][2]):
|
||||
eyes_matches += 1
|
||||
elif intersectionRate(eyes[i][1], testFaces[j][1]) > eps and intersectionRate(eyes[i][0], testFaces[j][2]):
|
||||
eyes_matches += 1
|
||||
|
||||
self.assertEqual(faces_matches, 2)
|
||||
self.assertEqual(eyes_matches, 2)
|
66
modules/python/test/test_fitline.py
Normal file
66
modules/python/test/test_fitline.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Robust line fitting.
|
||||
==================
|
||||
|
||||
Example of using cv2.fitLine function for fitting line
|
||||
to points in presence of outliers.
|
||||
|
||||
Switch through different M-estimator functions and see,
|
||||
how well the robust functions fit the line even
|
||||
in case of ~50% of outliers.
|
||||
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
w, h = 512, 256
|
||||
|
||||
def toint(p):
|
||||
return tuple(map(int, p))
|
||||
|
||||
def sample_line(p1, p2, n, noise=0.0):
|
||||
np.random.seed(10)
|
||||
p1 = np.float32(p1)
|
||||
t = np.random.rand(n,1)
|
||||
return p1 + (p2-p1)*t + np.random.normal(size=(n, 2))*noise
|
||||
|
||||
dist_func_names = ['DIST_L2', 'DIST_L1', 'DIST_L12', 'DIST_FAIR', 'DIST_WELSCH', 'DIST_HUBER']
|
||||
|
||||
class fitline_test(NewOpenCVTests):
|
||||
|
||||
def test_fitline(self):
|
||||
|
||||
noise = 5
|
||||
n = 200
|
||||
r = 5 / 100.0
|
||||
outn = int(n*r)
|
||||
|
||||
p0, p1 = (90, 80), (w-90, h-80)
|
||||
line_points = sample_line(p0, p1, n-outn, noise)
|
||||
outliers = np.random.rand(outn, 2) * (w, h)
|
||||
points = np.vstack([line_points, outliers])
|
||||
|
||||
lines = []
|
||||
|
||||
for name in dist_func_names:
|
||||
func = getattr(cv2, name)
|
||||
vx, vy, cx, cy = cv2.fitLine(np.float32(points), func, 0, 0.01, 0.01)
|
||||
line = [float(vx), float(vy), float(cx), float(cy)]
|
||||
lines.append(line)
|
||||
|
||||
eps = 0.05
|
||||
|
||||
refVec = (np.float32(p1) - p0) / cv2.norm(np.float32(p1) - p0)
|
||||
|
||||
for i in range(len(lines)):
|
||||
self.assertLessEqual(cv2.norm(refVec - lines[i][0:2], cv2.NORM_L2), eps)
|
60
modules/python/test/test_gaussian_mix.py
Normal file
60
modules/python/test/test_gaussian_mix.py
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
xrange = range
|
||||
|
||||
import numpy as np
|
||||
from numpy import random
|
||||
import cv2
|
||||
|
||||
def make_gaussians(cluster_n, img_size):
|
||||
points = []
|
||||
ref_distrs = []
|
||||
for i in xrange(cluster_n):
|
||||
mean = (0.1 + 0.8*random.rand(2)) * img_size
|
||||
a = (random.rand(2, 2)-0.5)*img_size*0.1
|
||||
cov = np.dot(a.T, a) + img_size*0.05*np.eye(2)
|
||||
n = 100 + random.randint(900)
|
||||
pts = random.multivariate_normal(mean, cov, n)
|
||||
points.append( pts )
|
||||
ref_distrs.append( (mean, cov) )
|
||||
points = np.float32( np.vstack(points) )
|
||||
return points, ref_distrs
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class gaussian_mix_test(NewOpenCVTests):
|
||||
|
||||
def test_gaussian_mix(self):
|
||||
|
||||
np.random.seed(10)
|
||||
cluster_n = 5
|
||||
img_size = 512
|
||||
|
||||
points, ref_distrs = make_gaussians(cluster_n, img_size)
|
||||
|
||||
em = cv2.ml.EM_create()
|
||||
em.setClustersNumber(cluster_n)
|
||||
em.setCovarianceMatrixType(cv2.ml.EM_COV_MAT_GENERIC)
|
||||
em.trainEM(points)
|
||||
means = em.getMeans()
|
||||
covs = em.getCovs() # Known bug: https://github.com/Itseez/opencv/pull/4232
|
||||
found_distrs = zip(means, covs)
|
||||
|
||||
matches_count = 0
|
||||
|
||||
meanEps = 0.05
|
||||
covEps = 0.1
|
||||
|
||||
for i in range(cluster_n):
|
||||
for j in range(cluster_n):
|
||||
if (cv2.norm(means[i] - ref_distrs[j][0], cv2.NORM_L2) / cv2.norm(ref_distrs[j][0], cv2.NORM_L2) < meanEps and
|
||||
cv2.norm(covs[i] - ref_distrs[j][1], cv2.NORM_L2) / cv2.norm(ref_distrs[j][1], cv2.NORM_L2) < covEps):
|
||||
matches_count += 1
|
||||
|
||||
self.assertEqual(matches_count, cluster_n)
|
57
modules/python/test/test_houghcircles.py
Normal file
57
modules/python/test/test_houghcircles.py
Normal file
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
'''
|
||||
This example illustrates how to use cv2.HoughCircles() function.
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import sys
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class houghcircles_test(NewOpenCVTests):
|
||||
|
||||
def test_houghcircles(self):
|
||||
|
||||
fn = "../../../samples/data/board.jpg"
|
||||
|
||||
src = cv2.imread(fn, 1)
|
||||
img = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
|
||||
img = cv2.medianBlur(img, 5)
|
||||
|
||||
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 10, np.array([]), 100, 30, 1, 30)[0]
|
||||
|
||||
testCircles = [[38, 181, 17.6],
|
||||
[99.7, 166, 13.12],
|
||||
[142.7, 160, 13.52],
|
||||
[223.6, 110, 8.62],
|
||||
[79.1, 206.7, 8.62],
|
||||
[47.5, 351.6, 11.64],
|
||||
[189.5, 354.4, 11.64],
|
||||
[189.8, 298.9, 10.64],
|
||||
[189.5, 252.4, 14.62],
|
||||
[252.5, 393.4, 15.62],
|
||||
[602.9, 467.5, 11.42],
|
||||
[222, 210.4, 9.12],
|
||||
[263.1, 216.7, 9.12],
|
||||
[359.8, 222.6, 9.12],
|
||||
[518.9, 120.9, 9.12],
|
||||
[413.8, 113.4, 9.12],
|
||||
[489, 127.2, 9.12],
|
||||
[448.4, 121.3, 9.12],
|
||||
[384.6, 128.9, 8.62]]
|
||||
|
||||
eps = 7
|
||||
matches_counter = 0
|
||||
|
||||
for i in range(len(testCircles)):
|
||||
for j in range(len(circles)):
|
||||
if cv2.norm(testCircles[i] - circles[j], cv2.NORM_L2) < eps:
|
||||
matches_counter += 1
|
||||
|
||||
self.assertGreater(float(matches_counter) / len(testCircles), .5)
|
||||
self.assertLess(float(len(circles) - matches_counter) / len(circles), .7)
|
65
modules/python/test/test_houghlines.py
Normal file
65
modules/python/test/test_houghlines.py
Normal file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
'''
|
||||
This example illustrates how to use Hough Transform to find lines
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import sys
|
||||
import math
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
def linesDiff(line1, line2):
|
||||
|
||||
norm1 = cv2.norm(line1 - line2, cv2.NORM_L2)
|
||||
line3 = line1[2:4] + line1[0:2]
|
||||
norm2 = cv2.norm(line3 - line2, cv2.NORM_L2)
|
||||
|
||||
return min(norm1, norm2)
|
||||
|
||||
class houghlines_test(NewOpenCVTests):
|
||||
|
||||
def test_houghlines(self):
|
||||
|
||||
fn = "../../../samples/data/pic1.png"
|
||||
|
||||
src = cv2.imread(fn)
|
||||
dst = cv2.Canny(src, 50, 200)
|
||||
|
||||
lines = cv2.HoughLinesP(dst, 1, math.pi/180.0, 40, np.array([]), 50, 10)[:,0,:]
|
||||
|
||||
eps = 5
|
||||
testLines = [
|
||||
#rect1
|
||||
[ 232, 25, 43, 25],
|
||||
[ 43, 129, 232, 129],
|
||||
[ 43, 129, 43, 25],
|
||||
[232, 129, 232, 25],
|
||||
#rect2
|
||||
[251, 86, 314, 183],
|
||||
[252, 86, 323, 40],
|
||||
[315, 183, 386, 137],
|
||||
[324, 40, 386, 136],
|
||||
#triangle
|
||||
[245, 205, 377, 205],
|
||||
[244, 206, 305, 278],
|
||||
[306, 279, 377, 205],
|
||||
#rect3
|
||||
[153, 177, 196, 177],
|
||||
[153, 277, 153, 179],
|
||||
[153, 277, 196, 277],
|
||||
[196, 177, 196, 277]]
|
||||
|
||||
matches_counter = 0
|
||||
|
||||
for i in range(len(testLines)):
|
||||
for j in range(len(lines)):
|
||||
if linesDiff(testLines[i], lines[j]) < eps:
|
||||
matches_counter += 1
|
||||
|
||||
self.assertGreater(float(matches_counter) / len(testLines), .7)
|
96
modules/python/test/test_squares.py
Normal file
96
modules/python/test/test_squares.py
Normal file
@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Simple "Square Detector" program.
|
||||
|
||||
Loads several images sequentially and tries to find squares in each image.
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
import sys
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
xrange = range
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
|
||||
def angle_cos(p0, p1, p2):
|
||||
d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
|
||||
return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )
|
||||
|
||||
def find_squares(img):
|
||||
img = cv2.GaussianBlur(img, (5, 5), 0)
|
||||
squares = []
|
||||
for gray in cv2.split(img):
|
||||
for thrs in xrange(0, 255, 26):
|
||||
if thrs == 0:
|
||||
bin = cv2.Canny(gray, 0, 50, apertureSize=5)
|
||||
bin = cv2.dilate(bin, None)
|
||||
else:
|
||||
retval, bin = cv2.threshold(gray, thrs, 255, cv2.THRESH_BINARY)
|
||||
bin, contours, hierarchy = cv2.findContours(bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
|
||||
for cnt in contours:
|
||||
cnt_len = cv2.arcLength(cnt, True)
|
||||
cnt = cv2.approxPolyDP(cnt, 0.02*cnt_len, True)
|
||||
if len(cnt) == 4 and cv2.contourArea(cnt) > 1000 and cv2.isContourConvex(cnt):
|
||||
cnt = cnt.reshape(-1, 2)
|
||||
max_cos = np.max([angle_cos( cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4] ) for i in xrange(4)])
|
||||
if max_cos < 0.1 and filterSquares(squares, cnt):
|
||||
squares.append(cnt)
|
||||
|
||||
return squares
|
||||
|
||||
def intersectionRate(s1, s2):
|
||||
area, intersection = cv2.intersectConvexConvex(np.array(s1), np.array(s2))
|
||||
return 2 * area / (cv2.contourArea(np.array(s1)) + cv2.contourArea(np.array(s2)))
|
||||
|
||||
def filterSquares(squares, square):
|
||||
|
||||
for i in range(len(squares)):
|
||||
if intersectionRate(squares[i], square) > 0.95:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class squares_test(NewOpenCVTests):
|
||||
|
||||
def test_squares(self):
|
||||
|
||||
img = cv2.imread('../../../samples/data/pic1.png')
|
||||
squares = find_squares(img)
|
||||
|
||||
testSquares = [
|
||||
[[43, 25],
|
||||
[43, 129],
|
||||
[232, 129],
|
||||
[232, 25]],
|
||||
|
||||
[[252, 87],
|
||||
[324, 40],
|
||||
[387, 137],
|
||||
[315, 184]],
|
||||
|
||||
[[154, 178],
|
||||
[196, 180],
|
||||
[198, 278],
|
||||
[154, 278]],
|
||||
|
||||
[[0, 0],
|
||||
[400, 0],
|
||||
[400, 300],
|
||||
[0, 300]]
|
||||
]
|
||||
|
||||
matches_counter = 0
|
||||
for i in range(len(squares)):
|
||||
for j in range(len(testSquares)):
|
||||
if intersectionRate(squares[i], testSquares[j]) > 0.9:
|
||||
matches_counter += 1
|
||||
|
||||
self.assertGreater(matches_counter / len(testSquares), 0.9)
|
||||
self.assertLess( (len(squares) - matches_counter) / len(squares), 0.2)
|
52
modules/python/test/test_texture_flow.py
Normal file
52
modules/python/test/test_texture_flow.py
Normal file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Texture flow direction estimation.
|
||||
|
||||
Sample shows how cv2.cornerEigenValsAndVecs function can be used
|
||||
to estimate image texture flow direction.
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
import sys
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
|
||||
class texture_flow_test(NewOpenCVTests):
|
||||
|
||||
def test_texture_flow(self):
|
||||
|
||||
fn = '../../../samples/data/pic6.png'
|
||||
img = cv2.imread(fn)
|
||||
|
||||
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
h, w = img.shape[:2]
|
||||
|
||||
eigen = cv2.cornerEigenValsAndVecs(gray, 15, 3)
|
||||
eigen = eigen.reshape(h, w, 3, 2) # [[e1, e2], v1, v2]
|
||||
flow = eigen[:,:,2]
|
||||
|
||||
vis = img.copy()
|
||||
vis[:] = (192 + np.uint32(vis)) / 2
|
||||
d = 80
|
||||
points = np.dstack( np.mgrid[d/2:w:d, d/2:h:d] ).reshape(-1, 2)
|
||||
|
||||
textureVectors = []
|
||||
|
||||
for x, y in np.int32(points):
|
||||
textureVectors.append(np.int32(flow[y, x]*d))
|
||||
|
||||
eps = 0.05
|
||||
|
||||
testTextureVectors = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
|
||||
[-38, 70], [-79, 3], [0, 0], [0, 0], [-39, 69], [-79, -1],
|
||||
[0, 0], [0, 0], [0, -79], [17, -78], [-48, -63], [65, -46],
|
||||
[-69, -39], [-48, -63], [-45, 66]]
|
||||
|
||||
for i in range(len(textureVectors)):
|
||||
self.assertLessEqual(cv2.norm(textureVectors[i] - testTextureVectors[i], cv2.NORM_L2), eps)
|
56
modules/python/test/tests_common.py
Normal file
56
modules/python/test/tests_common.py
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
import hashlib
|
||||
import os
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
# Python 3 moved urlopen to urllib.requests
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib import urlopen
|
||||
|
||||
class NewOpenCVTests(unittest.TestCase):
|
||||
|
||||
# path to local repository folder containing 'samples' folder
|
||||
repoPath = None
|
||||
# github repository url
|
||||
repoUrl = 'https://raw.github.com/Itseez/opencv/master'
|
||||
|
||||
def get_sample(self, filename, iscolor = cv2.IMREAD_COLOR):
|
||||
if not filename in self.image_cache:
|
||||
filedata = None
|
||||
if NewOpenCVTests.repoPath is not None:
|
||||
candidate = NewOpenCVTests.repoPath + '/' + filename
|
||||
if os.path.isfile(candidate):
|
||||
with open(candidate, 'rb') as f:
|
||||
filedata = f.read()
|
||||
if filedata is None:
|
||||
filedata = urlopen(NewOpenCVTests.repoUrl + '/' + filename).read()
|
||||
self.image_cache[filename] = cv2.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor)
|
||||
return self.image_cache[filename]
|
||||
|
||||
def setUp(self):
|
||||
self.image_cache = {}
|
||||
|
||||
def hashimg(self, im):
|
||||
""" Compute a hash for an image, useful for image comparisons """
|
||||
return hashlib.md5(im.tostring()).digest()
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
def assertLess(self, a, b, msg=None):
|
||||
if not a < b:
|
||||
self.fail('%s not less than %s' % (repr(a), repr(b)))
|
||||
|
||||
def assertLessEqual(self, a, b, msg=None):
|
||||
if not a <= b:
|
||||
self.fail('%s not less than or equal to %s' % (repr(a), repr(b)))
|
||||
|
||||
def assertGreater(self, a, b, msg=None):
|
||||
if not a > b:
|
||||
self.fail('%s not greater than %s' % (repr(a), repr(b)))
|
BIN
samples/data/kate.jpg
Normal file
BIN
samples/data/kate.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
@ -87,8 +87,11 @@ class App:
|
||||
for fn in glob('*.py'):
|
||||
name = splitfn(fn)[1]
|
||||
if fn[0] != '_' and name not in exclude_list:
|
||||
demos_lb.insert(tk.END, name)
|
||||
self.samples[name] = fn
|
||||
|
||||
for name in sorted(self.samples):
|
||||
demos_lb.insert(tk.END, name)
|
||||
|
||||
demos_lb.bind('<<ListboxSelect>>', self.on_demo_select)
|
||||
|
||||
self.cmd_entry = cmd_entry = tk.Entry(right)
|
||||
|
Loading…
Reference in New Issue
Block a user