third-party/leptonica/prog/findcorners_reg.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.
*====================================================================*/
/*
* findcorners_reg.c
*
* This reg test demonstrates extraction of deskewed objects (tickets
* in this case) using morphological operations to identify the
* barcodes on each object. The objects are separately deskewed,
* the barcodes are again located, and the objects are extracted.
*
* We also show how to generate the HMT sela for detecting corners,
* and how to use it (with pixUnionOfMorphOps()) to find all the
* corners. The corner Sels were constructed to find significant
* corners in the presence of the type of noise expected from
* scanned images. The located corners are displayed by xor-ing
* a pattern (sel_cross) on each one.
*
* When this function is called with the display argument
* findcorners_reg display
* we display some results and additionally generate the following pdfs:
* /tmp/regout/seq_output_1.pdf (morphological operations of
* first call to locate barcodes)
* /tmp/regout/tickets.pdf (deskewed result for the set of tickets)
*/
#include "allheaders.h"
static BOXA *LocateBarcodes(PIX *pixs, PIX **ppixd, l_int32 flag);
static SELA *GetCornerSela(L_REGPARAMS *rp);
static const char *sel_cross = " xxx "
" xxx "
" xxx "
" xxx "
" xxx "
"xxxxxxxxxxxxx"
"xxxxxxXxxxxxx"
"xxxxxxxxxxxxx"
" xxx "
" xxx "
" xxx "
" xxx "
" xxx ";
l_int32 main(int argc,
char **argv)
{
l_int32 i, n, flag;
l_float32 angle, conf, deg2rad;
BOX *box1, *box2, *box3, *box4;
BOXA *boxa, *boxa2;
PIX *pixs, *pixd, *pix1, *pix2, *pix3;
PIXA *pixa;
SEL *sel;
SELA *sela;
L_REGPARAMS *rp;
if (regTestSetup(argc, argv, &rp))
return 1;
pixs = pixRead("tickets.tif");
flag = (rp->display) ? -1 : 0;
boxa = LocateBarcodes(pixs, &pixd, flag);
regTestWritePixAndCheck(rp, pixd, IFF_TIFF_G4); /* 0 */
if (rp->display) boxaWriteStream(stderr, boxa);
n = boxaGetCount(boxa);
deg2rad = 3.14159265 / 180.;
pixa = pixaCreate(9);
for (i = 0; i < n; i++) {
box1 = boxaGetBox(boxa, i, L_CLONE);
/* Use a larger adjustment to get entire skewed ticket */
box2 = boxAdjustSides(NULL, box1, -266, 346, -1560, 182);
pix1 = pixClipRectangle(pixs, box2, NULL);
/* Deskew */
pixFindSkew(pix1, &angle, &conf);
pix2 = pixRotate(pix1, deg2rad * angle, L_ROTATE_SAMPLING,
L_BRING_IN_WHITE, 0, 0);
/* Find the barcode again ... */
boxa2 = LocateBarcodes(pix2, NULL, 0);
box3 = boxaGetBox(boxa2, 0, L_CLONE);
/* ... and adjust crop box exactly for ticket size */
box4 = boxAdjustSides(NULL, box3, -141, 221, -1535, 157);
pix3 = pixClipRectangle(pix2, box4, NULL);
regTestWritePixAndCheck(rp, pix3, IFF_TIFF_G4); /* 1 - 9 */
if (rp->display)
pixaAddPix(pixa, pix3, L_INSERT);
else
pixDestroy(&pix3);
boxDestroy(&box1);
boxDestroy(&box2);
boxDestroy(&box3);
boxDestroy(&box4);
boxaDestroy(&boxa2);
pixDestroy(&pix1);
pixDestroy(&pix2);
}
if (rp->display) {
pixaConvertToPdf(pixa, 0, 1.0, 0, 0, "tickets",
"/tmp/regout/tickets.pdf");
L_INFO("Output pdf: /tmp/regout/tickets.pdf\n", rp->testname);
}
pixaDestroy(&pixa);
/* Downscale by 2x and locate corners */
pix1 = pixScale(pixd, 0.5, 0.5);
regTestWritePixAndCheck(rp, pix1, IFF_TIFF_G4); /* 10 */
pixDisplayWithTitle(pix1, 100, 200, NULL, rp->display);
/* Find corners and blit a cross onto each (4 to each barcode) */
sela = GetCornerSela(rp);
pix2 = pixUnionOfMorphOps(pix1, sela, L_MORPH_HMT);
sel = selCreateFromString(sel_cross, 13, 13, "sel_cross");
pix3 = pixDilate(NULL, pix2, sel);
pixXor(pix3, pix3, pix1);
regTestWritePixAndCheck(rp, pix3, IFF_TIFF_G4); /* 11 */
pixDisplayWithTitle(pix3, 800, 200, NULL, rp->display);
boxaDestroy(&boxa);
pixDestroy(&pixs);
pixDestroy(&pix1);
pixDestroy(&pix2);
pixDestroy(&pix3);
pixDestroy(&pixd);
selDestroy(&sel);
selaDestroy(&sela);
return regTestCleanup(rp);
}
static BOXA *
LocateBarcodes(PIX *pixs,
PIX **ppixd,
l_int32 flag)
{
BOXA *boxa1, *boxa2, *boxad;
PIX *pix1, *pix2, *pix3;
pix1 = pixScale(pixs, 0.5, 0.5);
pix2 = pixMorphSequence(pix1, "o1.5 + c15.1 + o10.15 + c20.20", flag);
boxa1 = pixConnComp(pix2, NULL, 8);
boxa2 = boxaSelectBySize(boxa1, 300, 0, L_SELECT_WIDTH,
L_SELECT_IF_GT, NULL);
boxad = boxaTransform(boxa2, 0, 0, 2.0, 2.0);
if (ppixd) {
pix3 = pixSelectBySize(pix2, 300, 0, 8, L_SELECT_WIDTH,
L_SELECT_IF_GT, NULL);
*ppixd = pixScale(pix3, 2.0, 2.0);
pixDestroy(&pix3);
}
pixDestroy(&pix1);
pixDestroy(&pix2);
boxaDestroy(&boxa1);
boxaDestroy(&boxa2);
return boxad;
}
static SELA *
GetCornerSela(L_REGPARAMS *rp)
{
PIX *pix;
SEL *sel;
SELA *sela1, *sela2;
sela1 = selaAddHitMiss(NULL);
sela2 = selaCreate(4);
selaFindSelByName(sela1, "sel_ulc", NULL, &sel);
selaAddSel(sela2, sel, NULL, 1);
selaFindSelByName(sela1, "sel_urc", NULL, &sel);
selaAddSel(sela2, sel, NULL, 1);
selaFindSelByName(sela1, "sel_llc", NULL, &sel);
selaAddSel(sela2, sel, NULL, 1);
selaFindSelByName(sela1, "sel_lrc", NULL, &sel);
selaAddSel(sela2, sel, NULL, 1);
selaDestroy(&sela1);
if (rp->display) {
pix = selaDisplayInPix(sela2, 21, 3, 10, 4);
pixDisplay(pix, 0, 0);
pixDestroy(&pix);
}
return sela2;
}