Leptonica  1.83.1
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  if (!dirname)
85  return ERROR_INT("dirname not defined", __func__, 1);
86  if (nparts < 0 || nparts > 10)
87  return ERROR_INT("nparts not in [1 ... 10]", __func__, 1);
88  if (!outroot || outroot[0] == '\n')
89  return ERROR_INT("outroot undefined or empty", __func__, 1);
90 
91  pixadb = (debugfile) ? pixaCreate(0) : NULL;
92  pixac = pixacompCreateFromFiles(dirname, substr, IFF_PNG);
93  partifyPixac(pixac, nparts, outroot, pixadb);
94  if (pixadb) {
95  L_INFO("writing debug output to %s\n", __func__, debugfile);
96  pixaConvertToPdf(pixadb, 300, 1.0, L_FLATE_ENCODE, 0,
97  "Partify Debug", debugfile);
98  }
99  pixacompDestroy(&pixac);
100  pixaDestroy(&pixadb);
101  return 0;
102 }
103 
104 
120 l_ok
122  l_int32 nparts,
123  const char *outroot,
124  PIXA *pixadb)
125 {
126 char buf[512];
127 l_int32 i, j, pageno, res, npage, nbox, icount, line;
128 l_float32 factor;
129 L_BMF *bmf;
130 BOX *box1, *box2;
131 BOXA *boxa1, *boxa2, *boxa3;
132 PIX *pix1, *pix2, *pix3, *pix4, *pix5;
133 PIXAC **pixaca;
134 
135  if (!pixac)
136  return ERROR_INT("pixac not defined", __func__, 1);
137  if ((npage = pixacompGetCount(pixac)) == 0)
138  return ERROR_INT("pixac is empty", __func__, 1);
139  if (nparts < 1 || nparts > 10)
140  return ERROR_INT("nparts not in [1 ... 10]", __func__, 1);
141  if (!outroot || outroot[0] == '\n')
142  return ERROR_INT("outroot undefined or empty", __func__, 1);
143 
144  /* Initialize the output array for each of the nparts */
145  pixaca = (PIXAC **)LEPT_CALLOC(nparts, sizeof(PIXAC *));
146  for (i = 0; i < nparts; i++)
147  pixaca[i] = pixacompCreate(0);
148 
149  /* Process each page */
150  line = 1;
151  bmf = bmfCreate(NULL, 10);
152  for (pageno = 0; pageno < npage; pageno++) {
153  if ((pix1 = pixacompGetPix(pixac, pageno)) == NULL) {
154  L_ERROR("pix for page %d not found\n", __func__, pageno);
155  continue;
156  }
157 
158  /* Scale, binarize and deskew */
159  res = pixGetXRes(pix1);
160  if (res == 0 || res == 300 || res > 600) {
161  pix2 = pixClone(pix1);
162  } else {
163  factor = 300.0 / (l_float32)res;
164  if (factor > 3)
165  L_WARNING("resolution is very low\n", __func__);
166  pix2 = pixScale(pix1, factor, factor);
167  }
168  pix3 = pixConvertTo1Adaptive(pix2);
169  pix4 = pixDeskew(pix3, 0);
170  pixDestroy(&pix1);
171  pixDestroy(&pix2);
172  pixDestroy(&pix3);
173  if (!pix4) {
174  L_ERROR("pix for page %d not deskewed\n", __func__, pageno);
175  continue;
176  }
177  pix1 = pixClone(pix4); /* rename */
178  pixDestroy(&pix4);
179 
180  /* Find the stave sets at 4x reduction */
181  boxa1 = pixLocateStaveSets(pix1, pageno, pixadb);
182 
183  /* Break each stave set into the separate staves (parts).
184  * A typical set will have more than one part, but if one of
185  * the parts is a keyboard, it will usually have two staves
186  * (also called a Grand Staff), composed of treble and
187  * bass staves. For example, a classical violin sonata
188  * could have a staff for the violin and two staves for
189  * the piano. We would set nparts == 2, and extract both
190  * of the piano staves as the piano part. */
191  nbox = boxaGetCount(boxa1);
192  lept_stderr("number of boxes in page %d: %d\n", pageno, nbox);
193  for (i = 0; i < nbox; i++, line++) {
194  snprintf(buf, sizeof(buf), "%d", line);
195  box1 = boxaGetBox(boxa1, i, L_COPY);
196  pix2 = pixClipRectangle(pix1, box1, NULL);
197  pix3 = pixMorphSequence(pix2, "d1.20 + o50.1 + o1.30", 0);
198  boxa2 = pixConnCompBB(pix3, 8);
199  boxa3 = boxaSort(boxa2, L_SORT_BY_Y, L_SORT_INCREASING, NULL);
200  boxaRemoveVGaps(boxa3);
201  icount = boxaGetCount(boxa3);
202  if (icount < nparts)
203  L_WARNING("nparts requested = %d, but only found %d\n",
204  __func__, nparts, icount);
205  for (j = 0; j < icount && j < nparts; j++) {
206  box2 = boxaGetBox(boxa3, j, L_COPY);
207  if (j == nparts - 1) /* extend the box to the bottom */
208  boxSetSideLocations(box2, -1, -1, -1,
209  pixGetHeight(pix1) - 1);
210  pix4 = pixClipRectangle(pix2, box2, NULL);
211  pix5 = pixAddTextlines(pix4, bmf, buf, 1, L_ADD_LEFT);
212  pixacompAddPix(pixaca[j], pix5, IFF_TIFF_G4);
213  boxDestroy(&box2);
214  pixDestroy(&pix4);
215  pixDestroy(&pix5);
216  }
217  boxaDestroy(&boxa2);
218  boxaDestroy(&boxa3);
219  boxDestroy(&box1);
220  pixDestroy(&pix2);
221  pixDestroy(&pix3);
222  }
223  boxaDestroy(&boxa1);
224  pixDestroy(&pix1);
225  }
226 
227  /* Output separate pdfs for each part */
228  for (i = 0; i < nparts; i++) {
229  snprintf(buf, sizeof(buf), "%s-%d.pdf", outroot, i);
230  L_INFO("writing part %d: %s\n", __func__, i, buf);
231  pixacompConvertToPdf(pixaca[i], 300, 1.0, L_G4_ENCODE, 0, NULL, buf);
232  pixacompDestroy(&pixaca[i]);
233  }
234  LEPT_FREE(pixaca);
235  bmfDestroy(&bmf);
236  return 0;
237 }
238 
239 
240 /*
241  * \brief pixLocateStaveSets()
242  *
243  * \param[in] pixs 1 bpp, 300 ppi, deskewed
244  * \param[in] pageno page number; used for debug output
245  * \param[in] pixadb [optional] debug pixa; can be NULL
246  * \return boxa containing the stave sets at full resolution
247  */
248 static BOXA *
249 pixLocateStaveSets(PIX *pixs,
250  l_int32 pageno,
251  PIXA *pixadb)
252 {
253 BOXA *boxa1, *boxa2, *boxa3, *boxa4;
254 PIX *pix1, *pix2;
255 
256  /* Find the stave sets at 4x reduction */
257  pix1 = pixMorphSequence(pixs, "r11", 0);
258  boxa1 = pixConnCompBB(pix1, 8);
259  boxa2 = boxaSelectByArea(boxa1, 15000, L_SELECT_IF_GT, NULL);
260  boxa3 = boxaSort(boxa2, L_SORT_BY_Y, L_SORT_INCREASING, NULL);
261  if (pixadb) {
262  pix2 = pixConvertTo32(pix1);
263  pixRenderBoxaArb(pix2, boxa3, 2, 255, 0, 0);
264  pixaAddPix(pixadb, pix2, L_INSERT);
265  pixDisplay(pix2, 100 * pageno, 100);
266  }
267  boxaDestroy(&boxa1);
268  boxaDestroy(&boxa2);
269 
270  boxaRemoveVGaps(boxa3);
271  if (pixadb) {
272  pix2 = pixConvertTo32(pix1);
273  pixRenderBoxaArb(pix2, boxa3, 2, 0, 255, 0);
274  pixaAddPix(pixadb, pix2, L_INSERT);
275  pixDisplay(pix2, 100 * pageno, 600);
276  }
277  boxa4 = boxaTransform(boxa3, 0, 0, 4.0, 4.0); /* back to full res */
278  boxaDestroy(&boxa3);
279  pixDestroy(&pix1);
280  return boxa4;
281 }
282 
283 
284 /*
285  * \brief boxaRemoveVGaps()
286  *
287  * \param[in] boxa
288  * \return 0 if OK, 1 on error
289  *
290  * <pre>
291  * Notes:
292  * (1) The boxes in %boxa are aligned vertically. Move the horizontal
293  * edges vertically to remove the gaps between boxes.
294  * </pre>
295  */
296 static l_ok
297 boxaRemoveVGaps(BOXA *boxa)
298 {
299 l_int32 nbox, i, y1, h1, y2, h2, delta;
300 
301  nbox = boxaGetCount(boxa);
302  for (i = 0; i < nbox - 1; i++) {
303  boxaGetBoxGeometry(boxa, i, NULL, &y1, NULL, &h1);
304  boxaGetBoxGeometry(boxa, i + 1, NULL, &y2, NULL, &h2);
305  delta = (y2 - y1 - h1) / 2;
306  boxaAdjustBoxSides(boxa, i, 0, 0, 0, delta);
307  boxaAdjustBoxSides(boxa, i + 1, 0, 0, -delta, 0);
308  }
309  boxaAdjustBoxSides(boxa, nbox - 1, 0, 0, 0, delta); /* bot of last */
310  return 0;
311 }
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:168
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:118
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:796
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
l_int32 boxaGetCount(const BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:661
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:702
l_ok boxSetSideLocations(BOX *box, l_int32 l, l_int32 r, l_int32 t, l_int32 b)
boxSetSideLocations()
Definition: boxbasic.c:390
l_ok boxaAdjustBoxSides(BOXA *boxa, l_int32 index, l_int32 delleft, l_int32 delright, l_int32 deltop, l_int32 delbot)
boxaAdjustBoxSides()
Definition: boxfunc1.c:1886
BOXA * boxaTransform(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxaTransform()
Definition: boxfunc2.c:103
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:624
BOXA * boxaSelectByArea(BOXA *boxas, l_int32 area, l_int32 relation, l_int32 *pchanged)
boxaSelectByArea()
Definition: boxfunc4.c:363
BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity)
pixConnCompBB()
Definition: conncomp.c:307
l_ok pixRenderBoxaArb(PIX *pix, BOXA *boxa, l_int32 width, l_uint8 rval, l_uint8 gval, l_uint8 bval)
pixRenderBoxaArb()
Definition: graphics.c:1717
@ L_FLATE_ENCODE
Definition: imageio.h:161
@ L_G4_ENCODE
Definition: imageio.h:160
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
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 partifyPixac(PIXAC *pixac, l_int32 nparts, const char *outroot, PIXA *pixadb)
partifyPixac()
Definition: partify.c:121
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:756
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:994
@ L_SELECT_IF_GT
Definition: pix.h:576
@ L_SORT_BY_Y
Definition: pix.h:529
@ L_ADD_LEFT
Definition: pix.h:1004
@ L_COPY
Definition: pix.h:505
@ L_INSERT
Definition: pix.h:504
@ L_SORT_INCREASING
Definition: pix.h:522
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
void pixacompDestroy(PIXAC **ppixac)
pixacompDestroy()
Definition: pixcomp.c:851
PIXAC * pixacompCreateFromFiles(const char *dirname, const char *substr, l_int32 comptype)
pixacompCreateFromFiles()
Definition: pixcomp.c:774
PIXAC * pixacompCreate(l_int32 n)
pixacompCreate()
Definition: pixcomp.c:592
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:1923
l_int32 pixacompGetCount(PIXAC *pixac)
pixacompGetCount()
Definition: pixcomp.c:1121
l_ok pixacompAddPix(PIXAC *pixac, PIX *pix, l_int32 comptype)
pixacompAddPix()
Definition: pixcomp.c:894
PIX * pixacompGetPix(PIXAC *pixac, l_int32 index)
pixacompGetPix()
Definition: pixcomp.c:1182
PIX * pixConvertTo1Adaptive(PIX *pixs)
pixConvertTo1Adaptive()
Definition: pixconv.c:2895
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3246
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
PIX * pixDeskew(PIX *pixs, l_int32 redsearch)
pixDeskew()
Definition: skew.c:207
Definition: bmf.h:47
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:274
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306