mirror of http://192.168.1.51:8099/lmh188/twain3.0
875 lines
33 KiB
C
875 lines
33 KiB
C
|
/*====================================================================*
|
||
|
- Copyright (C) 2001 Leptonica. All rights reserved.
|
||
|
-
|
||
|
- Redistribution and use in source and binary forms, with or without
|
||
|
- modification, are permitted provided that the following conditions
|
||
|
- are met:
|
||
|
- 1. Redistributions of source code must retain the above copyright
|
||
|
- notice, this list of conditions and the following disclaimer.
|
||
|
- 2. Redistributions in binary form must reproduce the above
|
||
|
- copyright notice, this list of conditions and the following
|
||
|
- disclaimer in the documentation and/or other materials
|
||
|
- provided with the distribution.
|
||
|
-
|
||
|
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
|
||
|
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||
|
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
|
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||
|
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||
|
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
|
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*====================================================================*/
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \file fmorphauto.c
|
||
|
* <pre>
|
||
|
*
|
||
|
* Main function calls:
|
||
|
* l_int32 fmorphautogen()
|
||
|
* l_int32 fmorphautogen1()
|
||
|
* l_int32 fmorphautogen2()
|
||
|
*
|
||
|
* Static helpers:
|
||
|
* static SARRAY *sarrayMakeWplsCode()
|
||
|
* static SARRAY *sarrayMakeInnerLoopDWACode()
|
||
|
* static char *makeBarrelshiftString()
|
||
|
*
|
||
|
*
|
||
|
* This automatically generates dwa code for erosion and dilation.
|
||
|
* Here's a road map for how it all works.
|
||
|
*
|
||
|
* (1) You generate an array (a SELA) of structuring elements (SELs).
|
||
|
* This can be done in several ways, including
|
||
|
* (a) calling the function selaAddBasic() for
|
||
|
* pre-compiled SELs
|
||
|
* (b) generating the SELA in code in line
|
||
|
* (c) reading in a SELA from file, using selaRead() or
|
||
|
* various other formats.
|
||
|
*
|
||
|
* (2) You call fmorphautogen1() and fmorphautogen2() on this SELA.
|
||
|
* These use the text files morphtemplate1.txt and
|
||
|
* morphtemplate2.txt for building up the source code. See the file
|
||
|
* prog/fmorphautogen.c for an example of how this is done.
|
||
|
* The output is written to files named fmorphgen.*.c
|
||
|
* and fmorphgenlow.*.c, where "*" is an integer that you
|
||
|
* input to this function. That integer labels both
|
||
|
* the output files, as well as all the functions that
|
||
|
* are generated. That way, using different integers,
|
||
|
* you can invoke fmorphautogen() any number of times
|
||
|
* to get functions that all have different names so that
|
||
|
* they can be linked into one program.
|
||
|
*
|
||
|
* (3) You copy the generated source files back to your src
|
||
|
* directory for compilation. Put their names in the
|
||
|
* Makefile, regenerate the prototypes, and recompile
|
||
|
* the library. Look at the Makefile to see how I've
|
||
|
* included morphgen.1.c and fmorphgenlow.1.c. These files
|
||
|
* provide the high-level interfaces for erosion, dilation,
|
||
|
* opening and closing, and the low-level interfaces to
|
||
|
* do the actual work, for all 58 SELs in the SEL array.
|
||
|
*
|
||
|
* (4) In an application, you now use this interface. Again
|
||
|
* for the example files in the library, using integer "1":
|
||
|
*
|
||
|
* PIX *pixMorphDwa_1(PIX *pixd, PIX, *pixs,
|
||
|
* l_int32 operation, char *selname);
|
||
|
*
|
||
|
* or
|
||
|
*
|
||
|
* PIX *pixFMorphopGen_1(PIX *pixd, PIX *pixs,
|
||
|
* l_int32 operation, char *selname);
|
||
|
*
|
||
|
* where the operation is one of {L_MORPH_DILATE, L_MORPH_ERODE.
|
||
|
* L_MORPH_OPEN, L_MORPH_CLOSE}, and the selname is one
|
||
|
* of the set that were defined as the name field of sels.
|
||
|
* This set is listed at the beginning of the file fmorphgen.1.c.
|
||
|
* For examples of use, see the file prog/binmorph_reg1.c, which
|
||
|
* verifies the consistency of the various implementations by
|
||
|
* comparing the dwa result with that of full-image rasterops.
|
||
|
* </pre>
|
||
|
*/
|
||
|
|
||
|
#include <string.h>
|
||
|
#include "allheaders.h"
|
||
|
|
||
|
#define OUTROOT "fmorphgen"
|
||
|
#define TEMPLATE1 "morphtemplate1.txt"
|
||
|
#define TEMPLATE2 "morphtemplate2.txt"
|
||
|
|
||
|
#define PROTOARGS "(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, l_int32);"
|
||
|
|
||
|
//static const l_int32 L_BUF_SIZE = 512;
|
||
|
#define L_BUF_SIZE 512
|
||
|
|
||
|
static char * makeBarrelshiftString(l_int32 delx, l_int32 dely);
|
||
|
static SARRAY * sarrayMakeInnerLoopDWACode(SEL *sel, l_int32 index);
|
||
|
static SARRAY * sarrayMakeWplsCode(SEL *sel);
|
||
|
|
||
|
static char wpldecls[][53] = {
|
||
|
"l_int32 wpls2;",
|
||
|
"l_int32 wpls2, wpls3;",
|
||
|
"l_int32 wpls2, wpls3, wpls4;",
|
||
|
"l_int32 wpls5;",
|
||
|
"l_int32 wpls5, wpls6;",
|
||
|
"l_int32 wpls5, wpls6, wpls7;",
|
||
|
"l_int32 wpls5, wpls6, wpls7, wpls8;",
|
||
|
"l_int32 wpls9;",
|
||
|
"l_int32 wpls9, wpls10;",
|
||
|
"l_int32 wpls9, wpls10, wpls11;",
|
||
|
"l_int32 wpls9, wpls10, wpls11, wpls12;",
|
||
|
"l_int32 wpls13;",
|
||
|
"l_int32 wpls13, wpls14;",
|
||
|
"l_int32 wpls13, wpls14, wpls15;",
|
||
|
"l_int32 wpls13, wpls14, wpls15, wpls16;",
|
||
|
"l_int32 wpls17;",
|
||
|
"l_int32 wpls17, wpls18;",
|
||
|
"l_int32 wpls17, wpls18, wpls19;",
|
||
|
"l_int32 wpls17, wpls18, wpls19, wpls20;",
|
||
|
"l_int32 wpls21;",
|
||
|
"l_int32 wpls21, wpls22;",
|
||
|
"l_int32 wpls21, wpls22, wpls23;",
|
||
|
"l_int32 wpls21, wpls22, wpls23, wpls24;",
|
||
|
"l_int32 wpls25;",
|
||
|
"l_int32 wpls25, wpls26;",
|
||
|
"l_int32 wpls25, wpls26, wpls27;",
|
||
|
"l_int32 wpls25, wpls26, wpls27, wpls28;",
|
||
|
"l_int32 wpls29;",
|
||
|
"l_int32 wpls29, wpls30;",
|
||
|
"l_int32 wpls29, wpls30, wpls31;"};
|
||
|
|
||
|
static char wplgendecls[][30] = {
|
||
|
"l_int32 wpls2;",
|
||
|
"l_int32 wpls3;",
|
||
|
"l_int32 wpls4;",
|
||
|
"l_int32 wpls5;",
|
||
|
"l_int32 wpls6;",
|
||
|
"l_int32 wpls7;",
|
||
|
"l_int32 wpls8;",
|
||
|
"l_int32 wpls9;",
|
||
|
"l_int32 wpls10;",
|
||
|
"l_int32 wpls11;",
|
||
|
"l_int32 wpls12;",
|
||
|
"l_int32 wpls13;",
|
||
|
"l_int32 wpls14;",
|
||
|
"l_int32 wpls15;",
|
||
|
"l_int32 wpls16;",
|
||
|
"l_int32 wpls17;",
|
||
|
"l_int32 wpls18;",
|
||
|
"l_int32 wpls19;",
|
||
|
"l_int32 wpls20;",
|
||
|
"l_int32 wpls21;",
|
||
|
"l_int32 wpls22;",
|
||
|
"l_int32 wpls23;",
|
||
|
"l_int32 wpls24;",
|
||
|
"l_int32 wpls25;",
|
||
|
"l_int32 wpls26;",
|
||
|
"l_int32 wpls27;",
|
||
|
"l_int32 wpls28;",
|
||
|
"l_int32 wpls29;",
|
||
|
"l_int32 wpls30;",
|
||
|
"l_int32 wpls31;"};
|
||
|
|
||
|
static char wpldefs[][25] = {
|
||
|
" wpls2 = 2 * wpls;",
|
||
|
" wpls3 = 3 * wpls;",
|
||
|
" wpls4 = 4 * wpls;",
|
||
|
" wpls5 = 5 * wpls;",
|
||
|
" wpls6 = 6 * wpls;",
|
||
|
" wpls7 = 7 * wpls;",
|
||
|
" wpls8 = 8 * wpls;",
|
||
|
" wpls9 = 9 * wpls;",
|
||
|
" wpls10 = 10 * wpls;",
|
||
|
" wpls11 = 11 * wpls;",
|
||
|
" wpls12 = 12 * wpls;",
|
||
|
" wpls13 = 13 * wpls;",
|
||
|
" wpls14 = 14 * wpls;",
|
||
|
" wpls15 = 15 * wpls;",
|
||
|
" wpls16 = 16 * wpls;",
|
||
|
" wpls17 = 17 * wpls;",
|
||
|
" wpls18 = 18 * wpls;",
|
||
|
" wpls19 = 19 * wpls;",
|
||
|
" wpls20 = 20 * wpls;",
|
||
|
" wpls21 = 21 * wpls;",
|
||
|
" wpls22 = 22 * wpls;",
|
||
|
" wpls23 = 23 * wpls;",
|
||
|
" wpls24 = 24 * wpls;",
|
||
|
" wpls25 = 25 * wpls;",
|
||
|
" wpls26 = 26 * wpls;",
|
||
|
" wpls27 = 27 * wpls;",
|
||
|
" wpls28 = 28 * wpls;",
|
||
|
" wpls29 = 29 * wpls;",
|
||
|
" wpls30 = 30 * wpls;",
|
||
|
" wpls31 = 31 * wpls;"};
|
||
|
|
||
|
static char wplstrp[][10] = {"+ wpls", "+ wpls2", "+ wpls3", "+ wpls4",
|
||
|
"+ wpls5", "+ wpls6", "+ wpls7", "+ wpls8",
|
||
|
"+ wpls9", "+ wpls10", "+ wpls11", "+ wpls12",
|
||
|
"+ wpls13", "+ wpls14", "+ wpls15", "+ wpls16",
|
||
|
"+ wpls17", "+ wpls18", "+ wpls19", "+ wpls20",
|
||
|
"+ wpls21", "+ wpls22", "+ wpls23", "+ wpls24",
|
||
|
"+ wpls25", "+ wpls26", "+ wpls27", "+ wpls28",
|
||
|
"+ wpls29", "+ wpls30", "+ wpls31"};
|
||
|
|
||
|
static char wplstrm[][10] = {"- wpls", "- wpls2", "- wpls3", "- wpls4",
|
||
|
"- wpls5", "- wpls6", "- wpls7", "- wpls8",
|
||
|
"- wpls9", "- wpls10", "- wpls11", "- wpls12",
|
||
|
"- wpls13", "- wpls14", "- wpls15", "- wpls16",
|
||
|
"- wpls17", "- wpls18", "- wpls19", "- wpls20",
|
||
|
"- wpls21", "- wpls22", "- wpls23", "- wpls24",
|
||
|
"- wpls25", "- wpls26", "- wpls27", "- wpls28",
|
||
|
"- wpls29", "- wpls30", "- wpls31"};
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fmorphautogen()
|
||
|
*
|
||
|
* \param[in] sela
|
||
|
* \param[in] fileindex
|
||
|
* \param[in] filename [optional]; can be null
|
||
|
* \return 0 if OK; 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This function generates all the code for implementing
|
||
|
* dwa morphological operations using all the sels in the sela.
|
||
|
* (2) See fmorphautogen1() and fmorphautogen2() for details.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
fmorphautogen(SELA *sela,
|
||
|
l_int32 fileindex,
|
||
|
const char *filename)
|
||
|
{
|
||
|
l_int32 ret1, ret2;
|
||
|
|
||
|
PROCNAME("fmorphautogen");
|
||
|
|
||
|
if (!sela)
|
||
|
return ERROR_INT("sela not defined", procName, 1);
|
||
|
ret1 = fmorphautogen1(sela, fileindex, filename);
|
||
|
ret2 = fmorphautogen2(sela, fileindex, filename);
|
||
|
if (ret1 || ret2)
|
||
|
return ERROR_INT("code generation problem", procName, 1);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief fmorphautogen1()
|
||
|
*
|
||
|
* \param[in] sela
|
||
|
* \param[in] fileindex
|
||
|
* \param[in] filename [optional]; can be null
|
||
|
* \return 0 if OK; 1 on error
|
||
|
*
|
||
|
* <pre>
|
||
|
* Notes:
|
||
|
* (1) This function uses morphtemplate1.txt to create a
|
||
|
* top-level file that contains two functions. These
|
||
|
* functions will carry out dilation, erosion,
|
||
|
* opening or closing for any of the sels in the input sela.
|
||
|
* (2) The fileindex parameter is inserted into the output
|
||
|
* filename, as described below.
|
||
|
* (3) If filename == NULL, the output file is fmorphgen.[n].c,
|
||
|
* where [n] is equal to the %fileindex parameter.
|
||
|
* (4) If filename != NULL, the output file is [%filename].[n].c.
|
||
|
* </pre>
|
||
|
*/
|
||
|
l_ok
|
||
|
fmorphautogen1(SELA *sela,
|
||
|
l_int32 fileindex,
|
||
|
const char *filename)
|
||
|
{
|
||
|
char *filestr;
|
||
|
char *str_proto1, *str_proto2, *str_proto3;
|
||
|
char *str_doc1, *str_doc2, *str_doc3, *str_doc4;
|
||
|
char *str_def1, *str_def2, *str_proc1, *str_proc2;
|
||
|
char *str_dwa1, *str_low_dt, *str_low_ds, *str_low_ts;
|
||
|
char *str_low_tsp1, *str_low_dtp1;
|
||
|
char bigbuf[L_BUF_SIZE];
|
||
|
l_int32 i, nsels, nbytes, actstart, end, newstart;
|
||
|
size_t size;
|
||
|
SARRAY *sa1, *sa2, *sa3;
|
||
|
|
||
|
PROCNAME("fmorphautogen1");
|
||
|
|
||
|
if (!sela)
|
||
|
return ERROR_INT("sela not defined", procName, 1);
|
||
|
if (fileindex < 0)
|
||
|
fileindex = 0;
|
||
|
if ((nsels = selaGetCount(sela)) == 0)
|
||
|
return ERROR_INT("no sels in sela", procName, 1);
|
||
|
|
||
|
/* Make array of textlines from morphtemplate1.txt */
|
||
|
if ((filestr = (char *)l_binaryRead(TEMPLATE1, &size)) == NULL)
|
||
|
return ERROR_INT("filestr not made", procName, 1);
|
||
|
sa2 = sarrayCreateLinesFromString(filestr, 1);
|
||
|
LEPT_FREE(filestr);
|
||
|
if (!sa2)
|
||
|
return ERROR_INT("sa2 not made", procName, 1);
|
||
|
|
||
|
/* Make array of sel names */
|
||
|
sa1 = selaGetSelnames(sela);
|
||
|
|
||
|
/* Make strings containing function call names */
|
||
|
sprintf(bigbuf, "PIX *pixMorphDwa_%d(PIX *pixd, PIX *pixs, "
|
||
|
"l_int32 operation, char *selname);", fileindex);
|
||
|
str_proto1 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, "PIX *pixFMorphopGen_%d(PIX *pixd, PIX *pixs, "
|
||
|
"l_int32 operation, char *selname);", fileindex);
|
||
|
str_proto2 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, "l_int32 fmorphopgen_low_%d(l_uint32 *datad, l_int32 w,\n"
|
||
|
" l_int32 h, l_int32 wpld,\n"
|
||
|
" l_uint32 *datas, l_int32 wpls,\n"
|
||
|
" l_int32 index);", fileindex);
|
||
|
str_proto3 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " * PIX *pixMorphDwa_%d()", fileindex);
|
||
|
str_doc1 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " * PIX *pixFMorphopGen_%d()", fileindex);
|
||
|
str_doc2 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " * \\brief pixMorphDwa_%d()", fileindex);
|
||
|
str_doc3 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " * \\brief pixFMorphopGen_%d()", fileindex);
|
||
|
str_doc4 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, "pixMorphDwa_%d(PIX *pixd,", fileindex);
|
||
|
str_def1 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, "pixFMorphopGen_%d(PIX *pixd,", fileindex);
|
||
|
str_def2 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " PROCNAME(\"pixMorphDwa_%d\");", fileindex);
|
||
|
str_proc1 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " PROCNAME(\"pixFMorphopGen_%d\");", fileindex);
|
||
|
str_proc2 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf,
|
||
|
" pixt2 = pixFMorphopGen_%d(NULL, pixt1, operation, selname);",
|
||
|
fileindex);
|
||
|
str_dwa1 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf,
|
||
|
" fmorphopgen_low_%d(datad, w, h, wpld, datat, wpls, index);",
|
||
|
fileindex);
|
||
|
str_low_dt = stringNew(bigbuf);
|
||
|
sprintf(bigbuf,
|
||
|
" fmorphopgen_low_%d(datad, w, h, wpld, datas, wpls, index);",
|
||
|
fileindex);
|
||
|
str_low_ds = stringNew(bigbuf);
|
||
|
sprintf(bigbuf,
|
||
|
" fmorphopgen_low_%d(datat, w, h, wpls, datas, wpls, index+1);",
|
||
|
fileindex);
|
||
|
str_low_tsp1 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf,
|
||
|
" fmorphopgen_low_%d(datat, w, h, wpls, datas, wpls, index);",
|
||
|
fileindex);
|
||
|
str_low_ts = stringNew(bigbuf);
|
||
|
sprintf(bigbuf,
|
||
|
" fmorphopgen_low_%d(datad, w, h, wpld, datat, wpls, index+1);",
|
||
|
fileindex);
|
||
|
str_low_dtp1 = stringNew(bigbuf);
|
||
|
|
||
|
/* Make the output sa */
|
||
|
sa3 = sarrayCreate(0);
|
||
|
|
||
|
/* Copyright notice and info header */
|
||
|
sarrayParseRange(sa2, 0, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
|
||
|
/* Insert function names as documentation */
|
||
|
sarrayAddString(sa3, str_doc1, L_INSERT);
|
||
|
sarrayAddString(sa3, str_doc2, L_INSERT);
|
||
|
|
||
|
/* Add '#include's */
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
|
||
|
/* Insert function prototypes */
|
||
|
sarrayAddString(sa3, str_proto1, L_INSERT);
|
||
|
sarrayAddString(sa3, str_proto2, L_INSERT);
|
||
|
sarrayAddString(sa3, str_proto3, L_INSERT);
|
||
|
|
||
|
/* Add static globals */
|
||
|
sprintf(bigbuf, "\nstatic l_int32 NUM_SELS_GENERATED = %d;", nsels);
|
||
|
sarrayAddString(sa3, bigbuf, L_COPY);
|
||
|
sprintf(bigbuf, "static char SEL_NAMES[][80] = {");
|
||
|
sarrayAddString(sa3, bigbuf, L_COPY);
|
||
|
for (i = 0; i < nsels - 1; i++) {
|
||
|
sprintf(bigbuf, " \"%s\",",
|
||
|
sarrayGetString(sa1, i, L_NOCOPY));
|
||
|
sarrayAddString(sa3, bigbuf, L_COPY);
|
||
|
}
|
||
|
sprintf(bigbuf, " \"%s\"};",
|
||
|
sarrayGetString(sa1, i, L_NOCOPY));
|
||
|
sarrayAddString(sa3, bigbuf, L_COPY);
|
||
|
|
||
|
/* Start pixMorphDwa_*() function description */
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_doc3, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
|
||
|
/* Finish pixMorphDwa_*() function definition */
|
||
|
sarrayAddString(sa3, str_def1, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_proc1, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_dwa1, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
|
||
|
/* Start pixFMorphopGen_*() function description */
|
||
|
sarrayAddString(sa3, str_doc4, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
|
||
|
/* Finish pixFMorphopGen_*() function definition */
|
||
|
sarrayAddString(sa3, str_def2, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_proc2, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_low_dt, L_COPY);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_low_ds, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_low_tsp1, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_low_dt, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_low_ts, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
sarrayAddString(sa3, str_low_dtp1, L_INSERT);
|
||
|
sarrayParseRange(sa2, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa3, sa2, actstart, end);
|
||
|
|
||
|
/* Output to file */
|
||
|
filestr = sarrayToString(sa3, 1);
|
||
|
nbytes = strlen(filestr);
|
||
|
if (filename)
|
||
|
snprintf(bigbuf, L_BUF_SIZE, "%s.%d.c", filename, fileindex);
|
||
|
else
|
||
|
sprintf(bigbuf, "%s.%d.c", OUTROOT, fileindex);
|
||
|
l_binaryWrite(bigbuf, "w", filestr, nbytes);
|
||
|
sarrayDestroy(&sa1);
|
||
|
sarrayDestroy(&sa2);
|
||
|
sarrayDestroy(&sa3);
|
||
|
LEPT_FREE(filestr);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* fmorphautogen2()
|
||
|
*
|
||
|
* Input: sela
|
||
|
* fileindex
|
||
|
* filename (<optional>; can be null)
|
||
|
* Return: 0 if OK; 1 on error
|
||
|
*
|
||
|
* Notes:
|
||
|
* (1) This function uses morphtemplate2.txt to create a
|
||
|
* low-level file that contains the low-level functions for
|
||
|
* implementing dilation and erosion for every sel
|
||
|
* in the input sela.
|
||
|
* (2) The fileindex parameter is inserted into the output
|
||
|
* filename, as described below.
|
||
|
* (3) If filename == NULL, the output file is fmorphgenlow.[n].c,
|
||
|
* where [n] is equal to the 'fileindex' parameter.
|
||
|
* (4) If filename != NULL, the output file is [filename]low.[n].c.
|
||
|
*/
|
||
|
l_int32
|
||
|
fmorphautogen2(SELA *sela,
|
||
|
l_int32 fileindex,
|
||
|
const char *filename)
|
||
|
{
|
||
|
char *filestr, *linestr, *fname;
|
||
|
char *str_doc1, *str_doc2, *str_doc3, *str_doc4, *str_def1;
|
||
|
char bigbuf[L_BUF_SIZE];
|
||
|
char breakstring[] = " break;";
|
||
|
char staticstring[] = "static void";
|
||
|
l_int32 i, nsels, nbytes, actstart, end, newstart;
|
||
|
l_int32 argstart, argend, loopstart, loopend, finalstart, finalend;
|
||
|
size_t size;
|
||
|
SARRAY *sa1, *sa2, *sa3, *sa4, *sa5, *sa6;
|
||
|
SEL *sel;
|
||
|
|
||
|
PROCNAME("fmorphautogen2");
|
||
|
|
||
|
if (!sela)
|
||
|
return ERROR_INT("sela not defined", procName, 1);
|
||
|
if (fileindex < 0)
|
||
|
fileindex = 0;
|
||
|
if ((nsels = selaGetCount(sela)) == 0)
|
||
|
return ERROR_INT("no sels in sela", procName, 1);
|
||
|
|
||
|
/* Make the array of textlines from morphtemplate2.txt */
|
||
|
if ((filestr = (char *)l_binaryRead(TEMPLATE2, &size)) == NULL)
|
||
|
return ERROR_INT("filestr not made", procName, 1);
|
||
|
sa1 = sarrayCreateLinesFromString(filestr, 1);
|
||
|
LEPT_FREE(filestr);
|
||
|
if (!sa1)
|
||
|
return ERROR_INT("sa1 not made", procName, 1);
|
||
|
|
||
|
/* Make the array of static function names */
|
||
|
if ((sa2 = sarrayCreate(2 * nsels)) == NULL) {
|
||
|
sarrayDestroy(&sa1);
|
||
|
return ERROR_INT("sa2 not made", procName, 1);
|
||
|
}
|
||
|
for (i = 0; i < nsels; i++) {
|
||
|
sprintf(bigbuf, "fdilate_%d_%d", fileindex, i);
|
||
|
sarrayAddString(sa2, bigbuf, L_COPY);
|
||
|
sprintf(bigbuf, "ferode_%d_%d", fileindex, i);
|
||
|
sarrayAddString(sa2, bigbuf, L_COPY);
|
||
|
}
|
||
|
|
||
|
/* Make the static prototype strings */
|
||
|
sa3 = sarrayCreate(2 * nsels); /* should be ok */
|
||
|
for (i = 0; i < 2 * nsels; i++) {
|
||
|
fname = sarrayGetString(sa2, i, L_NOCOPY);
|
||
|
sprintf(bigbuf, "static void %s%s", fname, PROTOARGS);
|
||
|
sarrayAddString(sa3, bigbuf, L_COPY);
|
||
|
}
|
||
|
|
||
|
/* Make strings containing function names */
|
||
|
sprintf(bigbuf, " * l_int32 fmorphopgen_low_%d()",
|
||
|
fileindex);
|
||
|
str_doc1 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " * void fdilate_%d_*()", fileindex);
|
||
|
str_doc2 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, " * void ferode_%d_*()", fileindex);
|
||
|
str_doc3 = stringNew(bigbuf);
|
||
|
|
||
|
/* Output to this sa */
|
||
|
sa4 = sarrayCreate(0);
|
||
|
|
||
|
/* Copyright notice and info header */
|
||
|
sarrayParseRange(sa1, 0, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa4, sa1, actstart, end);
|
||
|
|
||
|
/* Insert function names as documentation */
|
||
|
sarrayAddString(sa4, str_doc1, L_INSERT);
|
||
|
sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa4, sa1, actstart, end);
|
||
|
sarrayAddString(sa4, str_doc2, L_INSERT);
|
||
|
sarrayAddString(sa4, str_doc3, L_INSERT);
|
||
|
sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa4, sa1, actstart, end);
|
||
|
|
||
|
/* Insert static protos */
|
||
|
for (i = 0; i < 2 * nsels; i++) {
|
||
|
if ((linestr = sarrayGetString(sa3, i, L_COPY)) == NULL) {
|
||
|
sarrayDestroy(&sa1);
|
||
|
sarrayDestroy(&sa2);
|
||
|
sarrayDestroy(&sa3);
|
||
|
sarrayDestroy(&sa4);
|
||
|
return ERROR_INT("linestr not retrieved", procName, 1);
|
||
|
}
|
||
|
sarrayAddString(sa4, linestr, L_INSERT);
|
||
|
}
|
||
|
|
||
|
/* More strings with function names */
|
||
|
sprintf(bigbuf, " * fmorphopgen_low_%d()", fileindex);
|
||
|
str_doc4 = stringNew(bigbuf);
|
||
|
sprintf(bigbuf, "fmorphopgen_low_%d(l_uint32 *datad,", fileindex);
|
||
|
str_def1 = stringNew(bigbuf);
|
||
|
|
||
|
/* Insert function header */
|
||
|
sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa4, sa1, actstart, end);
|
||
|
sarrayAddString(sa4, str_doc4, L_INSERT);
|
||
|
sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa4, sa1, actstart, end);
|
||
|
sarrayAddString(sa4, str_def1, L_INSERT);
|
||
|
sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa4, sa1, actstart, end);
|
||
|
|
||
|
/* Generate and insert the dispatcher code */
|
||
|
for (i = 0; i < 2 * nsels; i++) {
|
||
|
sprintf(bigbuf, " case %d:", i);
|
||
|
sarrayAddString(sa4, bigbuf, L_COPY);
|
||
|
sprintf(bigbuf, " %s(datad, w, h, wpld, datas, wpls);",
|
||
|
sarrayGetString(sa2, i, L_NOCOPY));
|
||
|
sarrayAddString(sa4, bigbuf, L_COPY);
|
||
|
sarrayAddString(sa4, breakstring, L_COPY);
|
||
|
}
|
||
|
|
||
|
/* Finish the dispatcher and introduce the low-level code */
|
||
|
sarrayParseRange(sa1, newstart, &actstart, &end, &newstart, "--", 0);
|
||
|
sarrayAppendRange(sa4, sa1, actstart, end);
|
||
|
|
||
|
/* Get the range for the args common to all functions */
|
||
|
sarrayParseRange(sa1, newstart, &argstart, &argend, &newstart, "--", 0);
|
||
|
|
||
|
/* Get the range for the loop code common to all functions */
|
||
|
sarrayParseRange(sa1, newstart, &loopstart, &loopend, &newstart, "--", 0);
|
||
|
|
||
|
/* Get the range for the ending code common to all functions */
|
||
|
sarrayParseRange(sa1, newstart, &finalstart, &finalend, &newstart, "--", 0);
|
||
|
|
||
|
/* Do all the static functions */
|
||
|
for (i = 0; i < 2 * nsels; i++) {
|
||
|
/* Generate the function header and add the common args */
|
||
|
sarrayAddString(sa4, staticstring, L_COPY);
|
||
|
fname = sarrayGetString(sa2, i, L_NOCOPY);
|
||
|
sprintf(bigbuf, "%s(l_uint32 *datad,", fname);
|
||
|
sarrayAddString(sa4, bigbuf, L_COPY);
|
||
|
sarrayAppendRange(sa4, sa1, argstart, argend);
|
||
|
|
||
|
/* Declare and define wplsN args, as necessary */
|
||
|
if ((sel = selaGetSel(sela, i/2)) == NULL) {
|
||
|
sarrayDestroy(&sa1);
|
||
|
sarrayDestroy(&sa2);
|
||
|
sarrayDestroy(&sa3);
|
||
|
sarrayDestroy(&sa4);
|
||
|
return ERROR_INT("sel not returned", procName, 1);
|
||
|
}
|
||
|
sa5 = sarrayMakeWplsCode(sel);
|
||
|
sarrayJoin(sa4, sa5);
|
||
|
sarrayDestroy(&sa5);
|
||
|
|
||
|
/* Add the function loop code */
|
||
|
sarrayAppendRange(sa4, sa1, loopstart, loopend);
|
||
|
|
||
|
/* Insert barrel-op code for *dptr */
|
||
|
sa6 = sarrayMakeInnerLoopDWACode(sel, i);
|
||
|
sarrayJoin(sa4, sa6);
|
||
|
sarrayDestroy(&sa6);
|
||
|
|
||
|
/* Finish the function code */
|
||
|
sarrayAppendRange(sa4, sa1, finalstart, finalend);
|
||
|
}
|
||
|
|
||
|
/* Output to file */
|
||
|
filestr = sarrayToString(sa4, 1);
|
||
|
nbytes = strlen(filestr);
|
||
|
if (filename)
|
||
|
snprintf(bigbuf, L_BUF_SIZE, "%slow.%d.c", filename, fileindex);
|
||
|
else
|
||
|
sprintf(bigbuf, "%slow.%d.c", OUTROOT, fileindex);
|
||
|
l_binaryWrite(bigbuf, "w", filestr, nbytes);
|
||
|
sarrayDestroy(&sa1);
|
||
|
sarrayDestroy(&sa2);
|
||
|
sarrayDestroy(&sa3);
|
||
|
sarrayDestroy(&sa4);
|
||
|
LEPT_FREE(filestr);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*
|
||
|
* Helper code for sel *
|
||
|
*--------------------------------------------------------------------------*/
|
||
|
/*!
|
||
|
* \brief sarrayMakeWplsCode()
|
||
|
*/
|
||
|
static SARRAY *
|
||
|
sarrayMakeWplsCode(SEL *sel)
|
||
|
{
|
||
|
char emptystring[] = "";
|
||
|
l_int32 i, j, ymax, dely, allvshifts;
|
||
|
l_int32 vshift[32];
|
||
|
SARRAY *sa;
|
||
|
|
||
|
PROCNAME("sarrayMakeWplsCode");
|
||
|
|
||
|
if (!sel)
|
||
|
return (SARRAY *)ERROR_PTR("sel not defined", procName, NULL);
|
||
|
|
||
|
for (i = 0; i < 32; i++)
|
||
|
vshift[i] = 0;
|
||
|
ymax = 0;
|
||
|
for (i = 0; i < sel->sy; i++) {
|
||
|
for (j = 0; j < sel->sx; j++) {
|
||
|
if (sel->data[i][j] == 1) {
|
||
|
dely = L_ABS(i - sel->cy);
|
||
|
if (dely < 32)
|
||
|
vshift[dely] = 1;
|
||
|
ymax = L_MAX(ymax, dely);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (ymax > 31) {
|
||
|
L_WARNING("ymax > 31; truncating to 31\n", procName);
|
||
|
ymax = 31;
|
||
|
}
|
||
|
|
||
|
/* Test if this is a vertical brick */
|
||
|
allvshifts = TRUE;
|
||
|
for (i = 0; i < ymax; i++) {
|
||
|
if (vshift[i] == 0) {
|
||
|
allvshifts = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sa = sarrayCreate(0);
|
||
|
|
||
|
/* Add declarations */
|
||
|
if (allvshifts == TRUE) { /* packs them as well as possible */
|
||
|
if (ymax > 4)
|
||
|
sarrayAddString(sa, wpldecls[2], L_COPY);
|
||
|
if (ymax > 8)
|
||
|
sarrayAddString(sa, wpldecls[6], L_COPY);
|
||
|
if (ymax > 12)
|
||
|
sarrayAddString(sa, wpldecls[10], L_COPY);
|
||
|
if (ymax > 16)
|
||
|
sarrayAddString(sa, wpldecls[14], L_COPY);
|
||
|
if (ymax > 20)
|
||
|
sarrayAddString(sa, wpldecls[18], L_COPY);
|
||
|
if (ymax > 24)
|
||
|
sarrayAddString(sa, wpldecls[22], L_COPY);
|
||
|
if (ymax > 28)
|
||
|
sarrayAddString(sa, wpldecls[26], L_COPY);
|
||
|
if (ymax > 1)
|
||
|
sarrayAddString(sa, wpldecls[ymax - 2], L_COPY);
|
||
|
} else { /* puts them one/line */
|
||
|
for (i = 2; i <= ymax; i++) {
|
||
|
if (vshift[i])
|
||
|
sarrayAddString(sa, wplgendecls[i - 2], L_COPY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sarrayAddString(sa, emptystring, L_COPY);
|
||
|
|
||
|
/* Add definitions */
|
||
|
for (i = 2; i <= ymax; i++) {
|
||
|
if (vshift[i])
|
||
|
sarrayAddString(sa, wpldefs[i - 2], L_COPY);
|
||
|
}
|
||
|
|
||
|
return sa;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief sarrayMakeInnerLoopDWACode()
|
||
|
*/
|
||
|
static SARRAY *
|
||
|
sarrayMakeInnerLoopDWACode(SEL *sel,
|
||
|
l_int32 index)
|
||
|
{
|
||
|
char *tstr, *string;
|
||
|
char logicalor[] = "|";
|
||
|
char logicaland[] = "&";
|
||
|
char bigbuf[L_BUF_SIZE];
|
||
|
l_int32 i, j, optype, count, nfound, delx, dely;
|
||
|
SARRAY *sa;
|
||
|
|
||
|
PROCNAME("sarrayMakeInnerLoopDWACode");
|
||
|
|
||
|
if (!sel)
|
||
|
return (SARRAY *)ERROR_PTR("sel not defined", procName, NULL);
|
||
|
|
||
|
if (index % 2 == 0) {
|
||
|
optype = L_MORPH_DILATE;
|
||
|
tstr = logicalor;
|
||
|
} else {
|
||
|
optype = L_MORPH_ERODE;
|
||
|
tstr = logicaland;
|
||
|
}
|
||
|
|
||
|
count = 0;
|
||
|
for (i = 0; i < sel->sy; i++) {
|
||
|
for (j = 0; j < sel->sx; j++) {
|
||
|
if (sel->data[i][j] == 1)
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sa = sarrayCreate(0);
|
||
|
if (count == 0) {
|
||
|
L_WARNING("no hits in Sel %d\n", procName, index);
|
||
|
return sa; /* no code inside! */
|
||
|
}
|
||
|
|
||
|
nfound = 0;
|
||
|
for (i = 0; i < sel->sy; i++) {
|
||
|
for (j = 0; j < sel->sx; j++) {
|
||
|
if (sel->data[i][j] == 1) {
|
||
|
nfound++;
|
||
|
if (optype == L_MORPH_DILATE) {
|
||
|
dely = sel->cy - i;
|
||
|
delx = sel->cx - j;
|
||
|
} else { /* optype == L_MORPH_ERODE */
|
||
|
dely = i - sel->cy;
|
||
|
delx = j - sel->cx;
|
||
|
}
|
||
|
if ((string = makeBarrelshiftString(delx, dely)) == NULL) {
|
||
|
L_WARNING("barrel shift string not made\n", procName);
|
||
|
continue;
|
||
|
}
|
||
|
if (count == 1) /* just one item */
|
||
|
sprintf(bigbuf, " *dptr = %s;", string);
|
||
|
else if (nfound == 1)
|
||
|
sprintf(bigbuf, " *dptr = %s %s", string, tstr);
|
||
|
else if (nfound < count)
|
||
|
sprintf(bigbuf, " %s %s", string, tstr);
|
||
|
else /* nfound == count */
|
||
|
sprintf(bigbuf, " %s;", string);
|
||
|
sarrayAddString(sa, bigbuf, L_COPY);
|
||
|
LEPT_FREE(string);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return sa;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
* \brief makeBarrelshiftString()
|
||
|
*/
|
||
|
static char *
|
||
|
makeBarrelshiftString(l_int32 delx, /* j - cx */
|
||
|
l_int32 dely) /* i - cy */
|
||
|
{
|
||
|
l_int32 absx, absy;
|
||
|
char bigbuf[L_BUF_SIZE];
|
||
|
|
||
|
PROCNAME("makeBarrelshiftString");
|
||
|
|
||
|
if (delx < -31 || delx > 31)
|
||
|
return (char *)ERROR_PTR("delx out of bounds", procName, NULL);
|
||
|
if (dely < -31 || dely > 31)
|
||
|
return (char *)ERROR_PTR("dely out of bounds", procName, NULL);
|
||
|
absx = L_ABS(delx);
|
||
|
absy = L_ABS(dely);
|
||
|
|
||
|
if ((delx == 0) && (dely == 0))
|
||
|
sprintf(bigbuf, "(*sptr)");
|
||
|
else if ((delx == 0) && (dely < 0))
|
||
|
sprintf(bigbuf, "(*(sptr %s))", wplstrm[absy - 1]);
|
||
|
else if ((delx == 0) && (dely > 0))
|
||
|
sprintf(bigbuf, "(*(sptr %s))", wplstrp[absy - 1]);
|
||
|
else if ((delx < 0) && (dely == 0))
|
||
|
sprintf(bigbuf, "((*(sptr) >> %d) | (*(sptr - 1) << %d))",
|
||
|
absx, 32 - absx);
|
||
|
else if ((delx > 0) && (dely == 0))
|
||
|
sprintf(bigbuf, "((*(sptr) << %d) | (*(sptr + 1) >> %d))",
|
||
|
absx, 32 - absx);
|
||
|
else if ((delx < 0) && (dely < 0))
|
||
|
sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
|
||
|
wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
|
||
|
else if ((delx > 0) && (dely < 0))
|
||
|
sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
|
||
|
wplstrm[absy - 1], absx, wplstrm[absy - 1], 32 - absx);
|
||
|
else if ((delx < 0) && (dely > 0))
|
||
|
sprintf(bigbuf, "((*(sptr %s) >> %d) | (*(sptr %s - 1) << %d))",
|
||
|
wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
|
||
|
else /* ((delx > 0) && (dely > 0)) */
|
||
|
sprintf(bigbuf, "((*(sptr %s) << %d) | (*(sptr %s + 1) >> %d))",
|
||
|
wplstrp[absy - 1], absx, wplstrp[absy - 1], 32 - absx);
|
||
|
|
||
|
return stringNew(bigbuf);
|
||
|
}
|