-
Notifications
You must be signed in to change notification settings - Fork 10
/
detectChars.php
150 lines (120 loc) · 5.35 KB
/
detectChars.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
use CV\FileStorage;
use CV\ML\KNearest;
use const CV\CV_PI;
const MIN_PIXEL_WIDTH = 2;
const MIN_PIXEL_HEIGHT = 8;
const MIN_ASPECT_RATIO = 0.25;
const MAX_ASPECT_RATIO = 1.0;
const MIN_PIXEL_AREA = 80;
const MAX_DIAG_SIZE_MULTIPLE_AWAY = 5.0;
const MAX_ANGLE_BETWEEN_CHARS = 12.0;
const MAX_CHANGE_IN_AREA = 0.5;
const MAX_CHANGE_IN_WIDTH = 0.8;
const MAX_CHANGE_IN_HEIGHT = 0.2;
const MIN_NUMBER_OF_MATCHING_CHARS = 3;
/**
* 加载KNN
* @return bool
*/
function loadKNNDataAndTrainKNN()
{
//读取训练分类器
$fsClassifications = new FileStorage('classifications.xml', FileStorage::READ);//读取分配器文件
if (!$fsClassifications->isOpened()) {
echo "错误, 无法打开训练分类文件, 程序退出\n\n";
return false;
}
$matClassificationInts = $fsClassifications->read('classifications', 5);
$fsClassifications->release();
$fsTrainingImages = new FileStorage('images.xml', FileStorage::READ);
if (!$fsTrainingImages->isOpened()) {
echo "错误, 无法打开训练图片文件, 程序退出\n\n";
return false;
}
$matTrainingImagesAsFlattenedFloats = $fsTrainingImages->read('images', 5);
$fsTrainingImages->release();
$KNearest = KNearest::create();
$KNearest->setDefaultK(1);
return $KNearest->train($matTrainingImagesAsFlattenedFloats, CV\ML\ROW_SAMPLE, $matClassificationInts);
}
function checkIfPossibleChar($possibleChar)
{
if ($possibleChar->boundingRect->area() > MIN_PIXEL_AREA &&
$possibleChar->boundingRect->width > MIN_PIXEL_WIDTH &&
$possibleChar->boundingRect->height > MIN_PIXEL_HEIGHT &&
MIN_ASPECT_RATIO < $possibleChar->dblAspectRatio &&
$possibleChar->dblAspectRatio < MAX_ASPECT_RATIO
) {
return true;
}
return false;
}
function findArrayOfArraysOfMatchingChars(array $arrayOfPossibleChars)
{
$arrayOfArraysOfMatchingChars = [];
foreach ($arrayOfPossibleChars as &$possibleChar) {
$vectorOfMatchingChars = findVectorOfMatchingChars($possibleChar, $arrayOfPossibleChars);
$vectorOfMatchingChars[] = $possibleChar;
if (count($vectorOfMatchingChars) < MIN_NUMBER_OF_MATCHING_CHARS) {
continue;
}
$arrayOfArraysOfMatchingChars[] = $vectorOfMatchingChars;
// exit;
$arrayOfPossibleCharsWithCurrentMatchesRemoved = [];
// $arrayOfPossibleCharsWithCurrentMatchesRemoved = array_diff($arrayOfPossibleChars, $vectorOfMatchingChars);
foreach ($arrayOfPossibleChars as &$possChar) {
if (!in_array($possChar, $vectorOfMatchingChars)) {//todo
$arrayOfPossibleCharsWithCurrentMatchesRemoved[] = $possChar;
}
}
// recursive call
$recursiveVectorOfVectorsOfMatchingChars = findArrayOfArraysOfMatchingChars($arrayOfPossibleCharsWithCurrentMatchesRemoved);
foreach ($recursiveVectorOfVectorsOfMatchingChars as $recursiveVectorOfMatchingChars) { // for each vector of matching chars found by recursive call
$arrayOfArraysOfMatchingChars[] = $recursiveVectorOfMatchingChars; // add to our original vector of vectors of matching chars
}
//
break;
}
return $arrayOfArraysOfMatchingChars;
}
function findVectorOfMatchingChars($possibleChar, $arrayOfChars)
{
$arrayOfMatchingChars = [];
foreach ($arrayOfChars as $possibleMatchingChar) {
if ($possibleMatchingChar->contour == $possibleChar->contour) {
continue;
}
$dblDistanceBetweenChars = distanceBetweenChars($possibleChar, $possibleMatchingChar);
$dblAngleBetweenChars = angleBetweenChars($possibleChar, $possibleMatchingChar);
$dblChangeInArea = (double)abs($possibleMatchingChar->boundingRect->area() - $possibleChar->boundingRect->area()) / (double)$possibleChar->boundingRect->area();
$dblChangeInWidth = (double)abs($possibleMatchingChar->boundingRect->width - $possibleChar->boundingRect->width) / (double)$possibleChar->boundingRect->width;
$dblChangeInHeight = (double)abs($possibleMatchingChar->boundingRect->height - $possibleChar->boundingRect->height) / (double)$possibleChar->boundingRect->height;
// exit;
// check if chars match
if ($dblDistanceBetweenChars < (
$possibleChar->dblDiagonalSize * MAX_DIAG_SIZE_MULTIPLE_AWAY) &&
$dblAngleBetweenChars < MAX_ANGLE_BETWEEN_CHARS &&
$dblChangeInArea < MAX_CHANGE_IN_AREA &&
$dblChangeInWidth < MAX_CHANGE_IN_WIDTH &&
$dblChangeInHeight < MAX_CHANGE_IN_HEIGHT
) {
$arrayOfMatchingChars[] = $possibleMatchingChar; // if the chars are a match, add the current char to vector of matching chars
}
}
return $arrayOfMatchingChars;
}
function distanceBetweenChars(PossibleChar $firstChar, PossibleChar $secondChar)
{
$intX = abs($firstChar->intCenterX - $secondChar->intCenterX);
$intY = abs($firstChar->intCenterY - $secondChar->intCenterY);
return (sqrt(pow($intX, 2) + pow($intY, 2)));
}
function angleBetweenChars(PossibleChar $firstChar, PossibleChar $secondChar)
{
$dblAdj = abs($firstChar->intCenterX - $secondChar->intCenterX);
$dblOpp = abs($firstChar->intCenterY - $secondChar->intCenterY);
$dblAngleInRad = atan($dblOpp / $dblAdj);
$dblAngleInDeg = $dblAngleInRad * (180.0 / CV_PI);
return ($dblAngleInDeg);
}