summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Le Garrec <legarrec.vincent@gmail.com>2018-01-16 22:05:50 +0100
committerVincent Le Garrec <legarrec.vincent@gmail.com>2018-01-16 22:05:50 +0100
commit85188af850f4e7ea252df6202215c328b63bb115 (patch)
tree62d91d81fd02a574c35cedc0c09b97091505dbb7
parentAdd fann dependency (diff)
downloadcore-85188af850f4e7ea252df6202215c328b63bb115.tar.gz
core-85188af850f4e7ea252df6202215c328b63bb115.zip
Recognize char by using lib fann network
Read all char, train the neural network with these char then apply the draw to get recognition. Change-Id: Ie48a173703f599b054f0c6edfa38acfdfb25ec71
-rw-r--r--cui/source/dialogs/cuicharmap.cxx281
-rw-r--r--cui/source/inc/cuicharmap.hxx8
2 files changed, 238 insertions, 51 deletions
diff --git a/cui/source/dialogs/cuicharmap.cxx b/cui/source/dialogs/cuicharmap.cxx
index 8bf4d7166801..b571fdeaf073 100644
--- a/cui/source/dialogs/cuicharmap.cxx
+++ b/cui/source/dialogs/cuicharmap.cxx
@@ -52,6 +52,9 @@
#include <unicode/uchar.h>
#include <unicode/utypes.h>
+#include <fann.h>
+#include <floatfann.h>
+
using namespace css;
Ocr::Ocr(const Bitmap& b, long w, long h) : m_bitmap(b), w_(w), h_(h), data()
@@ -67,18 +70,25 @@ void Ocr::ReadBitmap()
{
for (long i = 0; i < w_; i++)
{
- Color c = r->GetPixel (j, i);
- if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
- {
- data[j*w_+i] = 1;
- }
- else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+ if (i >= r->Width () || j >= r->Height())
{
data[j*w_+i] = 0;
}
else
{
- data[j*w_+i] = 2;
+ Color c = r->GetPixel (j, i);
+ if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+ {
+ data[j*w_+i] = 1;
+ }
+ else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+ {
+ data[j*w_+i] = 0;
+ }
+ else
+ {
+ data[j*w_+i] = 2;
+ }
}
}
}
@@ -200,6 +210,88 @@ void Ocr::ScaleBitmap(long width, long height)
}
m_bitmap.Scale(new_size, new_size, BmpScaleFlag::Fast);
+
+ w_ = width;
+ h_ = height;
+}
+
+void Ocr::ToFile(std::ofstream &file)
+{
+ BitmapReadAccess * r = m_bitmap.AcquireReadAccess ();
+
+ std::cout << "2r->Width () != w_" << r->Width () << " vs " << w_ << std::endl;
+ std::cout << "2r->Height() != h_" << r->Height () << " vs " << h_ << std::endl;
+ for (long j = 0; j < h_; j++)
+ {
+ std::cout << j << std::endl;
+ for (long i = 0; i < w_; i++)
+ {
+ std::cout << i << std::endl;
+ if (i >= r->Width () || j >= r->Height())
+ {
+ file << "-1 ";
+ }
+ else
+ {
+ Color c = r->GetPixel(j, i);
+ if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+ {
+ file << "-1 ";
+ }
+ else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+ {
+ file << "1 ";
+ }
+ else
+ {
+ file << "1 ";
+ }
+ }
+ }
+ }
+ file << std::endl;
+}
+
+void Ocr::ToFann(fann_type *out_data)
+{
+ BitmapReadAccess * r = m_bitmap.AcquireReadAccess ();
+ long idata = 0;
+
+ std::cout << "3r->Width () != w_" << r->Width () << " vs " << w_ << std::endl;
+ std::cout << "3r->Height() != h_" << r->Height () << " vs " << h_ << std::endl;
+
+ for (long j = 0; j < h_; j++)
+ {
+ for (long i = 0; i < w_; i++)
+ {
+ if (i >= r->Width () || j >= r->Height())
+ {
+ out_data[idata] = -1;
+ std::cout << "-1 ";
+ }
+ else
+ {
+ Color c = r->GetPixel(j, i);
+ if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+ {
+ out_data[idata] = -1;
+ std::cout << "-1 ";
+ }
+ else if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+ {
+ out_data[idata] = 1;
+ std::cout << "1 ";
+ }
+ else
+ {
+ out_data[idata] = 1;
+ std::cout << "1 ";
+ }
+ }
+ idata++;
+ }
+ }
+ std::cout << std::endl;
}
// class SvxCharacterMap =================================================
@@ -1095,6 +1187,8 @@ IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, Button*, void)
EndDialog(RET_OK);
}
+#include <iostream>
+
IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
{
if (m_pDrawChk->IsChecked())
@@ -1120,57 +1214,145 @@ IMPL_LINK_NOARG(SvxCharacterMap, DrawToggleHdl, Button*, void)
m_pSearchSet->ClearPreviousData();
- sal_UCS4 *range = new sal_UCS4[2];
- range[0] = 0;
- range[1] = 1114111;
- CmapResult rCR (true, range, 1);
- FontCharMapRef xFontCharMap(new FontCharMap(rCR));
- m_pSearchSet->GetFontCharMap(xFontCharMap);
-
- sal_UCS4 sChar = xFontCharMap->GetFirstChar();
- while(sChar != xFontCharMap->GetLastChar())
+ // Deep learning. Take about 30-60 minutes
+ if (access( "/tmp/fann.net", F_OK ) == -1)
{
- VirtualDevice od;
- OUString aOUStr( &sChar, 1 );
- Size s50(Ocr::SIZE, Ocr::SIZE);
- od.SetOutputSize( s50 );
- vcl::Font aFontBis(aFont);
- aFontBis.SetFontHeight(Ocr::SIZE);
- od.SetFont( aFontBis );
- od.DrawText( p, aOUStr );
- w = od.GetOutputWidthPixel ();
- h = od.GetOutputHeightPixel ();
-
- Size s2(w, h);
- b = od.GetBitmap (p, s2);
-
- BitmapReadAccess* r = b.AcquireReadAccess ();
-
- for (long j = 0; j < h; j++)
+ FontCharMapRef xFontCharMap(new FontCharMap());
+ m_pSearchSet->GetFontCharMap(xFontCharMap);
+
+
+ // One input for each pixel.
+ const unsigned int num_input = Ocr::SIZE*Ocr::SIZE;
+ // One ouput for each possible char.
+ const unsigned int num_output = xFontCharMap->GetCharCount()-1;
+ // 4 layers (one input, one output and two is recommended for OCR).
+ const unsigned int num_layers = 4;
+ // Number of neurons for each layer is usually between number of input and number on output.
+ const unsigned int num_neurons_hidden = std::max(num_input, num_output);
+ const float desired_error = (const float) 0.001;
+ const unsigned int max_epochs = 500000;
+ // To see progression. It's take time...
+ const unsigned int epochs_between_reports = 1;
+
+ struct fann *ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_neurons_hidden, num_output);
+
+ // Default function. Usually works well.
+ fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
+ fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);
+
+ std::ofstream file;
+ // Write in /tmp/xor.data all database of example.
+ // TODO: MUST be replace by the memory stream.
+ file.open("/tmp/xor.data");
+
+ // First line of the file.
+ file << num_output << " " << num_input << " " << num_output << std::endl;
+ // Then, the current char :
+ // - For each pixel : -1 if blank, 1 if not blank.
+ // - For each possible char : -1 if not the current char, 1 if it is the current char.
+
+ long i = 0;
+ sal_UCS4 sChar = xFontCharMap->GetFirstChar();
+ while(sChar != xFontCharMap->GetLastChar())
{
- for (long i = 0; i < w; i++)
+ // Draw the current char.
+ VirtualDevice od;
+ OUString aOUStr( &sChar, 1 );
+ Size s50(Ocr::SIZE, Ocr::SIZE);
+ od.SetOutputSize( s50 );
+ vcl::Font aFontBis(aFont);
+ aFontBis.SetFontHeight(Ocr::SIZE);
+ od.SetFont( aFontBis );
+ od.DrawText( p, aOUStr );
+
+ w = od.GetOutputWidthPixel ();
+ h = od.GetOutputHeightPixel ();
+ Size s2(w, h);
+ Bitmap b2 = od.GetBitmap (p, s2);
+
+ BitmapReadAccess* r = b2.AcquireReadAccess ();
+
+ // Show every pixel of the current char.
+ for (long j = 0; j < h; j++)
{
- Color c = r->GetPixel(j, i);
- if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
- {
- std::cout << "1";
- }
- else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
- {
- std::cout << "0";
- }
- else
+ for (long k = 0; k < w; k++)
{
- std::cout << "2";
+ Color c = r->GetPixel(j, k);
+ if (c.GetRed () == 0 && c.GetGreen () == 0 && c.GetBlue () == 0)
+ {
+ std::cout << "1";
+ }
+ else if (c.GetRed () == 255 && c.GetGreen () == 255 && c.GetBlue () == 255)
+ {
+ std::cout << "0";
+ }
+ else
+ {
+ std::cout << "2";
+ }
}
+ std::cout << std::endl;
}
- std::cout << std::endl;
+
+ // Resize the bitmap of the current char.
+ Ocr o2(b2, w, h);
+ o2.ReadBitmap();
+ o2.CropBitmap();
+ o2.ScaleBitmap(Ocr::SIZE, Ocr::SIZE);
+ // Write the draw of the current char to the file.
+ o2.ToFile(file);
+
+ // Write that the current char is the only one good.
+ for (long j = 0; j < i; j++)
+ {
+ file << "-1 ";
+ }
+
+ file << "1 ";
+
+ for (long j = i + 1; j < num_output; j++)
+ {
+ file << "-1 ";
+ }
+ file << std::endl;
+
+ sChar = xFontCharMap->GetNextChar(sChar);
+ m_pSearchSet->AppendCharToList(sChar);
+ i++;
}
- sChar = xFontCharMap->GetNextChar(sChar);
- m_pSearchSet->AppendCharToList(sChar);
+ file.close();
+ // Creating the database of example done.
+ std::cout << "DONE" << std::endl;
+
+
+ // Training the network. Take age !!!
+ fann_train_on_file(ann, "/tmp/xor.data", max_epochs, epochs_between_reports, desired_error);
+
+ // Save the result. Huge !!!
+ fann_save(ann, "/tmp/fann.net");
+
+ fann_destroy(ann);
}
- m_pSearchSet->AppendCharToList(sChar);
+
+ fann_type *calc_out;
+ fann_type input[Ocr::SIZE*Ocr::SIZE];
+
+ std::cout << "Starting loading fann" << std::endl;
+ struct fann *ann = fann_create_from_file("/tmp/fann.net");
+
+ o.ToFann(&input[0]);
+ std::cout << "Starting finding best result" << std::endl;
+ calc_out = fann_run(ann, input);
+ std::cout << "End of fann" << std::endl;
+
+ for (long i = 0; i < 2294; i++)
+ std::cout << calc_out[i] << " ";
+
+ fann_destroy(ann);
+
+ // TODO : sort the output and write the better char at first.
+// m_pSearchSet->AppendCharToList(sChar);
m_pSearchSet->Resize();
}
@@ -1530,7 +1712,6 @@ void DrawingAreaOcr::MouseMove( const MouseEvent &rMEvt )
Invalidate();
Update();
- std::cout << static_cast<int>(state) << std::endl;
}
void DrawingAreaOcr::MouseButtonUp (const MouseEvent &rMEvt)
diff --git a/cui/source/inc/cuicharmap.hxx b/cui/source/inc/cuicharmap.hxx
index 10b7dc956c03..0e80d4002c1a 100644
--- a/cui/source/inc/cuicharmap.hxx
+++ b/cui/source/inc/cuicharmap.hxx
@@ -28,6 +28,10 @@
#include <svx/charmap.hxx>
#include <svx/searchcharmap.hxx>
#include <sfx2/charwin.hxx>
+#include <iostream>
+#include <fstream>
+
+#include <floatfann.h>
using namespace ::com::sun::star;
class SubsetMap;
@@ -47,8 +51,10 @@ public:
void ReadBitmap();
void CropBitmap();
void ScaleBitmap(long width, long height);
+ void ToFile(std::ofstream &file);
+ void ToFann(fann_type *out_data);
- static const int SIZE = 25;
+ static const int SIZE = 15;
private:
Bitmap m_bitmap;