Leptonica: learn to despeckle 1bpp images

This commit is contained in:
James R. Barlow
2018-11-07 01:49:13 -08:00
parent 806daf4284
commit 58b26f6715
3 changed files with 110 additions and 6 deletions
+62 -1
View File
@@ -143,7 +143,7 @@ class LeptonicaObject:
def __init__(self, cdata):
if not cdata:
raise ValueError('NULL cdata object')
raise ValueError('Tried to wrap a NULL ' + self.LEPTONICA_TYPENAME)
self._cdata = ffi.gc(cdata, self._destroy)
@classmethod
@@ -570,6 +570,35 @@ class Pix(LeptonicaObject):
right, bottom = box.x + box.w, box.y + box.h
yield (decoded, (left, top, right, bottom))
def despeckle(self, size):
if size == 2:
speckle2 = """
oooo
oC o
o o
oooo
"""
sel1 = Sel.from_selstr(speckle2, 'speckle2')
sel2 = Sel.create_brick(2, 2, 0, 0, lept.SEL_HIT)
elif size == 3:
speckle3 = """
ooooo
oC o
o o
o o
ooooo
"""
sel1 = Sel.from_selstr(speckle3, 'speckle3')
sel2 = Sel.create_brick(3, 3, 0, 0, lept.SEL_HIT)
else:
raise ValueError(size)
pixhmt = Pix(lept.pixHMT(ffi.NULL, self._cdata, sel1._cdata))
pixdilated = Pix(lept.pixDilate(ffi.NULL, pixhmt._cdata, sel2._cdata))
pixsub = Pix(lept.pixSubtract(ffi.NULL, self._cdata, pixdilated._cdata))
return pixsub
class CompressedData(LeptonicaObject):
"""Wrapper for L_COMP_DATA - abstract compressed image data"""
@@ -682,6 +711,7 @@ class BoxArray(LeptonicaObject, Sequence):
class StringArray(LeptonicaObject, Sequence):
"""Leptonica SARRAY/string array"""
LEPTONICA_TYPENAME = 'SARRAY'
cdata_destroy = lept.sarrayDestroy
@@ -695,6 +725,37 @@ class StringArray(LeptonicaObject, Sequence):
raise IndexError(n)
class Sel(LeptonicaObject):
"""Leptonica 'sel'/selection element for hit-miss transform"""
LEPTONICA_TYPENAME = 'SEL'
cdata_destroy = lept.selDestroy
@classmethod
def from_selstr(cls, selstr, name):
lines = [line.strip() for line in selstr.split('\n') if line.strip()]
h = len(lines)
w = len(lines[0])
lengths = set(len(line) for line in lines)
if len(lengths) != 1:
raise ValueError("All lines in selstr must be same length")
repacked = ''.join(line.strip() for line in lines)
buf_selstr = ffi.from_buffer(repacked.encode('ascii'))
buf_name = ffi.from_buffer(name.encode('ascii'))
sel = lept.selCreateFromString(buf_selstr, h, w, buf_name)
return cls(sel)
@classmethod
def create_brick(cls, h, w, cy, cx, type_):
sel = lept.selCreateBrick(h, w, cy, cx, type_)
return cls(sel)
def __repr__(self):
selstr = ffi.gc(lept.selPrintToString(self._cdata), lept.lept_free)
return '<Sel \n' + ffi.string(selstr).decode('ascii') + '\n>'
@lru_cache(maxsize=1)
def get_leptonica_version():
"""Get Leptonica version string.
File diff suppressed because one or more lines are too long
+43
View File
@@ -135,6 +135,18 @@ struct L_Compressed_Data
};
typedef struct L_Compressed_Data L_COMP_DATA;
/*! Selection */
struct Sel
{
l_int32 sy; /*!< sel height */
l_int32 sx; /*!< sel width */
l_int32 cy; /*!< y location of sel origin */
l_int32 cx; /*!< x location of sel origin */
l_int32 **data; /*!< {0,1,2}; data[i][j] in [row][col] order */
char *name; /*!< used to find sel by name */
};
typedef struct Sel SEL;
enum {
REMOVE_CMAP_TO_BINARY = 0, /*!< remove colormap for conv to 1 bpp */
REMOVE_CMAP_TO_GRAYSCALE = 1, /*!< remove colormap for conv to 8 bpp */
@@ -184,6 +196,12 @@ enum {
L_SEVERITY_NONE = 6 /* Highest severity: print no messages */
};
enum {
SEL_DONT_CARE = 0,
SEL_HIT = 1,
SEL_MISS = 2
};
""")
ffibuilder.cdef("""
@@ -407,12 +425,34 @@ l_generateCIDataForPdf(const char *fname,
l_int32 quality,
L_COMP_DATA **pcid);
BOX *
boxClone ( BOX *box );
BOX *
boxaGetBox ( BOXA *boxa, l_int32 index, l_int32 accessflag );
SEL *
selCreateFromString ( const char *text, l_int32 h, l_int32 w, const char *name );
SEL *
selCreateBrick ( l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, l_int32 type );
char *
selPrintToString(SEL *sel);
PIX *
pixDilate ( PIX *pixd, PIX *pixs, SEL *sel );
PIX *
pixErode ( PIX *pixd, PIX *pixs, SEL *sel );
PIX *
pixHMT ( PIX *pixd, PIX *pixs, SEL *sel );
PIX *
pixSubtract ( PIX *pixd, PIX *pixs1, PIX *pixs2 );
void
boxDestroy(BOX **pbox);
@@ -434,8 +474,11 @@ sarrayDestroy(SARRAY **psa);
void
lept_free(void *ptr);
void selDestroy ( SEL **psel );
l_int32
setMsgSeverity(l_int32 newsev);
""")