Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 00017 /* 00018 * sel2.c 00019 * 00020 * Contains definitions of simple structuring elements 00021 * 00022 * SELA *selaAddBasic() 00023 * Linear horizontal and vertical 00024 * Square 00025 * Diagonals 00026 * 00027 * SELA *selaAddHitMiss() 00028 * Isolated foreground pixel 00029 * Horizontal and vertical edges 00030 * Slanted edge 00031 * 00032 * SELA *selaAddDwaLinear() 00033 * SELA *selaAddDwaCombs() 00034 * SELA *selaAddCrossJunctions() 00035 * SELA *selaAddTJunctions() 00036 */ 00037 00038 #include <stdio.h> 00039 #include <math.h> 00040 #include "allheaders.h" 00041 00042 /* MSVC can't handle arrays dimensioned by static const integers */ 00043 #define L_BUF_SIZE 512 00044 00045 /* Linear brick sel sizes, including all those that are required 00046 * for decomposable sels up to size 63. */ 00047 static const l_int32 num_linear = 25; 00048 static const l_int32 basic_linear[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20, 21, 25, 30, 31, 35, 40, 41, 45, 50, 51}; 00049 00050 00051 /*! 00052 * selaAddBasic() 00053 * 00054 * Input: sela (<optional>) 00055 * Return: sela with additional sels, or null on error 00056 * 00057 * Notes: 00058 * (1) Adds the following sels: 00059 * - all linear (horiz, vert) brick sels that are 00060 * necessary for decomposable sels up to size 63 00061 * - square brick sels up to size 10 00062 * - 4 diagonal sels 00063 */ 00064 SELA * 00065 selaAddBasic(SELA *sela) 00066 { 00067 char name[L_BUF_SIZE]; 00068 l_int32 i, size; 00069 SEL *sel; 00070 00071 PROCNAME("selaAddBasic"); 00072 00073 if (!sela) { 00074 if ((sela = selaCreate(0)) == NULL) 00075 return (SELA *)ERROR_PTR("sela not made", procName, NULL); 00076 } 00077 00078 /*--------------------------------------------------------------* 00079 * Linear horizontal and vertical sels * 00080 *--------------------------------------------------------------*/ 00081 for (i = 0; i < num_linear; i++) { 00082 size = basic_linear[i]; 00083 sel = selCreateBrick(1, size, 0, size / 2, 1); 00084 snprintf(name, L_BUF_SIZE, "sel_%dh", size); 00085 selaAddSel(sela, sel, name, 0); 00086 } 00087 for (i = 0; i < num_linear; i++) { 00088 size = basic_linear[i]; 00089 sel = selCreateBrick(size, 1, size / 2, 0, 1); 00090 snprintf(name, L_BUF_SIZE, "sel_%dv", size); 00091 selaAddSel(sela, sel, name, 0); 00092 } 00093 00094 /*-----------------------------------------------------------* 00095 * 2-d Bricks * 00096 *-----------------------------------------------------------*/ 00097 for (i = 2; i <= 5; i++) { 00098 sel = selCreateBrick(i, i, i / 2, i / 2, 1); 00099 snprintf(name, L_BUF_SIZE, "sel_%d", i); 00100 selaAddSel(sela, sel, name, 0); 00101 } 00102 00103 /*-----------------------------------------------------------* 00104 * Diagonals * 00105 *-----------------------------------------------------------*/ 00106 /* 0c 1 00107 1 0 */ 00108 sel = selCreateBrick(2, 2, 0, 0, 1); 00109 selSetElement(sel, 0, 0, 0); 00110 selSetElement(sel, 1, 1, 0); 00111 selaAddSel(sela, sel, "sel_2dp", 0); 00112 00113 /* 1c 0 00114 0 1 */ 00115 sel = selCreateBrick(2, 2, 0, 0, 1); 00116 selSetElement(sel, 0, 1, 0); 00117 selSetElement(sel, 1, 0, 0); 00118 selaAddSel(sela, sel, "sel_2dm", 0); 00119 00120 /* Diagonal, slope +, size 5 */ 00121 sel = selCreate(5, 5, "sel_5dp"); 00122 sel->cy = 2; 00123 sel->cx = 2; 00124 selSetElement(sel, 0, 4, 1); 00125 selSetElement(sel, 1, 3, 1); 00126 selSetElement(sel, 2, 2, 1); 00127 selSetElement(sel, 3, 1, 1); 00128 selSetElement(sel, 4, 0, 1); 00129 selaAddSel(sela, sel, "sel_5dp", 0); 00130 00131 /* Diagonal, slope -, size 5 */ 00132 sel = selCreate(5, 5, "sel_5dm"); 00133 sel->cy = 2; 00134 sel->cx = 2; 00135 selSetElement(sel, 0, 0, 1); 00136 selSetElement(sel, 1, 1, 1); 00137 selSetElement(sel, 2, 2, 1); 00138 selSetElement(sel, 3, 3, 1); 00139 selSetElement(sel, 4, 4, 1); 00140 selaAddSel(sela, sel, "sel_5dm", 0); 00141 00142 return sela; 00143 } 00144 00145 00146 /*! 00147 * selaAddHitMiss() 00148 * 00149 * Input: sela (<optional>) 00150 * Return: sela with additional sels, or null on error 00151 */ 00152 SELA * 00153 selaAddHitMiss(SELA *sela) 00154 { 00155 SEL *sel; 00156 00157 PROCNAME("selaAddHitMiss"); 00158 00159 if (!sela) { 00160 if ((sela = selaCreate(0)) == NULL) 00161 return (SELA *)ERROR_PTR("sela not made", procName, NULL); 00162 } 00163 00164 #if 0 /* use just for testing */ 00165 sel = selCreateBrick(3, 3, 1, 1, 2); 00166 selaAddSel(sela, sel, "sel_bad", 0); 00167 #endif 00168 00169 00170 /*--------------------------------------------------------------* 00171 * Isolated foreground pixel * 00172 *--------------------------------------------------------------*/ 00173 sel = selCreateBrick(3, 3, 1, 1, 2); 00174 selSetElement(sel, 1, 1, 1); 00175 selaAddSel(sela, sel, "sel_3hm", 0); 00176 00177 00178 /*--------------------------------------------------------------* 00179 * Horizontal and vertical edges * 00180 *--------------------------------------------------------------*/ 00181 sel = selCreateBrick(2, 3, 0, 1, 1); 00182 selSetElement(sel, 1, 0, 2); 00183 selSetElement(sel, 1, 1, 2); 00184 selSetElement(sel, 1, 2, 2); 00185 selaAddSel(sela, sel, "sel_3de", 0); 00186 00187 sel = selCreateBrick(2, 3, 1, 1, 1); 00188 selSetElement(sel, 0, 0, 2); 00189 selSetElement(sel, 0, 1, 2); 00190 selSetElement(sel, 0, 2, 2); 00191 selaAddSel(sela, sel, "sel_3ue", 0); 00192 00193 sel = selCreateBrick(3, 2, 1, 0, 1); 00194 selSetElement(sel, 0, 1, 2); 00195 selSetElement(sel, 1, 1, 2); 00196 selSetElement(sel, 2, 1, 2); 00197 selaAddSel(sela, sel, "sel_3re", 0); 00198 00199 sel = selCreateBrick(3, 2, 1, 1, 1); 00200 selSetElement(sel, 0, 0, 2); 00201 selSetElement(sel, 1, 0, 2); 00202 selSetElement(sel, 2, 0, 2); 00203 selaAddSel(sela, sel, "sel_3le", 0); 00204 00205 00206 /*--------------------------------------------------------------* 00207 * Slanted edge * 00208 *--------------------------------------------------------------*/ 00209 sel = selCreateBrick(13, 6, 6, 2, 0); 00210 selSetElement(sel, 0, 3, 2); 00211 selSetElement(sel, 0, 5, 1); 00212 selSetElement(sel, 4, 2, 2); 00213 selSetElement(sel, 4, 4, 1); 00214 selSetElement(sel, 8, 1, 2); 00215 selSetElement(sel, 8, 3, 1); 00216 selSetElement(sel, 12, 0, 2); 00217 selSetElement(sel, 12, 2, 1); 00218 selaAddSel(sela, sel, "sel_sl1", 0); 00219 00220 return sela; 00221 } 00222 00223 00224 /*! 00225 * selaAddDwaLinear() 00226 * 00227 * Input: sela (<optional>) 00228 * Return: sela with additional sels, or null on error 00229 * 00230 * Notes: 00231 * (1) Adds all linear (horizontal, vertical) sels from 00232 * 2 to 63 pixels in length, which are the sizes over 00233 * which dwa code can be generated. 00234 */ 00235 SELA * 00236 selaAddDwaLinear(SELA *sela) 00237 { 00238 char name[L_BUF_SIZE]; 00239 l_int32 i; 00240 SEL *sel; 00241 00242 PROCNAME("selaAddDwaLinear"); 00243 00244 if (!sela) { 00245 if ((sela = selaCreate(0)) == NULL) 00246 return (SELA *)ERROR_PTR("sela not made", procName, NULL); 00247 } 00248 00249 for (i = 2; i < 64; i++) { 00250 sel = selCreateBrick(1, i, 0, i / 2, 1); 00251 snprintf(name, L_BUF_SIZE, "sel_%dh", i); 00252 selaAddSel(sela, sel, name, 0); 00253 } 00254 for (i = 2; i < 64; i++) { 00255 sel = selCreateBrick(i, 1, i / 2, 0, 1); 00256 snprintf(name, L_BUF_SIZE, "sel_%dv", i); 00257 selaAddSel(sela, sel, name, 0); 00258 } 00259 return sela; 00260 } 00261 00262 00263 /*! 00264 * selaAddDwaCombs() 00265 * 00266 * Input: sela (<optional>) 00267 * Return: sela with additional sels, or null on error 00268 * 00269 * Notes: 00270 * (1) Adds all comb (horizontal, vertical) Sels that are 00271 * used in composite linear morphological operations 00272 * up to 63 pixels in length, which are the sizes over 00273 * which dwa code can be generated. 00274 */ 00275 SELA * 00276 selaAddDwaCombs(SELA *sela) 00277 { 00278 char name[L_BUF_SIZE]; 00279 l_int32 i, f1, f2, prevsize, size; 00280 SEL *selh, *selv; 00281 00282 PROCNAME("selaAddDwaCombs"); 00283 00284 if (!sela) { 00285 if ((sela = selaCreate(0)) == NULL) 00286 return (SELA *)ERROR_PTR("sela not made", procName, NULL); 00287 } 00288 00289 prevsize = 0; 00290 for (i = 4; i < 64; i++) { 00291 selectComposableSizes(i, &f1, &f2); 00292 size = f1 * f2; 00293 if (size == prevsize) 00294 continue; 00295 selectComposableSels(i, L_HORIZ, NULL, &selh); 00296 selectComposableSels(i, L_VERT, NULL, &selv); 00297 snprintf(name, L_BUF_SIZE, "sel_comb_%dh", size); 00298 selaAddSel(sela, selh, name, 0); 00299 snprintf(name, L_BUF_SIZE, "sel_comb_%dv", size); 00300 selaAddSel(sela, selv, name, 0); 00301 prevsize = size; 00302 } 00303 00304 return sela; 00305 } 00306 00307 00308 /*! 00309 * selaAddCrossJunctions() 00310 * 00311 * Input: sela (<optional>) 00312 * hlsize (length of each line of hits from origin) 00313 * mdist (distance of misses from the origin) 00314 * norient (number of orientations; max of 8) 00315 * debugflag (1 for debug output) 00316 * Return: sela with additional sels, or null on error 00317 * 00318 * Notes: 00319 * (1) Adds hitmiss Sels for the intersection of two lines. 00320 * If the lines are very thin, they must be nearly orthogonal 00321 * to register. 00322 * (2) The number of Sels generated is equal to @norient. 00323 * (3) If @norient == 2, this generates 2 Sels of crosses, each with 00324 * two perpendicular lines of hits. One Sel has horizontal and 00325 * vertical hits; the other has hits along lines at +-45 degrees. 00326 * Likewise, if @norient == 3, this generates 3 Sels of crosses 00327 * oriented at 30 degrees with each other. 00328 * (4) It is suggested that @hlsize be chosen at least 1 greater 00329 * than @mdist. Try values of (@hlsize, @mdist) such as 00330 * (6,5), (7,6), (8,7), (9,7), etc. 00331 */ 00332 SELA * 00333 selaAddCrossJunctions(SELA *sela, 00334 l_float32 hlsize, 00335 l_float32 mdist, 00336 l_int32 norient, 00337 l_int32 debugflag) 00338 { 00339 char name[L_BUF_SIZE]; 00340 l_int32 i, j, w, xc, yc; 00341 l_float64 pi, halfpi, radincr, radang; 00342 l_float64 angle; 00343 PIX *pixc, *pixm, *pixt; 00344 PIXA *pixa; 00345 PTA *pta1, *pta2, *pta3, *pta4; 00346 SEL *sel; 00347 00348 PROCNAME("selaAddCrossJunctions"); 00349 00350 if (hlsize <= 0) 00351 return (SELA *)ERROR_PTR("hlsize not > 0", procName, NULL); 00352 if (norient < 1 || norient > 8) 00353 return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL); 00354 00355 if (!sela) { 00356 if ((sela = selaCreate(0)) == NULL) 00357 return (SELA *)ERROR_PTR("sela not made", procName, NULL); 00358 } 00359 00360 pi = 3.1415926535; 00361 halfpi = 3.1415926535 / 2.0; 00362 radincr = halfpi / (l_float64)norient; 00363 w = (l_int32)(2.2 * (L_MAX(hlsize, mdist) + 0.5)); 00364 if (w % 2 == 0) 00365 w++; 00366 xc = w / 2; 00367 yc = w / 2; 00368 00369 pixa = pixaCreate(norient); 00370 for (i = 0; i < norient; i++) { 00371 00372 /* Set the don't cares */ 00373 pixc = pixCreate(w, w, 32); 00374 pixSetAll(pixc); 00375 00376 /* Add the green lines of hits */ 00377 pixm = pixCreate(w, w, 1); 00378 radang = (l_float32)i * radincr; 00379 pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang); 00380 pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + halfpi); 00381 pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi); 00382 pta4 = generatePtaLineFromPt(xc, yc, hlsize + 1, radang + pi + halfpi); 00383 ptaJoin(pta1, pta2, 0, 0); 00384 ptaJoin(pta1, pta3, 0, 0); 00385 ptaJoin(pta1, pta4, 0, 0); 00386 pixRenderPta(pixm, pta1, L_SET_PIXELS); 00387 pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000); 00388 ptaDestroy(&pta1); 00389 ptaDestroy(&pta2); 00390 ptaDestroy(&pta3); 00391 ptaDestroy(&pta4); 00392 00393 /* Add red misses between the lines */ 00394 for (j = 0; j < 4; j++) { 00395 angle = radang + (j - 0.5) * halfpi; 00396 pixSetPixel(pixc, xc + (l_int32)(mdist * cos(angle)), 00397 yc + (l_int32)(mdist * sin(angle)), 0xff000000); 00398 } 00399 00400 /* Add dark green for origin */ 00401 pixSetPixel(pixc, xc, yc, 0x00550000); 00402 00403 /* Generate the sel */ 00404 sel = selCreateFromColorPix(pixc, NULL); 00405 sprintf(name, "sel_cross_%d", i); 00406 selaAddSel(sela, sel, name, 0); 00407 00408 if (debugflag) { 00409 pixt = pixScaleBySampling(pixc, 10.0, 10.0); 00410 pixaAddPix(pixa, pixt, L_INSERT); 00411 } 00412 pixDestroy(&pixm); 00413 pixDestroy(&pixc); 00414 } 00415 00416 if (debugflag) { 00417 l_int32 w; 00418 pixaGetPixDimensions(pixa, 0, &w, NULL, NULL); 00419 pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 1, 0, 10, 2); 00420 pixWriteTempfile("/tmp", "xsel1.png", pixt, IFF_PNG, 0); 00421 pixDisplay(pixt, 0, 100); 00422 pixDestroy(&pixt); 00423 pixt = selaDisplayInPix(sela, 15, 2, 20, 1); 00424 pixWriteTempfile("/tmp", "xsel2.png", pixt, IFF_PNG, 0); 00425 pixDisplay(pixt, 500, 100); 00426 pixDestroy(&pixt); 00427 selaWriteStream(stderr, sela); 00428 } 00429 pixaDestroy(&pixa); 00430 00431 return sela; 00432 } 00433 00434 00435 /*! 00436 * selaAddTJunctions() 00437 * 00438 * Input: sela (<optional>) 00439 * hlsize (length of each line of hits from origin) 00440 * mdist (distance of misses from the origin) 00441 * norient (number of orientations; max of 8) 00442 * debugflag (1 for debug output) 00443 * Return: sela with additional sels, or null on error 00444 * 00445 * Notes: 00446 * (1) Adds hitmiss Sels for the T-junction of two lines. 00447 * If the lines are very thin, they must be nearly orthogonal 00448 * to register. 00449 * (2) The number of Sels generated is 4 * @norient. 00450 * (3) It is suggested that @hlsize be chosen at least 1 greater 00451 * than @mdist. Try values of (@hlsize, @mdist) such as 00452 * (6,5), (7,6), (8,7), (9,7), etc. 00453 */ 00454 SELA * 00455 selaAddTJunctions(SELA *sela, 00456 l_float32 hlsize, 00457 l_float32 mdist, 00458 l_int32 norient, 00459 l_int32 debugflag) 00460 { 00461 char name[L_BUF_SIZE]; 00462 l_int32 i, j, k, w, xc, yc; 00463 l_float64 pi, halfpi, radincr, jang, radang; 00464 l_float64 angle[3], dist[3]; 00465 PIX *pixc, *pixm, *pixt; 00466 PIXA *pixa; 00467 PTA *pta1, *pta2, *pta3; 00468 SEL *sel; 00469 00470 PROCNAME("selaAddTJunctions"); 00471 00472 if (hlsize <= 2) 00473 return (SELA *)ERROR_PTR("hlsizel not > 1", procName, NULL); 00474 if (norient < 1 || norient > 8) 00475 return (SELA *)ERROR_PTR("norient not in [1, ... 8]", procName, NULL); 00476 00477 if (!sela) { 00478 if ((sela = selaCreate(0)) == NULL) 00479 return (SELA *)ERROR_PTR("sela not made", procName, NULL); 00480 } 00481 00482 pi = 3.1415926535; 00483 halfpi = 3.1415926535 / 2.0; 00484 radincr = halfpi / (l_float32)norient; 00485 w = (l_int32)(2.4 * (L_MAX(hlsize, mdist) + 0.5)); 00486 if (w % 2 == 0) 00487 w++; 00488 xc = w / 2; 00489 yc = w / 2; 00490 00491 pixa = pixaCreate(4 * norient); 00492 for (i = 0; i < norient; i++) { 00493 for (j = 0; j < 4; j++) { /* 4 orthogonal orientations */ 00494 jang = (l_float32)j * halfpi; 00495 00496 /* Set the don't cares */ 00497 pixc = pixCreate(w, w, 32); 00498 pixSetAll(pixc); 00499 00500 /* Add the green lines of hits */ 00501 pixm = pixCreate(w, w, 1); 00502 radang = (l_float32)i * radincr; 00503 pta1 = generatePtaLineFromPt(xc, yc, hlsize + 1, jang + radang); 00504 pta2 = generatePtaLineFromPt(xc, yc, hlsize + 1, 00505 jang + radang + halfpi); 00506 pta3 = generatePtaLineFromPt(xc, yc, hlsize + 1, 00507 jang + radang + pi); 00508 ptaJoin(pta1, pta2, 0, 0); 00509 ptaJoin(pta1, pta3, 0, 0); 00510 pixRenderPta(pixm, pta1, L_SET_PIXELS); 00511 pixPaintThroughMask(pixc, pixm, 0, 0, 0x00ff0000); 00512 ptaDestroy(&pta1); 00513 ptaDestroy(&pta2); 00514 ptaDestroy(&pta3); 00515 00516 /* Add red misses between the lines */ 00517 angle[0] = radang + jang - halfpi; 00518 angle[1] = radang + jang + 0.5 * halfpi; 00519 angle[2] = radang + jang + 1.5 * halfpi; 00520 dist[0] = 0.8 * mdist; 00521 dist[1] = dist[2] = mdist; 00522 for (k = 0; k < 3; k++) { 00523 pixSetPixel(pixc, xc + (l_int32)(dist[k] * cos(angle[k])), 00524 yc + (l_int32)(dist[k] * sin(angle[k])), 00525 0xff000000); 00526 } 00527 00528 /* Add dark green for origin */ 00529 pixSetPixel(pixc, xc, yc, 0x00550000); 00530 00531 /* Generate the sel */ 00532 sel = selCreateFromColorPix(pixc, NULL); 00533 sprintf(name, "sel_cross_%d", 4 * i + j); 00534 selaAddSel(sela, sel, name, 0); 00535 00536 if (debugflag) { 00537 pixt = pixScaleBySampling(pixc, 10.0, 10.0); 00538 pixaAddPix(pixa, pixt, L_INSERT); 00539 } 00540 pixDestroy(&pixm); 00541 pixDestroy(&pixc); 00542 } 00543 } 00544 00545 if (debugflag) { 00546 l_int32 w; 00547 pixaGetPixDimensions(pixa, 0, &w, NULL, NULL); 00548 pixt = pixaDisplayTiledAndScaled(pixa, 32, w, 4, 0, 10, 2); 00549 pixWriteTempfile("/tmp", "tsel1.png", pixt, IFF_PNG, 0); 00550 pixDisplay(pixt, 0, 100); 00551 pixDestroy(&pixt); 00552 pixt = selaDisplayInPix(sela, 15, 2, 20, 4); 00553 pixWriteTempfile("/tmp", "tsel2.png", pixt, IFF_PNG, 0); 00554 pixDisplay(pixt, 500, 100); 00555 pixDestroy(&pixt); 00556 selaWriteStream(stderr, sela); 00557 } 00558 pixaDestroy(&pixa); 00559 00560 return sela; 00561 } 00562