Leptonica  1.82.0
Image processing and image analysis suite
partify.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
41 #ifdef HAVE_CONFIG_H
42 #include <config_auto.h>
43 #endif /* HAVE_CONFIG_H */
44 
45 #include "allheaders.h"
46 
47  /* Static helplers */
48 static BOXA *pixLocateStaveSets(PIX *pixs, l_int32 pageno, PIXA *pixadb);
49 static l_ok boxaRemoveVGaps(BOXA *boxa);
50 
51 /*---------------------------------------------------------------------*
52  * Top level *
53  *---------------------------------------------------------------------*/
74 l_ok
75 partifyFiles(const char *dirname,
76  const char *substr,
77  l_int32 nparts,
78  const char *outroot,
79  const char *debugfile)
80 {
81 PIXA *pixadb;
82 PIXAC *pixac;
83 
84  PROCNAME("partifyFiles");
85 
86  if (!dirname)
87  return ERROR_INT("dirname not defined", procName, 1);
88  if (nparts < 0 || nparts > 10)
89  return ERROR_INT("nparts not in [1 ... 10]", procName, 1);
90  if (!outroot || outroot[0] == '\n')
91  return ERROR_INT("outroot undefined or empty", procName, 1);
92 
93  pixadb = (debugfile) ? pixaCreate(0) : NULL;
94  pixac = pixacompCreateFromFiles(dirname, substr, IFF_PNG);
95  partifyPixac(pixac, nparts, outroot, pixadb);
96  if (pixadb) {
97  L_INFO("writing debug output to %s\n", procName, debugfile);
98  pixaConvertToPdf(pixadb, 300, 1.0, L_FLATE_ENCODE, 0,
99  "Partify Debug", debugfile);
100  }
101  pixacompDestroy(&pixac);
102  pixaDestroy(&pixadb);
103  return 0;
104 }
105 
106 
122 l_ok
124  l_int32 nparts,
125  const char *outroot,
126  PIXA *pixadb)
127 {
128 char buf[512];
129 l_int32 i, j, pageno, res, npage, nbox, icount, line;
130 l_float32 factor;
131 L_BMF *bmf;
132 BOX *box1, *box2;
133 BOXA *boxa1, *boxa2, *boxa3;
134 PIX *pix1, *pix2, *pix3, *pix4, *pix5;
135 PIXAC **pixaca;
136 
137  PROCNAME("partifyPixac");
138 
139  if (!pixac)
140  return ERROR_INT("pixac not defined", procName, 1);
141  if ((npage = pixacompGetCount(pixac)) == 0)
142  return ERROR_INT("pixac is empty", procName, 1);
143  if (nparts < 1 || nparts > 10)
144  return ERROR_INT("nparts not in [1 ... 10]", procName, 1);
145  if (!outroot || outroot[0] == '\n')
146  return ERROR_INT("outroot undefined or empty", procName, 1);
147 
148  /* Initialize the output array for each of the nparts */
149  pixaca = (PIXAC **)LEPT_CALLOC(nparts, sizeof(PIXAC *));
150  for (i = 0; i < nparts; i++)
151  pixaca[i] = pixacompCreate(0);
152 
153  /* Process each page */
154  line = 1;
155  bmf = bmfCreate(NULL, 10);
156  for (pageno = 0; pageno < npage; pageno++) {
157  if ((pix1 = pixacompGetPix(pixac, pageno)) == NULL) {
158  L_ERROR("pix for page %d not found\n", procName, pageno);
159  continue;
160  }
161 
162  /* Scale, binarize and deskew */
163  res = pixGetXRes(pix1);
164  if (res == 0 || res == 300 || res > 600) {
165  pix2 = pixClone(pix1);
166  } else {
167  factor = 300.0 / (l_float32)res;
168  if (factor > 3)
169  L_WARNING("resolution is very low\n", procName);
170  pix2 = pixScale(pix1, factor, factor);
171  }
172  pix3 = pixConvertTo1Adaptive(pix2);
173  pix4 = pixDeskew(pix3, 0);
174  pixDestroy(&pix1);
175  pixDestroy(&pix2);
176  pixDestroy(&pix3);
177  if (!pix4) {
178  L_ERROR("pix for page %d not deskewed\n", procName, pageno);
179  continue;
180  }
181  pix1 = pixClone(pix4); /* rename */
182  pixDestroy(&pix4);
183 
184  /* Find the stave sets at 4x reduction */
185  boxa1 = pixLocateStaveSets(pix1, pageno, pixadb);
186 
187  /* Break each stave set into the separate staves (parts).
188  * A typical set will have more than one part, but if one of
189  * the parts is a keyboard, it will usually have two staves
190  * (also called a Grand Staff), composed of treble and
191  * bass staves. For example, a classical violin sonata
192  * could have a staff for the violin and two staves for
193  * the piano. We would set nparts == 2, and extract both
194  * of the piano staves as the piano part. */
195  nbox = boxaGetCount(boxa1);
196  lept_stderr("number of boxes in page %d: %d\n", pageno, nbox);
197  for (i = 0; i < nbox; i++, line++) {
198  snprintf(buf, sizeof(buf), "%d", line);
199  box1 = boxaGetBox(boxa1, i, L_COPY);
200  pix2 = pixClipRectangle(pix1, box1, NULL);
201  pix3 = pixMorphSequence(pix2, "d1.20 + o50.1 + o1.30", 0);
202  boxa2 = pixConnCompBB(pix3, 8);
203  boxa3 = boxaSort(boxa2, L_SORT_BY_Y, L_SORT_INCREASING, NULL);
204  boxaRemoveVGaps(boxa3);
205  icount = boxaGetCount(boxa3);
206  if (icount < nparts)
207  L_WARNING("nparts requested = %d, but only found %d\n",
208  procName, nparts, icount);
209  for (j = 0; j < icount && j < nparts; j++) {
210  box2 = boxaGetBox(boxa3, j, L_COPY);
211  if (j == nparts - 1) /* extend the box to the bottom */
212  boxSetSideLocations(box2, -1, -1, -1,
213  pixGetHeight(pix1) - 1);
214  pix4 = pixClipRectangle(pix2, box2, NULL);
215  pix5 = pixAddTextlines(pix4, bmf, buf, 1, L_ADD_LEFT);
216  pixacompAddPix(pixaca[j], pix5, IFF_TIFF_G4);
217  boxDestroy(&box2);
218  pixDestroy(&pix4);
219  pixDestroy(&pix5);
220  }
221  boxaDestroy(&boxa2);
222  boxaDestroy(&boxa3);
223  boxDestroy(&box1);
224  pixDestroy(&pix2);
225  pixDestroy(&pix3);
226  }
227  boxaDestroy(&boxa1);
228  pixDestroy(&pix1);
229  }
230 
231  /* Output separate pdfs for each part */
232  for (i = 0; i < nparts; i++) {
233  snprintf(buf, sizeof(buf), "%s-%d.pdf", outroot, i);
234  L_INFO("writing part %d: %s\n", procName, i, buf);
235  pixacompConvertToPdf(pixaca[i], 300, 1.0, L_G4_ENCODE, 0, NULL, buf);
236  pixacompDestroy(&pixaca[i]);
237  }
238  LEPT_FREE(pixaca);
239  bmfDestroy(&bmf);
240  return 0;
241 }
242 
243 
244 /*
245  * \brief pixLocateStaveSets()
246  *
247  * \param[in] pixs 1 bpp, 300 ppi, deskewed
248  * \param[in] pageno page number; used for debug output
249  * \param[in] pixadb [optional] debug pixa; can be NULL
250  * \return boxa containing the stave sets at full resolution
251  */
252 static BOXA *
253 pixLocateStaveSets(PIX *pixs,
254  l_int32 pageno,
255  PIXA *pixadb)
256 {
257 BOXA *boxa1, *boxa2, *boxa3, *boxa4;
258 PIX *pix1, *pix2;
259 
260  /* Find the stave sets at 4x reduction */
261  pix1 = pixMorphSequence(pixs, "r11", 0);
262  boxa1 = pixConnCompBB(pix1, 8);
263  boxa2 = boxaSelectByArea(boxa1, 15000, L_SELECT_IF_GT, NULL);
264  boxa3 = boxaSort(boxa2, L_SORT_BY_Y, L_SORT_INCREASING, NULL);
265  if (pixadb) {
266  pix2 = pixConvertTo32(pix1);
267  pixRenderBoxaArb(pix2, boxa3, 2, 255, 0, 0);
268  pixaAddPix(pixadb, pix2, L_INSERT);
269  pixDisplay(pix2, 100 * pageno, 100);
270  }
271  boxaDestroy(&boxa1);
272  boxaDestroy(&boxa2);
273 
274  boxaRemoveVGaps(boxa3);
275  if (pixadb) {
276  pix2 = pixConvertTo32(pix1);
277  pixRenderBoxaArb(pix2, boxa3, 2, 0, 255, 0);
278  pixaAddPix(pixadb, pix2, L_INSERT);
279  pixDisplay(pix2, 100 * pageno, 600);
280  }
281  boxa4 = boxaTransform(boxa3, 0, 0, 4.0, 4.0); /* back to full res */
282  boxaDestroy(&boxa3);
283  pixDestroy(&pix1);
284  return boxa4;
285 }
286 
287 
288 /*
289  * \brief boxaRemoveVGaps()
290  *
291  * \param[in] boxa
292  * \return 0 if OK, 1 on error
293  *
294  * <pre>
295  * Notes:
296  * (1) The boxes in %boxa are aligned vertically. Move the horizontal
297  * edges vertically to remove the gaps between boxes.
298  * </pre>
299  */
300 static l_ok
301 boxaRemoveVGaps(BOXA *boxa)
302 {
303 l_int32 nbox, i, y1, h1, y2, h2, delta;
304 
305  nbox = boxaGetCount(boxa);
306  for (i = 0; i < nbox - 1; i++) {
307  boxaGetBoxGeometry(boxa, i, NULL, &y1, NULL, &h1);
308  boxaGetBoxGeometry(boxa, i + 1, NULL, &y2, NULL, &h2);
309  delta = (y2 - y1 - h1) / 2;
310  boxaAdjustBoxSides(boxa, i, 0, 0, 0, delta);
311  boxaAdjustBoxSides(boxa, i + 1, 0, 0, -delta, 0);
312  }
313  boxaAdjustBoxSides(boxa, nbox - 1, 0, 0, 0, delta); /* bot of last */
314  return 0;
315 }
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:169
PIX * pixDeskew(PIX *pixs, l_int32 redsearch)
pixDeskew()
Definition: skew.c:210
PIX * pixacompGetPix(PIXAC *pixac, l_int32 index)
pixacompGetPix()
Definition: pixcomp.c:1227
l_ok pixacompAddPix(PIXAC *pixac, PIX *pix, l_int32 comptype)
pixacompAddPix()
Definition: pixcomp.c:923
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:637
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
l_ok boxSetSideLocations(BOX *box, l_int32 l, l_int32 r, l_int32 t, l_int32 b)
boxSetSideLocations()
Definition: boxbasic.c:408
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
Definition: pix.h:712
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
PIXAC * pixacompCreate(l_int32 n)
pixacompCreate()
Definition: pixcomp.c:609
l_ok pixacompConvertToPdf(PIXAC *pixac, l_int32 res, l_float32 scalefactor, l_int32 type, l_int32 quality, const char *title, const char *fileout)
pixacompConvertToPdf()
Definition: pixcomp.c:2002
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
Definition: pix.h:491
Definition: bmf.h:46
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
BOXA * boxaTransform(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxaTransform()
Definition: boxfunc2.c:102
BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity)
pixConnCompBB()
Definition: conncomp.c:310
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:879
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
PIXAC * pixacompCreateFromFiles(const char *dirname, const char *substr, l_int32 comptype)
pixacompCreateFromFiles()
Definition: pixcomp.c:797
l_ok partifyPixac(PIXAC *pixac, l_int32 nparts, const char *outroot, PIXA *pixadb)
partifyPixac()
Definition: partify.c:123
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
Definition: pix.h:653
BOXA * boxaSelectByArea(BOXA *boxas, l_int32 area, l_int32 relation, l_int32 *pchanged)
boxaSelectByArea()
Definition: boxfunc4.c:370
void pixacompDestroy(PIXAC **ppixac)
pixacompDestroy()
Definition: pixcomp.c:878
PIX * pixConvertTo1Adaptive(PIX *pixs)
pixConvertTo1Adaptive()
Definition: pixconv.c:2967
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
Definition: pix.h:711
Definition: pix.h:455
l_ok partifyFiles(const char *dirname, const char *substr, l_int32 nparts, const char *outroot, const char *debugfile)
partifyFiles()
Definition: partify.c:75
l_ok pixaConvertToPdf(PIXA *pixa, l_int32 res, l_float32 scalefactor, l_int32 type, l_int32 quality, const char *title, const char *fileout)
pixaConvertToPdf()
Definition: pdfio1.c:790
l_ok pixRenderBoxaArb(PIX *pix, BOXA *boxa, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxaArb()
Definition: graphics.c:1772
l_ok boxaAdjustBoxSides(BOXA *boxa, l_int32 index, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxaAdjustBoxSides()
Definition: boxfunc1.c:1943
Definition: pix.h:138
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:276
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
l_int32 pixacompGetCount(PIXAC *pixac)
pixacompGetCount()
Definition: pixcomp.c:1162
Definition: pix.h:480
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:117