feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

View File

@ -0,0 +1,42 @@
package org.opencv.test.ml;
import org.opencv.ml.Ml;
import org.opencv.ml.SVM;
import org.opencv.core.Mat;
import org.opencv.core.MatOfFloat;
import org.opencv.core.MatOfInt;
import org.opencv.core.CvType;
import org.opencv.test.OpenCVTestCase;
import org.opencv.test.OpenCVTestRunner;
public class MLTest extends OpenCVTestCase {
public void testSaveLoad() {
Mat samples = new MatOfFloat(new float[] {
5.1f, 3.5f, 1.4f, 0.2f,
4.9f, 3.0f, 1.4f, 0.2f,
4.7f, 3.2f, 1.3f, 0.2f,
4.6f, 3.1f, 1.5f, 0.2f,
5.0f, 3.6f, 1.4f, 0.2f,
7.0f, 3.2f, 4.7f, 1.4f,
6.4f, 3.2f, 4.5f, 1.5f,
6.9f, 3.1f, 4.9f, 1.5f,
5.5f, 2.3f, 4.0f, 1.3f,
6.5f, 2.8f, 4.6f, 1.5f
}).reshape(1, 10);
Mat responses = new MatOfInt(new int[] {
0, 0, 0, 0, 0, 1, 1, 1, 1, 1
}).reshape(1, 10);
SVM saved = SVM.create();
assertFalse(saved.isTrained());
saved.train(samples, Ml.ROW_SAMPLE, responses);
assertTrue(saved.isTrained());
String filename = OpenCVTestRunner.getTempFileName("yml");
saved.save(filename);
SVM loaded = SVM.load(filename);
assertTrue(loaded.isTrained());
}
}

View File

@ -0,0 +1,9 @@
{
"enum_fix" : {
"EM" : { "Types": "EMTypes" },
"SVM" : { "Types": "SVMTypes" },
"KNearest" : { "Types": "KNearestTypes" },
"DTrees" : { "Flags": "DTreeFlags" },
"StatModel" : { "Flags": "StatModelFlags" }
}
}

View File

@ -0,0 +1,22 @@
template<>
bool pyopencv_to(PyObject *obj, CvTermCriteria& dst, const ArgInfo& info)
{
CV_UNUSED(info);
if(!obj)
return true;
return PyArg_ParseTuple(obj, "iid", &dst.type, &dst.max_iter, &dst.epsilon) > 0;
}
template<>
bool pyopencv_to(PyObject* obj, CvSlice& r, const ArgInfo& info)
{
CV_UNUSED(info);
if(!obj || obj == Py_None)
return true;
if(PyObject_Size(obj) == 0)
{
r = CV_WHOLE_SEQ;
return true;
}
return PyArg_ParseTuple(obj, "ii", &r.start_index, &r.end_index) > 0;
}

View File

