30 #ifdef CRN_USING_GDKPB
31 # include <gdk-pixbuf/gdk-pixbuf.h>
34 #ifdef CRN_USING_GDIPLUS
41 #ifdef CRN_USING_LIBPNG
45 #ifdef CRN_USING_LIBJPEG
48 struct crn_jpeg_error_mgr {
49 struct jpeg_error_mgr pub;
50 jmp_buf setjmp_buffer;
52 typedef struct crn_jpeg_error_mgr * crn_jpeg_error_ptr;
53 void crn_jpeg_error_exit(j_common_ptr cinfo);
60 #ifdef CRN_USING_LIBPNG
61 static std::pair<bool, String> save_png_libpng(
const Path &filename,
const ImageGray &img)
67 std::unique_ptr<FILE, decltype(fclose_if_not_null)*> fp(fopen(fname.CStr(),
"wb"),
fclose_if_not_null);
70 return std::make_pair(
false,
String(
_(
"Cannot create file ")) + U
"<" + fname + U
">");
74 png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
77 return std::make_pair(
false,
String(
_(
"Cannot create the PNG structure.")));
79 png_infop info_ptr = png_create_info_struct(png_ptr);
82 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
83 return std::make_pair(
false,
String(
_(
"Cannot create the PNG info.")));
87 if (setjmp(png_jmpbuf(png_ptr)))
89 png_destroy_write_struct(&png_ptr, &info_ptr);
90 return std::make_pair(
false,
String(
_(
"Error while generating the PNG image.")));
94 png_init_io(png_ptr, fp.get());
100 int color_type = PNG_COLOR_TYPE_GRAY;
101 int interlace_type = PNG_INTERLACE_NONE;
102 int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
103 int filter_method = PNG_FILTER_TYPE_DEFAULT;
104 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_method);
107 png_write_info(png_ptr, info_ptr);
108 png_bytepp row_pointers;
109 row_pointers = (png_bytep*)malloc(
sizeof(png_byte*) * height);
110 for (
int i = 0; i < height ; ++i)
112 #if (PNG_LIBPNG_VER > 10300)
113 row_pointers[i] = (png_bytep)calloc(1, png_get_rowbytes(png_ptr, info_ptr));
115 row_pointers[i] = (png_bytep)calloc(1, info_ptr->rowbytes);
121 for (
int y = 0; y < height; y++)
122 for (
int x = 0; x < width; x++)
123 row_pointers[y][x] = img.
At(x, y);
125 png_write_image(png_ptr, row_pointers);
129 txt[0].compression = PNG_TEXT_COMPRESSION_NONE;
130 txt[0].key = (
char*)
"creator";
131 txt[0].text = (
char*)
"libcrn";
132 txt[0].text_length = strlen(txt[0].text);
133 png_set_text(png_ptr, info_ptr, txt, 1);
135 png_write_end(png_ptr, info_ptr);
136 png_destroy_write_struct(&png_ptr, &info_ptr);
139 for (
int i = 0; i < height ; ++i)
141 free(row_pointers[i]);
144 return std::make_pair(
true,
String(
""));
149 #ifdef CRN_USING_GDKPB
150 static std::pair<bool, String> save_png_gdkpixbuf(
const Path &fname,
const ImageGray &img)
152 GdkPixbuf *pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
156 return std::make_pair(
false,
String(
_(
"Cannot create temporary buffer.")));
159 int w = gdk_pixbuf_get_width(pb);
160 int h = gdk_pixbuf_get_height(pb);
161 int rs = gdk_pixbuf_get_rowstride(pb);
162 guchar *ppix = gdk_pixbuf_get_pixels(pb);
163 for (
int y = 0; y < h; y++)
164 for (
int x = 0; x < w; x++)
166 const auto px = img.
At(x, y);
167 int o2 = x + x + x + y * rs;
176 utfname = g_locale_to_utf8(fname.
CStr(), -1, NULL, &i, NULL);
178 filename = g_filename_from_utf8(utfname, -1, NULL, &i, NULL);
180 gchar *tinfo = g_locale_to_utf8(
"tEXt::Source", -1, NULL, &i, NULL);
181 gchar *tinfo2 = g_locale_to_utf8(
"Saved by libcrn.", -1, NULL, &i, NULL);
182 bool ok = gdk_pixbuf_save(pb, filename,
"png", &err, tinfo, tinfo2, NULL);
190 out =
String(
_(
"Cannot save file. ")) + err->message;
193 return std::make_pair(ok, out);
197 #ifdef CRN_USING_GDIPLUS
198 static int GetEncoderClsid(
const WCHAR* format, CLSID* pClsid)
203 Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
205 Gdiplus::GetImageEncodersSize(&num, &size);
209 pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
210 if (pImageCodecInfo ==
nullptr)
213 Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);
215 for (UINT j = 0; j < num; ++j)
217 if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
219 *pClsid = pImageCodecInfo[j].Clsid;
220 free(pImageCodecInfo);
225 free(pImageCodecInfo);
229 static std::pair<bool, String> save_png_gdiplus(
const Path &filename,
const ImageGray &img)
232 Path winname(filename);
234 const auto newsize = winname.Size() + 1;
235 auto wcstring = std::vector<wchar_t>(newsize);
236 auto convertedChars = size_t(0);
237 mbstowcs_s(&convertedChars, wcstring.data(), newsize, winname.CStr(), _TRUNCATE);
239 Gdiplus::Bitmap *outbm =
new Gdiplus::Bitmap(INT(img.
GetWidth()), INT(img.
GetHeight()), PixelFormat8bppIndexed);
242 return std::make_pair(
false,
String(
_(
"Cannot create bitmap")));
244 Gdiplus::ColorPalette *pal = (Gdiplus::ColorPalette *)malloc(
sizeof(Gdiplus::ColorPalette) + 255 *
sizeof(Gdiplus::ARGB));
246 pal->Flags = Gdiplus::PaletteFlagsGrayScale;
247 for (
size_t tmp = 0; tmp < 256; ++tmp)
248 pal->Entries[tmp] = Gdiplus::ARGB(0xFF000000 | tmp | (tmp << 8) | (tmp << 16));
249 outbm->SetPalette(pal);
250 Gdiplus::BitmapData bitmapData;
251 outbm->LockBits(&Gdiplus::Rect(0, 0, outbm->GetWidth(), outbm->GetHeight()), Gdiplus::ImageLockModeWrite, PixelFormat8bppIndexed, &bitmapData);
252 auto *pixels = (uint8_t*)bitmapData.Scan0;
256 pixels[x + y * bitmapData.Stride] = img.
At(x, y);
258 outbm->UnlockBits(&bitmapData);
261 GetEncoderClsid(L
"image/png", &pngClsid);
262 Gdiplus::Status stat = outbm->Save(wcstring.data(), &pngClsid,
nullptr);
265 return std::make_pair(stat == Gdiplus::Ok,
String{});
284 std::pair<bool, String> res(std::make_pair(
false,
String(U
"")));
286 #ifdef CRN_USING_LIBPNG
287 if (res.first ==
false)
289 res = save_png_libpng(fname, img);
290 error += U
" " + res.second;
293 #ifdef CRN_USING_GDIPLUS
294 if (res.first ==
false)
296 res = save_png_gdiplus(fname, img);
297 error += U
" " + res.second;
300 #ifdef CRN_USING_GDKPB
301 if (res.first ==
false)
303 res = save_png_gdkpixbuf(fname, img);
304 error += U
" " + res.second;
307 if (res.first ==
false)
309 _(
"No library for saving image found or write permissions on the file or directory are not granted. No image will be saved.") +
"\n" +
StringUTF8(error) +
"\n" +
StringUTF8(fname));
312 #ifdef CRN_USING_LIBJPEG
313 static std::pair<bool, String> save_jpeg_libjpeg(
const Path &filename,
const ImageGray &img,
int qual)
316 Path fname(filename);
322 return std::make_pair(
false,
String(
_(
"Cannot create file ")) + U
"<" + fname + U
">");
325 crn_jpeg_error_mgr jerr;
326 struct jpeg_compress_struct cinfo;
328 cinfo.err = jpeg_std_error(&jerr.pub);
329 jerr.pub.error_exit = crn_jpeg_error_exit;
330 if (setjmp(jerr.setjmp_buffer))
332 jpeg_destroy_compress(&cinfo);
333 return std::make_pair(
false,
String(
_(
"Cannot create jpeg file structure.")));
336 jpeg_create_compress(&cinfo);
337 jpeg_stdio_dest(&cinfo, fp.get());
338 cinfo.image_width = int(img.
GetWidth());
339 cinfo.image_height = int(img.
GetHeight());
340 cinfo.input_components = 1;
341 cinfo.in_color_space = JCS_GRAYSCALE;
342 jpeg_set_defaults(&cinfo);
343 jpeg_set_quality(&cinfo, qual,
TRUE);
344 jpeg_start_compress(&cinfo,
TRUE);
345 JSAMPROW scanline =
new JSAMPLE[img.
GetWidth()];
346 for (
size_t y = 0; y < img.
GetHeight(); ++y)
348 for (
size_t x = 0; x < img.
GetWidth(); ++x)
350 scanline[x] = img.
At(x, y);
352 jpeg_write_scanlines(&cinfo, &scanline, 1);
356 jpeg_write_marker(&cinfo, JPEG_COM, (JOCTET*)
"Saved by libcrn.", (
unsigned int)strlen(
"Saved by libcrn."));
358 jpeg_finish_compress(&cinfo);
359 jpeg_destroy_compress(&cinfo);
361 return std::make_pair(
true,
String(U
""));
365 #ifdef CRN_USING_GDKPB
366 static std::pair<bool, String> save_jpeg_gdkpixbuf(
const Path &fname,
const ImageGray &img,
int qual)
368 GdkPixbuf *pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
372 return std::make_pair(
false,
String(
_(
"Cannot create temporary buffer.")));
374 int w = gdk_pixbuf_get_width(pb);
375 int h = gdk_pixbuf_get_height(pb);
376 int rs = gdk_pixbuf_get_rowstride(pb);
377 guchar *ppix = gdk_pixbuf_get_pixels(pb);
378 for (
int y = 0; y < h; y++)
379 for (
int x = 0; x < w; x++)
381 auto px = img.
At(x, y);
382 int o2 = x + x + x + y * rs;
391 utfname = g_locale_to_utf8(fname.
CStr(), -1, NULL, &i, NULL);
393 filename = g_filename_from_utf8(utfname, -1, NULL, &i, NULL);
395 gchar *tinfo = g_locale_to_utf8(
"quality", -1, NULL, &i, NULL);
397 sprintf(qt,
"%i", qual);
398 gchar *tinfo2 = g_locale_to_utf8(qt, -1, NULL, &i, NULL);
399 bool ok = gdk_pixbuf_save(pb, filename,
"jpeg", &err, tinfo, tinfo2, NULL);
407 res =
String(
_(
"Cannot save file. ")) + err->message;
410 return std::make_pair(ok, res);
414 #ifdef CRN_USING_GDIPLUS
415 static std::pair<bool, String> save_jpeg_gdiplus(
const Path &filename,
const ImageGray &img,
int qual)
418 Path winname(filename);
420 const auto newsize = winname.Size() + 1;
421 auto wcstring = std::vector<wchar_t>(newsize);
422 auto convertedChars = size_t(0);
423 mbstowcs_s(&convertedChars, wcstring.data(), newsize, winname.CStr(), _TRUNCATE);
425 Gdiplus::Bitmap *outbm =
new Gdiplus::Bitmap(INT(img.
GetWidth()), INT(img.
GetHeight()), PixelFormat24bppRGB);
428 return std::make_pair(
false,
String(
_(
"Cannot create bitmap")));
430 Gdiplus::BitmapData bitmapData;
431 auto clip = Gdiplus::Rect(0, 0, outbm->GetWidth(), outbm->GetHeight());
432 outbm->LockBits(&clip, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData);
433 auto *pixels = (uint8_t*)bitmapData.Scan0;
437 size_t poffset = 3 * x + y * bitmapData.Stride;
438 const auto pix = img.
At(x, y);
439 pixels[poffset + 2] = pix;
440 pixels[poffset + 1] = pix;
441 pixels[poffset] = pix;
443 outbm->UnlockBits(&bitmapData);
445 GetEncoderClsid(L
"image/jpeg", &jpegClsid);
446 Gdiplus::EncoderParameters encoderParameters;
447 encoderParameters.Count = 1;
448 encoderParameters.Parameter[0].Guid = Gdiplus::EncoderQuality;
449 encoderParameters.Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
450 encoderParameters.Parameter[0].NumberOfValues = 1;
451 ULONG quality = qual;
452 encoderParameters.Parameter[0].Value = &quality;
453 outbm->Save(wcstring.data(), &jpegClsid, &encoderParameters);
455 return std::make_pair(
true,
String{});
472 _(
"Null file name."));
476 std::pair<bool, String> res(std::make_pair(
false,
String(U
"")));
478 #ifdef CRN_USING_LIBJPEG
479 if (res.first ==
false)
481 res = save_jpeg_libjpeg(fname, img, qual);
482 error += U
" " + res.second;
485 #ifdef CRN_USING_GDIPLUS
486 if (res.first ==
false)
488 res = save_jpeg_gdiplus(fname, img, qual);
489 error += U
" " + res.second;
492 #ifdef CRN_USING_GDKPB
493 if (res.first ==
false)
495 res = save_jpeg_gdkpixbuf(fname, img, qual);
496 error += U
" " + res.second;
499 if (res.first ==
false)
501 _(
"No library for saving image found or write permissions on the file or directory are not granted. No image will be saved.") +
StringUTF8(error));
518 int pb = 0, pw = 255;
519 int ppb = 0, ppw = 255;
523 unsigned int cumb = 0, cumw = 0;
524 size_t nbb = 0, nbw = 0;
525 for (
int val = 0; val < int(h.Size()); ++val)
527 int db =
Abs(pb - val);
528 int dw =
Abs(pw - val);
531 cumb += val * h.GetBin(val);
532 nbb += h.GetBin(val);
536 cumw += val * h.GetBin(val);
537 nbw += h.GetBin(val);
543 pb = cumb / int(nbb);
545 pw = cumw / int(nbw);
546 }
while ((ppb != pb) || (ppw != pw));
550 for (
auto tmp :
Range(img))
552 if (img.
At(tmp) < pb)
554 else if (img.
At(tmp) > pw)
558 img.
At(tmp) = uint8_t(((img.
At(tmp) - pb) * 255) / diff);
570 for (
size_t y = 0; y < img.
GetHeight(); y++)
572 unsigned int cnt = 0;
573 for (
size_t x = 0; x < img.
GetWidth(); x++)
575 h.SetBin(y, cnt / 255);
586 for (
size_t x = 0; x < img.
GetWidth(); x++)
588 unsigned int cnt = 0;
589 for (
size_t y = 0; y < img.
GetHeight(); y++)
591 h.SetBin(x, cnt / 255);
622 for (
size_t tx = x * xdiv; tx <
Min(img.
GetWidth(), (x + 1) * xdiv); ++tx)
624 if (img.
At(tx, y) < minv)
625 minv = img.
At(tx, y);
636 for (
size_t x = 0; x < ibw.GetWidth(); ++x)
645 if (y >= ibw.GetHeight())
654 while (!ibw.At(x, y))
657 if (y >= ibw.GetHeight())
663 h.IncBin(
Min(
size_t(249), y - by));
666 h.AverageSmoothing(2);
667 return int(
Max(
size_t(floor(h.Mean())), h.Argmax()));
678 for (
auto tmp :
Range(ly))
679 ly.At(tmp) = img.
At(tmp);
687 for (
auto tmp :
Range(ly))
695 for (
size_t x = 0; x < img.
GetWidth(); ++x)
697 bool w = bl.At(x, 0);
699 for (
size_t y = 1; y < img.
GetHeight(); ++y)
712 histo.IncBin(y - by);
719 return histo.MedianValue();
738 for (
size_t tx = x * div; tx <
Min(img.
GetWidth(), (x + 1) * div); ++tx)
740 if (img.
At(tx, y) < minv)
741 minv = img.
At(tx, y);
746 auto ibw = std::make_shared<ImageBW>(
Fisher(ig));
754 auto mask = lb->ExtractCC(U
"cc");
755 lb->FilterMinOr(U
"cc", 3, 3);
757 for (
auto cco : lb->GetTree(U
"cc"))
759 auto cc = std::static_pointer_cast<
Block>(cco);
761 auto val = cc->GetName().ToInt();
762 auto maxval = int(
Min(bbox.GetWidth(), bbox.GetHeight()));
763 Point2DInt topleft, topright, bottomleft, bottomright;
764 bool tl =
false, tr =
false, bl =
false, br =
false;
765 for (
int tmp = 1; tmp < maxval; ++tmp)
767 for (
int off = 0; off <= tmp; ++off)
770 if (mask->At(bbox.GetLeft() + off, bbox.GetTop() + tmp - off) == val)
772 topleft.
X = bbox.GetLeft() + off;
773 topleft.
Y = bbox.GetTop() + tmp - off;
777 if (mask->At(bbox.GetRight() - off, bbox.GetTop() + tmp - off) == val)
779 topright.
X = bbox.GetRight() - off;
780 topright.
Y = bbox.GetTop() + tmp - off;
784 if (mask->At(bbox.GetLeft() + off, bbox.GetBottom() - tmp + off) == val)
786 bottomleft.
X = bbox.GetLeft() + off;
787 bottomleft.
Y = bbox.GetBottom() - tmp + off;
791 if (mask->At(bbox.GetRight() - off, bbox.GetBottom() - tmp + off) == val)
793 bottomright.
X = bbox.GetRight() - off;
794 bottomright.
Y = bbox.GetBottom() - tmp + off;
798 if (tl && tr && bl && br)
803 U += long(div) * (topright.
X - topleft.
X);
804 V += topright.
Y - topleft.
Y;
808 U += long(div) * (bottomright.
X - bottomleft.
X);
809 V += bottomright.
Y - bottomleft.
Y;
820 UserData.
Set(U
"threshold", std::make_shared<Int>(t));
825 return Threshold(img, uint8_t(*std::static_pointer_cast<Int>(
UserData[U
"threshold"])));
834 UserData.
Set(U
"halfwin", std::make_shared<Int>(
int(halfwin)));
840 return Niblack(img, *std::static_pointer_cast<Int>(
UserData[U
"halfwin"]),
841 *std::static_pointer_cast<Real>(
UserData[U
"k"]));
850 UserData.
Set(U
"halfwin", std::make_shared<Int>(
int(halfwin)));
856 return Sauvola(img, *std::static_pointer_cast<Int>(
UserData[U
"halfwin"]),
857 *std::static_pointer_cast<Real>(
UserData[U
"k"]));
866 UserData.
Set(U
"classes", std::make_shared<Int>(
int(classes)));
867 UserData.
Set(U
"black_classes", std::make_shared<Int>(
int(black_classes)));
873 *std::static_pointer_cast<Int>(
UserData[U
"black_classes"]));
881 UserData.
Set(U
"area", std::make_shared<Int>(
int(area)));
894 UserData.
Set(U
"area", std::make_shared<Int>(
int(area)));
940 act = std::make_shared<Gray2BWFisher>();
943 return act->Binarize(img);
static MatrixDouble NewGaussianLineDerivative(double sigma)
Creates a line matrix with the derivative of a centered Gaussian.
void AutoContrast(ImageGray &img)
ImageBW Sauvola(const Image< T > &img, size_t halfwin, double k=0.5, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
ImageBW Entropy(const Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
ScalarRange< T > Range(T b, T e)
Creates a range [[b, e[[.
ImageBW Fisher(const Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
ImageBW MakeImageBW(const ImageGray &img)
Gray2BWNiblack(size_t halfwin=3, double k=0.5)
Default constructor.
void fclose_if_not_null(FILE *f)
Image< int > ImageIntGray
Int grayscale image class.
Fisher binarization action.
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
std::vector< pixel_type >::reference At(size_t x, size_t y) noexcept
Returns a reference to a pixel.
size_t GetHeight() const noexcept
Image< uint8_t > ImageGray
Grayscale image class.
static MatrixDouble NewGaussianLine(double sigma)
Creates a line matrix with a centered Gaussian.
const T & Max(const T &a, const T &b)
Returns the max of two values.
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
void Set(const String &key, SObject value)
Sets a value for a key with constraints check.
Gray2BWFisher()
Default constructor.
Niblack binarization action.
void SavePNG(const ImageBW &img, const Path &fname)
Saves as PNG file.
Otsu binarization action.
Gray2BWkMeansHisto(size_t classes=5, size_t black_classes=3)
Default constructor.
ImageBW kMeansHisto(const Image< T > &img, size_t classes, size_t black_classes, size_t maxcnt=10000, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
#define CRN_END_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
#define FOREACHPIXEL(x, y, img)
Convenience macro to sweep an image.
A convenience class for angles units.
void Sqrt(ImageDoubleGray &img) noexcept
Replaces the pixels with their square root.
static std::mutex & GetMutex(const Path &fname)
Gets the mutex associated to a file.
A UTF32 character string class.
ImageBW LocalMin(const Image< T > &img, size_t area=1, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
size_t EstimateLeading(const ImageGray &img)
Computes the median distance between two baselines.
ImageBW Niblack(const Image< T > &img, size_t halfwin, double k=0.5, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
static SBlock New(const SImage &src, const String &nam=U"")
Top block creator.
static SAction GetAction(const String &name)
Gets a default action.
const char * CStr() const noexcept
Conversion to UTF8 cstring.
const Rect & GetAbsoluteBBox() const noexcept
Gets the absolute bounding box of the block.
A convenience class for file paths.
#define CRN_DATA_FACTORY_REGISTER(elemname, classname)
Registers a class to the data factory.
ImageBW Otsu(const Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
Threshold binarization action.
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
Gray2BWOtsu()
Default constructor.
ImageBW Threshold(const Image< T > &img, T thresh, CMP cmp=std::less< T >{})
Gray2BWLocalMax(size_t area=1)
Default constructor.
void Abs(Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr) noexcept
Replaces each pixel by its absolute value.
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
const T & Min(const T &a, const T &b)
Returns the min of two values.
size_t EstimateLinesXHeight(const ImageGray &img, unsigned int xdiv=16)
Computes the mean text line x-height.
Mother class for integer histograms.
Entropy binarization action.
Local max binarization action.
Gray2BWLocalMin(size_t area=1)
Default constructor.
ImageBW LocalMax(const Image< T > &img, size_t area=1, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
void SaveJPEG(const ImageBW &img, const Path &fname, unsigned int qual)
Saves as JPEG file.
size_t GetWidth() const noexcept
Path & ToLocal()
Converts the path to the local format.
Angle< Radian > EstimateSkew(const ImageGray &img)
Estimates the mean skew of the document's lines.
size_t StrokesWidth(const Image< T > &img, size_t maxval=50, size_t defaultval=0, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
Histogram HorizontalProjection(const ImageBW &img)
Computes the horizontal projection.
A character string class.
Sauvola binarization action.
k-means histo binarization action
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
Histogram MakeHistogram(const Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr)
Gray2BWSauvola(size_t halfwin=3, double k=0.5)
Default constructor.
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
virtual ImageBW Binarize(const ImageGray &img) override
Action = binarize a gray image.
Histogram VerticalProjection(const ImageBW &img)
Computes the vertical projection.
static void SetAction(const String &name, SAction action)
Sets a default action.
Invalid argument error (e.g.: nullptr pointer)
#define CRN_BEGIN_CLASS_CONSTRUCTOR(classname)
Defines a class constructor.
Local min binarization action.
Gray2BWThreshold(uint8_t t=127)
Default constructor.
Gray2BWEntropy()
Default constructor.
static Angle Atan(double tangent) noexcept(std::is_nothrow_constructible< typename Unit::type >::value)
Computes arc tangent.