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 */
48static BOXA *pixLocateStaveSets(PIX *pixs, l_int32 pageno, PIXA *pixadb);
49static l_ok boxaRemoveVGaps(BOXA *boxa);
50
51/*---------------------------------------------------------------------*
52 * Top level *
53 *---------------------------------------------------------------------*/
74l_ok
75partifyFiles(const char *dirname,
76 const char *substr,
77 l_int32 nparts,
78 const char *outroot,
79 const char *debugfile)
80{
81PIXA *pixadb;
82PIXAC *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
122l_ok
124 l_int32 nparts,
125 const char *outroot,
126 PIXA *pixadb)
127{
128char buf[512];
129l_int32 i, j, pageno, res, npage, nbox, icount, line;
130l_float32 factor;
131L_BMF *bmf;
132BOX *box1, *box2;
133BOXA *boxa1, *boxa2, *boxa3;
134PIX *pix1, *pix2, *pix3, *pix4, *pix5;
135PIXAC **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 */
252static BOXA *
253pixLocateStaveSets(PIX *pixs,
254 l_int32 pageno,
255 PIXA *pixadb)
256{
257BOXA *boxa1, *boxa2, *boxa3, *boxa4;
258PIX *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 */
300static l_ok
301boxaRemoveVGaps(BOXA *boxa)
302{
303l_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
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:117
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
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
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
l_ok boxSetSideLocations(BOX *box, l_int32 l, l_int32 r, l_int32 t, l_int32 b)
boxSetSideLocations()
Definition: boxbasic.c:408
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
BOXA * boxaTransform(BOXA *boxas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
boxaTransform()
Definition: boxfunc2.c:102
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:637
BOXA * boxaSelectByArea(BOXA *boxas, l_int32 area, l_int32 relation, l_int32 *pchanged)
boxaSelectByArea()
Definition: boxfunc4.c:370
BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity)
pixConnCompBB()
Definition: conncomp.c:310
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_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:123
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
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
@ L_SELECT_IF_GT
Definition: pix.h:783
@ L_SORT_BY_Y
Definition: pix.h:736
@ L_ADD_LEFT
Definition: pix.h:1211
@ L_COPY
Definition: pix.h:712
@ L_INSERT
Definition: pix.h:711
@ L_SORT_INCREASING
Definition: pix.h:729
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
PIXAC * pixacompCreateFromFiles(const char *dirname, const char *substr, l_int32 comptype)
pixacompCreateFromFiles()
Definition: pixcomp.c:797
void pixacompDestroy(PIXAC **ppixac)
pixacompDestroy()
Definition: pixcomp.c:878
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
l_int32 pixacompGetCount(PIXAC *pixac)
pixacompGetCount()
Definition: pixcomp.c:1162
l_ok pixacompAddPix(PIXAC *pixac, PIX *pix, l_int32 comptype)
pixacompAddPix()
Definition: pixcomp.c:923
PIX * pixacompGetPix(PIXAC *pixac, l_int32 index)
pixacompGetPix()
Definition: pixcomp.c:1227
PIXAC * pixacompCreate(l_int32 n)
pixacompCreate()
Definition: pixcomp.c:609
PIX * pixConvertTo1Adaptive(PIX *pixs)
pixConvertTo1Adaptive()
Definition: pixconv.c:2967
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
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:210
Definition: pix.h:481
Definition: pix.h:492
Definition: bmf.h:47
Definition: pix.h:139
Definition: pix.h:654
Definition: pix.h:456
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:276
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306