summaryrefslogtreecommitdiff
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
parent63e2b57bb5ea4286e196b224fecc157c248d7c04 (diff)
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;