Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

put aside others, finally found the memleak in swt impl

  • Loading branch information...
commit 6174b659ba39b9d2fa7764a8bd97ea64b7f5c983 1 parent a191811
@liuliu authored
View
296 bin/swtcreate.c
@@ -44,162 +44,151 @@ static double om_one = 0.8;
static double center_diff_thr = 1.0;
// compute harmonic mean of precision / recall of swt
-static double _ccv_evaluate_wolf(ccv_array_t* detected, ccv_array_t* gt, double a, ccv_swt_param_t params, double* precision, double* recall)
+static void _ccv_evaluate_wolf(ccv_array_t* words, ccv_array_t* truth, ccv_swt_param_t params, double* precision, double* recall)
{
- int i, j, k;
- int total_detected = 0, total_truth = 0;
- double total_precision = 0, total_recall = 0;
- for (i = 0; i < detected->rnum; i++)
+ if (words->rnum == 0 || truth->rnum == 0)
+ return;
+ int j, k;
+ double total_recall = 0, total_precision = 0;
+ int* cG = (int*)ccmalloc(sizeof(int) * truth->rnum);
+ int* cD = (int*)ccmalloc(sizeof(int) * words->rnum);
+ memset(cG, 0, sizeof(int) * truth->rnum);
+ memset(cD, 0, sizeof(int) * words->rnum);
+ double* mG = (double*)ccmalloc(sizeof(double) * truth->rnum * words->rnum);
+ double* mD = (double*)ccmalloc(sizeof(double) * truth->rnum * words->rnum);
+ memset(mG, 0, sizeof(double) * truth->rnum * words->rnum);
+ memset(mD, 0, sizeof(double) * truth->rnum * words->rnum);
+ for (j = 0; j < truth->rnum; j++)
{
- ccv_array_t* words = *(ccv_array_t**)ccv_array_get(detected, i);
- ccv_array_t* truth = *(ccv_array_t**)ccv_array_get(gt, i);
- if (words->rnum == 0 || truth->rnum == 0)
- {
- ccv_array_free(words);
- continue;
- }
- total_detected += words->rnum;
- total_truth += truth->rnum;
- int* cG = (int*)ccmalloc(sizeof(int) * truth->rnum);
- int* cD = (int*)ccmalloc(sizeof(int) * words->rnum);
- memset(cG, 0, sizeof(int) * truth->rnum);
- memset(cD, 0, sizeof(int) * words->rnum);
- double* mG = (double*)ccmalloc(sizeof(double) * truth->rnum * words->rnum);
- double* mD = (double*)ccmalloc(sizeof(double) * truth->rnum * words->rnum);
- memset(mG, 0, sizeof(double) * truth->rnum * words->rnum);
- memset(mD, 0, sizeof(double) * truth->rnum * words->rnum);
- for (j = 0; j < truth->rnum; j++)
+ ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(truth, j);
+ for (k = 0; k < words->rnum; k++)
{
- ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(truth, j);
- for (k = 0; k < words->rnum; k++)
+ ccv_rect_t* target = (ccv_rect_t*)ccv_array_get(words, k);
+ int match = ccv_max(ccv_min(target->x + target->width, rect->x + rect->width) - ccv_max(target->x, rect->x), 0) * ccv_max(ccv_min(target->y + target->height, rect->y + rect->height) - ccv_max(target->y, rect->y), 0);
+ if (match > 0)
{
- ccv_rect_t* target = (ccv_rect_t*)ccv_array_get(words, k);
- int match = ccv_max(ccv_min(target->x + target->width, rect->x + rect->width) - ccv_max(target->x, rect->x), 0) * ccv_max(ccv_min(target->y + target->height, rect->y + rect->height) - ccv_max(target->y, rect->y), 0);
- if (match > 0)
- {
- mG[j * words->rnum + k] = (double)match / (double)(rect->width * rect->height);
- mD[k * truth->rnum + j] = (double)match / (double)(target->width * target->height);
- ++cG[j];
- ++cD[k];
- }
+ mG[j * words->rnum + k] = (double)match / (double)(rect->width * rect->height);
+ mD[k * truth->rnum + j] = (double)match / (double)(target->width * target->height);
+ ++cG[j];
+ ++cD[k];
}
}
- unsigned char* tG = (unsigned char*)ccmalloc(truth->rnum);
- unsigned char* tD = (unsigned char*)ccmalloc(words->rnum);
- memset(tG, 0, truth->rnum);
- memset(tD, 0, words->rnum);
- // one to one match
- for (j = 0; j < truth->rnum; j++)
+ }
+ unsigned char* tG = (unsigned char*)ccmalloc(truth->rnum);
+ unsigned char* tD = (unsigned char*)ccmalloc(words->rnum);
+ memset(tG, 0, truth->rnum);
+ memset(tD, 0, words->rnum);
+ // one to one match
+ for (j = 0; j < truth->rnum; j++)
+ {
+ if (cG[j] != 1)
+ continue;
+ ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(truth, j);
+ for (k = 0; k < words->rnum; k++)
{
- if (cG[j] != 1)
+ if (cD[k] != 1)
continue;
- ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(truth, j);
- for (k = 0; k < words->rnum; k++)
+ ccv_rect_t* target = (ccv_rect_t*)ccv_array_get(words, k);
+ if (mG[j * words->rnum + k] >= one_g && mD[k * truth->rnum + j] >= one_d)
{
- if (cD[j] != 1)
- continue;
- ccv_rect_t* target = (ccv_rect_t*)ccv_array_get(words, k);
- if (mG[j * words->rnum + k] >= one_g && mD[k * truth->rnum + j] >= one_d)
+ double dx = (target->x + target->width * 0.5) - (rect->x + rect->width * 0.5);
+ double dy = (target->y + target->height * 0.5) - (rect->y + rect->height * 0.5);
+ double d = sqrt(dx * dx + dy * dy) * 2.0 / (sqrt(target->width * target->width + target->height * target->height) + sqrt(rect->width * rect->width + rect->height * rect->height));
+ if (d < center_diff_thr)
{
- double dx = (target->x + target->width * 0.5) - (rect->x + rect->width * 0.5);
- double dy = (target->y + target->height * 0.5) - (rect->y + rect->height * 0.5);
- double d = sqrt(dx * dx + dy * dy) * 2.0 / (sqrt(target->width * target->width + target->height * target->height) + sqrt(rect->width * rect->width + rect->height * rect->height));
- if (d < center_diff_thr)
- {
- total_recall += 1.0;
- total_precision += 1.0;
- tG[j] = tD[k] = 1;
- }
+ total_recall += 1.0;
+ total_precision += 1.0;
+ assert(tG[j] == 0);
+ assert(tD[k] == 0);
+ tG[j] = tD[k] = 1;
}
}
}
- int* many = (int*)ccmalloc(sizeof(int) * ccv_max(words->rnum, truth->rnum));
- // one to many match, starts with ground truth
- for (j = 0; j < truth->rnum; j++)
+ }
+ int* many = (int*)ccmalloc(sizeof(int) * ccv_max(words->rnum, truth->rnum));
+ // one to many match, starts with ground truth
+ for (j = 0; j < truth->rnum; j++)
+ {
+ if (tG[j] || cG[j] <= 1)
+ continue;
+ double one_sum = 0;
+ int no_many = 0;
+ for (k = 0; k < words->rnum; k++)
{
- if (tG[j] || cG[j] <= 1)
+ if (tD[k])
continue;
- double one_sum = 0;
- int no_many = 0;
- for (k = 0; k < words->rnum; k++)
+ double many_single = mD[k * truth->rnum + j];
+ if (many_single >= one_d)
{
- if (tD[k])
- continue;
- double many_single = mD[k * truth->rnum + j];
- if (many_single >= one_d)
- {
- one_sum += mG[j * words->rnum + k];
- many[no_many] = k;
- ++no_many;
- }
+ one_sum += mG[j * words->rnum + k];
+ many[no_many] = k;
+ ++no_many;
}
- if (no_many == 1)
+ }
+ if (no_many == 1)
+ {
+ // degrade to one to one match
+ if (mG[j * words->rnum + many[0]] >= one_g && mD[many[0] * truth->rnum + j] >= one_d)
{
- // degrade to one to one match
- if (mG[j * words->rnum + many[0]] >= one_g && mD[many[0] * truth->rnum + j] >= one_d)
- {
- total_recall += 1.0;
- total_precision += 1.0;
- tG[j] = tD[many[0]] = 1;
- }
- } else if (one_sum >= one_g) {
- for (k = 0; k < no_many; k++)
- tD[many[k]] = 1;
- total_recall += om_one;
- total_precision += om_one * no_many;
+ total_recall += 1.0;
+ total_precision += 1.0;
+ tG[j] = tD[many[0]] = 1;
}
+ } else if (one_sum >= one_g) {
+ for (k = 0; k < no_many; k++)
+ tD[many[k]] = 1;
+ total_recall += om_one;
+ total_precision += om_one / (1 + log(no_many));
}
- // one to many match, with estimate
- for (k = 0; k < words->rnum; k++)
+ }
+ // one to many match, with estimate
+ for (k = 0; k < words->rnum; k++)
+ {
+ if (tD[k] || cD[k] <= 1)
+ continue;
+ double one_sum = 0;
+ int no_many = 0;
+ for (j = 0; j < truth->rnum; j++)
{
- if (tD[k] || cD[k] <= 1)
+ if (tG[j])
continue;
- double one_sum = 0;
- int no_many = 0;
- for (j = 0; j < truth->rnum; j++)
+ double many_single = mG[j * words->rnum + k];
+ if (many_single >= one_g)
{
- if (tG[j])
- continue;
- double many_single = mG[j * words->rnum + k];
- if (many_single >= one_g)
- {
- one_sum += mD[k * truth->rnum + j];
- many[no_many] = j;
- ++no_many;
- }
+ one_sum += mD[k * truth->rnum + j];
+ many[no_many] = j;
+ ++no_many;
}
- if (no_many == 1)
+ }
+ if (no_many == 1)
+ {
+ // degrade to one to one match
+ if (mG[many[0] * words->rnum + k] >= one_g && mD[k * truth->rnum + many[0]] >= one_d)
{
- // degrade to one to one match
- if (mG[many[0] * words->rnum + k] >= one_g && mD[k * truth->rnum + many[0]] >= one_d)
- {
- total_recall += 1.0;
- total_precision += 1.0;
- tG[many[0]] = tD[k] = 1;
- }
- } else if (one_sum >= one_g) {
- for (j = 0; j < no_many; j++)
- tG[many[j]] = 1;
- total_recall += om_one * no_many;
- total_precision += om_one;
+ total_recall += 1.0;
+ total_precision += 1.0;
+ tG[many[0]] = tD[k] = 1;
}
+ } else if (one_sum >= one_g) {
+ for (j = 0; j < no_many; j++)
+ tG[many[j]] = 1;
+ total_recall += om_one / (1 + log(no_many));
+ total_precision += om_one;
}
- ccv_array_free(words);
- ccfree(many);
- ccfree(tG);
- ccfree(tD);
- ccfree(cG);
- ccfree(cD);
- ccfree(mG);
- ccfree(mD);
}
- total_precision /= total_detected;
- total_recall /= total_truth;
+ ccfree(many);
+ ccfree(tG);
+ ccfree(tD);
+ ccfree(cG);
+ ccfree(cD);
+ ccfree(mG);
+ ccfree(mD);
+ assert(total_precision < words->rnum + 0.1);
+ assert(total_recall < truth->rnum + 0.1);
if (precision)
*precision = total_precision;
if (recall)
*recall = total_recall;
- return 1.0 / (a / total_precision + (1.0 - a) / total_recall);
}
typedef struct {
@@ -244,9 +233,9 @@ int main(int argc, char** argv)
if (argc <= 1)
exit_with_help();
ccv_swt_param_t params = {
- .interval = 0,
+ .interval = 5,
.same_word_thresh = { 0.5, 0.9 },
- .min_neighbors = 0,
+ .min_neighbors = 2,
.scale_invariant = 0,
.size = 3,
.low_thresh = 65,
@@ -369,7 +358,7 @@ int main(int argc, char** argv)
.step = 0.01,
.enable = 1,
};
- int i, j, k, iterations = 1; // 10;
+ int i, j, k, l, iterations = 10;
while (getopt_long_only(argc - 1, argv + 1, "", swt_options, &k) != -1)
{
switch (k)
@@ -483,19 +472,48 @@ int main(int argc, char** argv)
int total_iterations = 0; \
for (v = parameter##_range.min_value; v <= parameter##_range.max_value; v += parameter##_range.step) \
++total_iterations; \
- ccv_array_t** detected = (ccv_array_t**)alloca(sizeof(ccv_array_t*) * total_iterations); \
- for (v = parameter##_range.min_value, j = 0; v <= parameter##_range.max_value; v += parameter##_range.step, j++) \
- detected[j] = ccv_array_new(sizeof(ccv_array_t*), 64, 0); \
+ double* precision = (double*)ccmalloc(sizeof(double) * total_iterations); \
+ double* recall = (double*)ccmalloc(sizeof(double) * total_iterations); \
+ double* total_words = (double*)ccmalloc(sizeof(double) * total_iterations); \
+ memset(precision, 0, sizeof(double) * total_iterations); \
+ memset(recall, 0, sizeof(double) * total_iterations); \
+ memset(total_words, 0, sizeof(double) * total_iterations); \
+ double total_truth = 0; \
for (j = 0; j < aof->rnum; j++) \
{ \
char* name = *(char**)ccv_array_get(aof, j); \
ccv_dense_matrix_t* image = 0; \
ccv_read(name, &image, CCV_IO_GRAY | CCV_IO_ANY_FILE); \
+ ccv_array_t* truth = *(ccv_array_t**)ccv_array_get(aow, j); \
+ total_truth += truth->rnum; \
+ int upscaled = (image->rows < 500 || image->cols < 500); \
+ if (upscaled) \
+ { \
+ ccv_dense_matrix_t* up2x = 0; \
+ ccv_sample_up(image, &up2x, 0, 0, 0); \
+ ccv_matrix_free(image); \
+ image = up2x; \
+ } \
for (v = parameter##_range.min_value, k = 0; v <= parameter##_range.max_value; v += parameter##_range.step, k++) \
{ \
params.parameter = (type)(v + rounding); \
ccv_array_t* words = ccv_swt_detect_words(image, params); \
- ccv_array_push(detected[k], &words); \
+ if (upscaled) \
+ for (l = 0; l < words->rnum; l++) \
+ { \
+ ccv_rect_t* word = (ccv_rect_t*)ccv_array_get(words, l); \
+ word->x /= 2; \
+ word->y /= 2; \
+ word->width /= 2; \
+ word->height /= 2; \
+ } \
+ double one_precision = 0, one_recall = 0; \
+ _ccv_evaluate_wolf(words, truth, params, &one_precision, &one_recall); \
+ assert(one_precision <= words->rnum + 0.1); \
+ precision[k] += one_precision; \
+ recall[k] += one_recall; \
+ total_words[k] += words->rnum; \
+ ccv_array_free(words); \
FLUSH("perform SWT on %s (%d / %d) for " #parameter " = (%lg <- [%lg, %lg])", name, j + 1, aof->rnum, v, parameter##_range.min_value, parameter##_range.max_value); \
} \
ccv_matrix_free(image); \
@@ -503,19 +521,23 @@ int main(int argc, char** argv)
for (v = parameter##_range.min_value, j = 0; v <= parameter##_range.max_value; v += parameter##_range.step, j++) \
{ \
params.parameter = (type)(v + rounding); \
- double f, recall, precision; \
- f = _ccv_evaluate_wolf(detected[j], aow, a, params, &precision, &recall); \
- ccv_array_free(detected[j]); \
+ double f, total_precision = precision[j], total_recall = recall[j]; \
+ total_precision /= total_words[j]; \
+ total_recall /= total_truth; \
+ f = 1.0 / (a / total_precision + (1.0 - a) / total_recall); \
if (f > best_f) \
{ \
best_params = params; \
best_f = f; \
- best_precision = precision; \
- best_recall = recall; \
+ best_precision = total_precision; \
+ best_recall = total_recall; \
} \
- FLUSH("current harmonic mean : %.2lf%%, precision : %.2lf%%, recall : %.2lf%% ; best harmonic mean : %.2lf%%, precision : %.2lf%%, recall : %.2lf%% ; at " #parameter " = %lg (%lg <- [%lg, %lg])", f * 100, precision * 100, recall * 100, best_f * 100, best_precision * 100, best_recall * 100, (double)best_params.parameter, v, parameter##_range.min_value, parameter##_range.max_value); \
+ FLUSH("current harmonic mean : %.2lf%%, precision : %.2lf%%, recall : %.2lf%% ; best harmonic mean : %.2lf%%, precision : %.2lf%%, recall : %.2lf%% ; at " #parameter " = %lg (%lg <- [%lg, %lg])", f * 100, total_precision * 100, total_recall * 100, best_f * 100, best_precision * 100, best_recall * 100, (double)best_params.parameter, v, parameter##_range.min_value, parameter##_range.max_value); \
} \
printf("\n"); \
+ ccfree(precision); \
+ ccfree(recall); \
+ ccfree(total_words); \
}
for (i = 0; i < iterations; i++)
{
View
69 bin/swtdetect.c
@@ -12,28 +12,28 @@ unsigned int get_current_time()
int main(int argc, char** argv)
{
ccv_swt_param_t params = {
- .interval = 5,
+ .interval = 2,
.same_word_thresh = { 0.5, 0.9 },
- .min_neighbors = 2,
+ .min_neighbors = 0,
.scale_invariant = 1,
.size = 3,
- .low_thresh = 65,
- .high_thresh = 212,
+ .low_thresh = 75,
+ .high_thresh = 250,
.max_height = 300,
.min_height = 14,
- .min_area = 94,
- .letter_occlude_thresh = 4,
- .aspect_ratio = 9,
- .std_ratio = 0.95,
- .thickness_ratio = 1.7,
- .height_ratio = 1.8,
- .intensity_thresh = 34,
- .distance_ratio = 3.3,
- .intersect_ratio = 1.2,
- .letter_thresh = 4,
- .elongate_ratio = 1.9,
+ .min_area = 75,
+ .letter_occlude_thresh = 3,
+ .aspect_ratio = 10,
+ .std_ratio = 0.75,
+ .thickness_ratio = 2.0,
+ .height_ratio = 2.0,
+ .intensity_thresh = 35,
+ .distance_ratio = 3.0,
+ .intersect_ratio = 1.5,
+ .letter_thresh = 3,
+ .elongate_ratio = 2.0,
.breakdown = 1,
- .breakdown_ratio = 0.82,
+ .breakdown_ratio = 1.0,
};
ccv_enable_default_cache();
ccv_dense_matrix_t* image = 0;
@@ -41,7 +41,10 @@ int main(int argc, char** argv)
if (image != 0)
{
unsigned int elapsed_time = get_current_time();
- ccv_array_t* words = ccv_swt_detect_words(image, params);
+ ccv_dense_matrix_t* up2x = 0;
+ ccv_sample_up(image, &up2x, 0, 0, 0);
+ ccv_array_t* words = ccv_swt_detect_words(up2x, params);
+ ccv_matrix_free(up2x);
elapsed_time = get_current_time() - elapsed_time;
if (words)
{
@@ -49,7 +52,7 @@ int main(int argc, char** argv)
for (i = 0; i < words->rnum; i++)
{
ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(words, i);
- printf("%d %d %d %d\n", rect->x, rect->y, rect->width, rect->height);
+ printf("%d %d %d %d\n", rect->x / 2, rect->y / 2, rect->width / 2, rect->height / 2);
}
printf("total : %d in time %dms\n", words->rnum, elapsed_time);
ccv_array_free(words);
@@ -71,15 +74,31 @@ int main(int argc, char** argv)
file[read] = 0;
image = 0;
ccv_read(file, &image, CCV_IO_GRAY | CCV_IO_ANY_FILE);
- ccv_array_t* words = ccv_swt_detect_words(image, params);
- int i;
- printf("%s\n", file);
- for (i = 0; i < words->rnum; i++)
+ if (image->rows < 500 || image->cols < 500)
{
- ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(words, i);
- printf("%d %d %d %d\n", rect->x, rect->y, rect->width, rect->height);
+ ccv_dense_matrix_t* up2x = 0;
+ ccv_sample_up(image, &up2x, 0, 0, 0);
+ ccv_array_t* words = ccv_swt_detect_words(up2x, params);
+ ccv_matrix_free(up2x);
+ int i;
+ printf("%s\n", file);
+ for (i = 0; i < words->rnum; i++)
+ {
+ ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(words, i);
+ printf("%d %d %d %d\n", rect->x / 2, rect->y / 2, rect->width / 2, rect->height / 2);
+ }
+ ccv_array_free(words);
+ } else {
+ ccv_array_t* words = ccv_swt_detect_words(image, params);
+ int i;
+ printf("%s\n", file);
+ for (i = 0; i < words->rnum; i++)
+ {
+ ccv_rect_t* rect = (ccv_rect_t*)ccv_array_get(words, i);
+ printf("%d %d %d %d\n", rect->x, rect->y, rect->width, rect->height);
+ }
+ ccv_array_free(words);
}
- ccv_array_free(words);
ccv_matrix_free(image);
}
free(file);
View
4 bin/swtvldtr.rb
@@ -101,7 +101,7 @@
tD[j] = true
end
recall += om_one
- precision += om_one * many.count
+ precision += om_one / (1.0 + Math.log(many.count))
end
end
# one to many match, with estimate
@@ -128,7 +128,7 @@
many.each do |i|
tG[i] = true
end
- recall += om_one * many.count
+ recall += om_one / (1.0 + Math.log(many.count))
precision += om_one
end
end
View
42 doc/swt.md
@@ -11,4 +11,44 @@ How it works?
-------------
It is a long story, as always, please read their paper. SWT tries to capture the
-only text effective features and using geometric signature of text.
+only text effective features and using geometric signature of text to filter out
+non-text areas. As a result, SWT gives you reliable text regions that is language
+neutral. Try it yourself:
+
+ ./swtdetect <Your Image contains Text> | ./swtdraw.rb <Your Image contains Text> output.png
+
+Checkout output.png, luckily, the text area is labeled.
+
+What about performance?
+-----------------------
+
+SWT is quite fast. The SWT without scale-invariant support (multi-scale) can run
+on a 640x480 photo for well under 50 milliseconds on my laptop. By extending SWT
+to multi-scale, the accuracy increased by about 10% with about 2~4 times longer
+running time.
+
+Accuracy-wise:
+
+ccv's SWT implementation performs on ICDAR 2003 dataset achieved similar performance
+with what Epshtein et al. reported in their paper, namely, with the old measure
+method described in ICDAR 2003 contest, ccv's implementation was able to achieve
+precision rate at 66% and recall rate at 59% (numbers reported in the paper are
+precision rate 73% and recall rate at 60%).
+
+However, these results are quite out-dated, and using [ICDAR 2011 dataset](http://robustreading.opendfki.de/wiki/SceneText)
+more meaningful comparison is possible.
+
+With ccv's scale-invariant SWT implementation, and do parameter search on ICDAR
+2011's training dataset, I was able to achieve:
+
+ precision: 59%
+ recall: 61%
+ harmonic mean: 60%
+
+Which would rank around 2nd to 3rd place in the chart. Please note that other
+methods in comparison are language specific, thus, were trained with additional
+character shape information using SVM or Adaboost where as SWT is language neutral
+and doesn't use any language specific features.
+
+Speed-wise:
+
View
12 lib/ccv_swt.c
@@ -584,13 +584,16 @@ static ccv_array_t* _ccv_swt_break_words(ccv_array_t* textline, ccv_swt_param_t
mean = mean / (t->neighbors - 1);
if (sqrt(var) > mean * params.breakdown_ratio)
{
- ccv_textline_t nt = { .neighbors = 0 };
+ ccv_textline_t nt = { .neighbors = 0, .letters = 0 };
_ccv_swt_add_letter(&nt, t->letters[0]);
for (j = 0; j < t->neighbors - 1; j++)
{
if (buffer[j] > threshold)
{
ccv_array_push(words, &nt.rect);
+ if (nt.letters)
+ ccfree(nt.letters);
+ nt.letters = 0;
nt.neighbors = 0;
}
_ccv_swt_add_letter(&nt, t->letters[j + 1]);
@@ -635,8 +638,6 @@ ccv_array_t* ccv_swt_detect_words(ccv_dense_matrix_t* a, ccv_swt_param_t params)
// create down-sampled image on-demand because swt itself is very memory intensive
if (k % next)
{
- if (pyr != phx)
- ccv_matrix_free(pyr);
pyr = 0;
int j = k % next;
ccv_resample(phx, &pyr, 0, (int)(phx->rows / pow(scale, j)), (int)(phx->cols / pow(scale, j)), CCV_INTER_AREA);
@@ -660,6 +661,8 @@ ccv_array_t* ccv_swt_detect_words(ccv_dense_matrix_t* a, ccv_swt_param_t params)
ccv_swt(pyr, &swt, 0, params);
ccv_array_t* lettersF = _ccv_swt_connected_letters(pyr, swt, params);
ccv_matrix_free(swt);
+ if (pyr != phx)
+ ccv_matrix_free(pyr);
ccv_array_t* textline2 = _ccv_swt_merge_textline(lettersF, params);
for (i = 0; i < textline2->rnum; i++)
ccv_array_push(textline, ccv_array_get(textline2, i));
@@ -753,6 +756,7 @@ ccv_array_t* ccv_swt_detect_words(ccv_dense_matrix_t* a, ccv_swt_param_t params)
r2->neighbors = 1;
}
}
+ ccv_array_free(idx);
ccv_array_free(all_words);
if (params.min_neighbors > 1)
{
@@ -770,8 +774,6 @@ ccv_array_t* ccv_swt_detect_words(ccv_dense_matrix_t* a, ccv_swt_param_t params)
// just copy the pointer for min_neighbors == 1
all_words = new_words;
}
- if (pyr != phx)
- ccv_matrix_free(pyr);
if (phx != a)
ccv_matrix_free(phx);
return all_words;
Please sign in to comment.
Something went wrong with that request. Please try again.