// -*- C++ -*- // Copyright 2006 Deutsches Forschungszentrum fuer Kuenstliche Intelligenz // or its licensors, as applicable. // // You may not use this file except under the terms of the accompanying license. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You may // obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Project: bpnet -- bpnet network classifier // File: confusion-matrix.cc // Purpose: class for a confusion matrix // Responsible: Hagen Kaprykowsky (kapry@iupr.net) // Reviewer: Yves Rangoni (rangoni@iupr.dfki.de) // Primary Repository: // Web Sites: www.iupr.org, www.dfki.de #include "confusion-matrix.h" #include "ocr-utils.h" using namespace ocropus; using namespace colib; namespace iupr_bpnet { // convert an ascii integer code in a utf8 string with some // white spaces before void ascii_to_nustring(int code, char** str,int size=1) { CHECK_CONDITION(size>0&&code>0); nuchar c(code); nustring s(1); s[0] = c; if (*str) free(*str); *str = s.mallocUtf8Encode(); if (strlen(*str) > 0) { // a trick to have a nice alignment char* ns = (char*)malloc(32); // non-ascii characters *ns = 0; for(int i=0;i0&&nCols>0); confusion.resize(nRows,nCols); fill(confusion,0); }; // constructor with intarray ConfusionMatrix::ConfusionMatrix(colib::intarray &matrix) { CHECK_CONDITION(matrix.rank()==2&&matrix.dim(0)>0&&matrix.dim(0)>0); copy(confusion,matrix); } // destructor ConfusionMatrix::~ConfusionMatrix() { confusion.dealloc(); }; // set matrix entries to zero void ConfusionMatrix::clear() { fill(confusion,0); }; // increment matrix entry by one void ConfusionMatrix::increment(int actual,int predicted) { if(actual>confusion.dim(0)) return; ASSERT(predicted0&&matrix.dim(0)>0); copy(confusion,matrix); } // erase the current matrix by another one void ConfusionMatrix::set(ConfusionMatrix &matrix) { copy(confusion,matrix.confusion); } // have a copy of the matrix void ConfusionMatrix::get(intarray &matrix) { copy(matrix,confusion); } // create a sorted 'list' of confusions void ConfusionMatrix::confusion_to_list(intarray &out) { intarray x,y,v; int l=confusion.dim(0)*confusion.dim(1); x.resize(l); y.resize(l); v.resize(l); int k=0; for(int i=0;i0) && (i!=j) void ConfusionMatrix::printReduced(FILE *stream) { intarray conf; confusion_to_list(conf); fprintf(stream, "cnf -t- -o-\n"); for(int i=0;i0) && (conf(i,0)!=conf(i,1))) { fprintf(stream, "cnf %4d %4d %6d\n",conf(i,0),conf(i,1),conf(i,2)); } } } // dump confusion matrix to a stream // An aligned table is created, size is the field width. // If norm is set to true, the values are normalized, and size is // the number of digits to be printed after the decimal point void ConfusionMatrix::printMatrix(FILE* stream,int size,bool norm) { CHECK_CONDITION(size>0); char format_v[32]; char format_b[32]; float _isum = 1.; if(norm==true) { _isum = 1./sum(confusion); sprintf(format_v,"%%%d.%df",size+3,size); size += 3; } else { sprintf(format_v,"%%%dd",size); } sprintf(format_b,"%%%dd",size); for(int k=0;k<=size;k++) { fprintf(stream," "); } for(int j=0;j0); char formatn[32]; char formats[32]; float _isum = 1.; if(norm==true) { _isum = 1./sum(confusion); sprintf(formatn,"%%%d.%df",size+3,size); size += 3; } else { sprintf(formatn,"%%%dd",size); } sprintf(formats,"%%%ds",size); for(int k=0;k<=size;k++) fprintf(stream," "); char* str = 0; for(int j=0;j0 && (conf(i,0)==conf(i,1))) { print_one_confusion(stream,map,conf(i,0),conf(i,1),conf(i,2),"good"); } } fprintf(stream, "--------------\n"); for(int i=0;i0) && (conf(i,0)!=conf(i,1))) { print_one_confusion(stream,map,conf(i,0),conf(i,1),conf(i,2),"conf"); } } } // dump one line of confusion to a stream // should be note use from the outside, but through printReduced void ConfusionMatrix::print_one_confusion(FILE* stream,ClassMap &map,int i,int j,int v, const char* prefix) { char* str1 = 0; char* str2 = 0; ascii_to_nustring(map.get_ascii(i),&str1,3); ascii_to_nustring(map.get_ascii(j),&str2,3); fprintf(stream, "%s (%4d <-> %4d) (%6d <-> %6d)" " (%3s <-> %3s):\t%6d\n", prefix,i,j, map.get_ascii(i),map.get_ascii(j), (map.get_ascii(i)==172)?"*G*":str1, (map.get_ascii(j)==172)?"*G*":str2, v); if (str1) free(str1); if (str2) free(str2); } void ConfusionMatrix::logMatrix(strbuf &out) { strbuf aux; strbuf_format(aux,"\n\n"); out = aux; for(int j=0;j%d",j); out += aux; } strbuf_format(aux,"\n"); out += aux; for(int i=0;i\n",i); out += aux; for(int j=0;j%d",confusion(i,j)); } else { strbuf_format(aux,"",confusion(i,j)); } out += aux; } strbuf_format(aux,"\n"); out += aux; } strbuf_format(aux,"
%d%d
\n"); out += aux; } void ConfusionMatrix::logMatrix(strbuf &out, ClassMap &map) { strbuf aux; strbuf_format(aux,"\n\n"); out = aux; for(int j=0;j"); out += aux; code_to_strbuf(aux, map.get_ascii(j)); out += aux; strbuf_format(aux,""); out += aux; } strbuf_format(aux,"\n"); out += aux; for(int i=0;i"); out += aux; code_to_strbuf(aux, map.get_ascii(i)); out += aux; strbuf_format(aux,""); out += aux; for(int j=0;j%d", confusion(i,j)); out += aux; } else { strbuf_format(aux,"",confusion(i,j)); out += aux; } } strbuf_format(aux,"\n"); out += aux; } strbuf_format(aux,"
%d
\n"); out += aux; } void ConfusionMatrix::print_one_confusion(strbuf &out, ClassMap &map, int i, int j, int v, const char* prefix) { strbuf aux; strbuf_format(aux, "%s" "%d" "%d" "%d" "%d", prefix,i,j, map.get_ascii(i),map.get_ascii(j)); out = aux; if (map.get_ascii(i)==172) { strbuf_format(aux,"*G*"); out += aux; } else { strbuf_format(aux,""); out += aux; code_to_strbuf(aux, map.get_ascii(i)); out += aux; strbuf_format(aux,""); out += aux; } if (map.get_ascii(j)==172) { strbuf_format(aux,"*G*"); out += aux; } else { strbuf_format(aux,""); out += aux; code_to_strbuf(aux, map.get_ascii(j)); out += aux; strbuf_format(aux,""); out += aux; } strbuf_format(aux,"%d\n",v); out += aux; } void ConfusionMatrix::logReducedConfusion(strbuf &out, ClassMap &map) { strbuf aux; intarray conf; confusion_to_list(conf); strbuf_format(aux,""); out = aux; strbuf_format(aux,"" "\n"); out += aux; strbuf_format(aux,"" "" "\n"); out += aux; strbuf_format(aux,"\n"); out += aux; for(int i=0;i0 && (conf(i,0)==conf(i,1))) { print_one_confusion(aux,map,conf(i,0),conf(i,1), conf(i,2),"good"); out += aux; } } strbuf_format(aux,"\n"); out += aux; for(int i=0;i0) && (conf(i,0)!=conf(i,1))) { print_one_confusion(aux,map,conf(i,0),conf(i,1), conf(i,2),"conf"); out += aux; } } strbuf_format(aux,"
internalascii" "utf8
-t--o--t--o--t--o-
\n"); out += aux; } ConfusionMatrix *make_ConfusionMatrix(int ncls) { return new ConfusionMatrix(ncls,ncls); } ConfusionMatrix *make_ConfusionMatrix(colib::intarray &c) { return new ConfusionMatrix(c); } }