@ -0,0 +1,201 @@
#!/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 as cv
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 deskew(img):
m = cv.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 = cv.warpAffine(img, M, (SZ, SZ), flags=cv.WARP_INVERSE_MAP | cv.INTER_LINEAR)
return img
class StatModel(object):
def load(self, fn):
self.model.load(fn) # Known bug: https://github.com/opencv/opencv/issues/4969
def save(self, fn):
self.model.save(fn)
class KNearest(StatModel):
def __init__(self, k = 3):
self.k = k
self.model = cv.ml.KNearest_create()
def train(self, samples, responses):
self.model.train(samples, cv.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 = cv.ml.SVM_create()
self.model.setGamma(gamma)
self.model.setC(C)
self.model.setKernel(cv.ml.SVM_RBF)
self.model.setType(cv.ml.SVM_C_SVC)
def train(self, samples, responses):
self.model.train(samples, cv.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[int(i), int(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 = cv.Sobel(img, cv.CV_32F, 1, 0)
gy = cv.Sobel(img, cv.CV_32F, 0, 1)
mag, ang = cv.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 load_digits(self, fn):
digits_img = self.get_sample(fn, 0)
digits = split2d(digits_img, (SZ, SZ))
labels = np.repeat(np.arange(CLASS_N), len(digits)/CLASS_N)
return digits, labels
def test_digits(self):
digits, labels = self.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(cv.norm(confusionMatrixes[0] - confusionKNN, cv.NORM_L1), normEps)
self.assertLess(cv.norm(confusionMatrixes[1] - confusionSVM, cv.NORM_L1), normEps)
self.assertLess(errors[0] - 0.034, eps)
self.assertLess(errors[1] - 0.018, eps)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python
# Python 2/3 compatibility
from __future__ import print_function
import cv2 as cv
import numpy as np
from tests_common import NewOpenCVTests
class TestGoodFeaturesToTrack_test(NewOpenCVTests):
def test_goodFeaturesToTrack(self):
arr = self.get_sample('samples/data/lena.jpg', 0)
original = arr.copy()
threshes = [ x / 100. for x in range(1,10) ]
numPoints = 20000
results = dict([(t, cv.goodFeaturesToTrack(arr, numPoints, t, 2, useHarrisDetector=True)) for t in threshes])
# Check that GoodFeaturesToTrack has not modified input image
self.assertTrue(arr.tostring() == original.tostring())
# Check for repeatability
for i in range(1):
results2 = dict([(t, cv.goodFeaturesToTrack(arr, numPoints, t, 2, useHarrisDetector=True)) for t in threshes])
for t in threshes:
self.assertTrue(len(results2[t]) == len(results[t]))
for i in range(len(results[t])):
self.assertTrue(cv.norm(results[t][i][0] - results2[t][i][0]) == 0)
for t0,t1 in zip(threshes, threshes[1:]):
r0 = results[t0]
r1 = results[t1]
# Increasing thresh should make result list shorter
self.assertTrue(len(r0) > len(r1))
# Increasing thresh should monly truncate result list
for i in range(len(r1)):
self.assertTrue(cv.norm(r1[i][0] - r0[i][0])==0)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python
import cv2 as cv
from tests_common import NewOpenCVTests
class knearest_test(NewOpenCVTests):
def test_load(self):
k_nearest = cv.ml.KNearest_load(self.find_file("ml/opencv_ml_knn.xml"))
self.assertFalse(k_nearest.empty())
self.assertTrue(k_nearest.isTrained())
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

View File

@ -0,0 +1,171 @@
#!/usr/bin/env python
'''
The sample demonstrates how to train Random Trees classifier
(or Boosting classifier, or MLP, or Knearest, or Support Vector Machines) using the provided dataset.
We use the sample database letter-recognition.data
from UCI Repository, here is the link:
Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998).
UCI Repository of machine learning databases
[http://www.ics.uci.edu/~mlearn/MLRepository.html].
Irvine, CA: University of California, Department of Information and Computer Science.
The dataset consists of 20000 feature vectors along with the
responses - capital latin letters A..Z.
The first 10000 samples are used for training
and the remaining 10000 - to test the classifier.
======================================================
Models: RTrees, KNearest, Boost, SVM, MLP
'''
# Python 2/3 compatibility
from __future__ import print_function
import numpy as np
import cv2 as cv
def load_base(fn):
a = np.loadtxt(fn, np.float32, delimiter=',', converters={ 0 : lambda ch : ord(ch)-ord('A') })
samples, responses = a[:,1:], a[:,0]
return samples, responses
class LetterStatModel(object):
class_n = 26
train_ratio = 0.5
def load(self, fn):
self.model.load(fn)
def save(self, fn):
self.model.save(fn)
def unroll_samples(self, samples):
sample_n, var_n = samples.shape
new_samples = np.zeros((sample_n * self.class_n, var_n+1), np.float32)
new_samples[:,:-1] = np.repeat(samples, self.class_n, axis=0)
new_samples[:,-1] = np.tile(np.arange(self.class_n), sample_n)
return new_samples
def unroll_responses(self, responses):
sample_n = len(responses)
new_responses = np.zeros(sample_n*self.class_n, np.int32)
resp_idx = np.int32( responses + np.arange(sample_n)*self.class_n )
new_responses[resp_idx] = 1
return new_responses
class RTrees(LetterStatModel):
def __init__(self):
self.model = cv.ml.RTrees_create()
def train(self, samples, responses):
#sample_n, var_n = samples.shape
self.model.setMaxDepth(20)
self.model.train(samples, cv.ml.ROW_SAMPLE, responses.astype(int))
def predict(self, samples):
_ret, resp = self.model.predict(samples)
return resp.ravel()
class KNearest(LetterStatModel):
def __init__(self):
self.model = cv.ml.KNearest_create()
def train(self, samples, responses):
self.model.train(samples, cv.ml.ROW_SAMPLE, responses)
def predict(self, samples):
_retval, results, _neigh_resp, _dists = self.model.findNearest(samples, k = 10)
return results.ravel()
class Boost(LetterStatModel):
def __init__(self):
self.model = cv.ml.Boost_create()
def train(self, samples, responses):
_sample_n, var_n = samples.shape
new_samples = self.unroll_samples(samples)
new_responses = self.unroll_responses(responses)
var_types = np.array([cv.ml.VAR_NUMERICAL] * var_n + [cv.ml.VAR_CATEGORICAL, cv.ml.VAR_CATEGORICAL], np.uint8)
self.model.setWeakCount(15)
self.model.setMaxDepth(10)
self.model.train(cv.ml.TrainData_create(new_samples, cv.ml.ROW_SAMPLE, new_responses.astype(int), varType = var_types))
def predict(self, samples):
new_samples = self.unroll_samples(samples)
_ret, resp = self.model.predict(new_samples)
return resp.ravel().reshape(-1, self.class_n).argmax(1)
class SVM(LetterStatModel):
def __init__(self):
self.model = cv.ml.SVM_create()
def train(self, samples, responses):
self.model.setType(cv.ml.SVM_C_SVC)
self.model.setC(1)
self.model.setKernel(cv.ml.SVM_RBF)
self.model.setGamma(.1)
self.model.train(samples, cv.ml.ROW_SAMPLE, responses.astype(int))
def predict(self, samples):
_ret, resp = self.model.predict(samples)
return resp.ravel()
class MLP(LetterStatModel):
def __init__(self):
self.model = cv.ml.ANN_MLP_create()
def train(self, samples, responses):
_sample_n, var_n = samples.shape
new_responses = self.unroll_responses(responses).reshape(-1, self.class_n)
layer_sizes = np.int32([var_n, 100, 100, self.class_n])
self.model.setLayerSizes(layer_sizes)
self.model.setTrainMethod(cv.ml.ANN_MLP_BACKPROP)
self.model.setBackpropMomentumScale(0)
self.model.setBackpropWeightScale(0.001)
self.model.setTermCriteria((cv.TERM_CRITERIA_COUNT, 20, 0.01))
self.model.setActivationFunction(cv.ml.ANN_MLP_SIGMOID_SYM, 2, 1)
self.model.train(samples, cv.ml.ROW_SAMPLE, np.float32(new_responses))
def predict(self, samples):
_ret, resp = self.model.predict(samples)
return resp.argmax(-1)
from tests_common import NewOpenCVTests
class letter_recog_test(NewOpenCVTests):
def test_letter_recog(self):
eps = 0.01
models = [RTrees, KNearest, Boost, SVM, MLP]
models = dict( [(cls.__name__.lower(), cls) for cls in models] )
testErrors = {RTrees: (98.930000, 92.390000), KNearest: (94.960000, 92.010000),
Boost: (85.970000, 74.920000), SVM: (99.780000, 95.680000), MLP: (90.060000, 87.410000)}
for model in models:
Model = models[model]
classifier = Model()
samples, responses = load_base(self.repoPath + '/samples/data/letter-recognition.data')
train_n = int(len(samples)*classifier.train_ratio)
classifier.train(samples[:train_n], responses[:train_n])
train_rate = np.mean(classifier.predict(samples[:train_n]) == responses[:train_n].astype(int))
test_rate = np.mean(classifier.predict(samples[train_n:]) == responses[train_n:].astype(int))
self.assertLess(train_rate - testErrors[Model][0], eps)
self.assertLess(test_rate - testErrors[Model][1], eps)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()