/* Splits a PGM image of N fragments into N separate images. */ /* Last edited on 2015-01-20 16:48:19 by stolfilocal */ #include #include #include #include TYPE Options = struct ??? { char *inFile; /* Input image name, without the ".pgm" extension */ char *outPrefix; /* Output image name prefix, without the ".pgm" extension */ unsigned startNum; /* First fragment number */ unsigned black; /* Max "black" intensity value [0..254] */ } ???; IntPoint == i2_t; Pixel = struct ??? { IntPoint pos; pz_gray_pixel_t level; } ???; Pixels == ARRAY OF Pixel; int main(int argc, char **argv ) VAR image : REF pz_image_t; { { /* with */ ??? o = pz_get_options(int argc, char **argv); /* do */ image = pz_image_read_pgm(o.inFile); SplitPuzzle(o.outPrefix, o.startNum, image^, o.black); fprintf(stderr, " ok !! \n"); }; } /* Main */ void SplitPuzzle( char *outPrefix, unsigned startNum, pz_image_t *M, unsigned black ) /* Gets a PGM image "M" of a puzzle, identifies the pieces, and writes each piece to a separate file "outPrefix-0001.pgm", "outPrefix-0002.pgm", etc. The "inside" of a piece is assumed to consist of all pixels with value greater than "black". The "boundary" of a piece consists of all outside pixels that are 4-adjacent to an inside pixel. In the output files, the inside and boundary pixels are copied from the original image, while the remaining outside pixels are set to "black". */ CONST SmallImage == 100; /* Ignore pieces with this perimeter or less */ VAR cont: unsigned = startNum; newImage : REF pz_image_t; rimg: REF Pixels; { { /* with */ ??? NY = (M.ne); ??? NX = (M[0].ne); /* do */ rimg = NEW(REF Pixels, (NX DIV 10) * (NY DIV 10) + 1); void GetPixel( y,x :unsigned ) { if (( f >= (rimg^.ne) )){ { /* with */ ??? nimg = NEW(REF Pixels, 2*f); /* do */ SUBARRAY(nimg^,0,f) = SUBARRAY(rimg^,0,f); rimg = nimg; ; };; }; rimg[f].pos = IntPoint{x, y}; rimg[f].level = M[y,x]; M[y,x] = 0; } /* GetPixel */ void FindNeighbourhood( ) /* Given a pixel with coordinates "(x,y)" inside some piece of the puzzle "M", finds all pixels that are connected to it (in the 4-neighbor topology). Those pixels are copied into the array "img" starting at index "n", and then set to "black". A pixel is assumed to be inside if its value is greater than "black". */ { while ( s < f ){ { /* with */ ??? x = rimg[s].pos[0]; ??? y = rimg[s].pos[1]; /* do */ if (( y > 0 )){ if (( (M[y-1,x] > black) )){ GetPixel(y-1,x); f++ ;};; }; if (( x > 0 )){ if (( (M[y,x-1] > black) )){ GetPixel(y,x-1); f++ ;};; }; if (( y < NY-1 )){ if (( (M[y+1,x] > black) )){ GetPixel(y+1,x); f++ ;}; ; }; if (( x < NX-1 )){ if (( (M[y,x+1] > black) )){ GetPixel(y,x+1); f++ ;};; };; }; s++;; }; } /* FindNeighbourhood */ { for (y = 0; y <= NY-1 ; y++){ for (x = 0; x <= NX-1 ; x++){ if (( M[y,x] > black )){ f = 0; s = 0; GetPixel(y,x); f++; FindNeighbourhood(); if (( f > SmallImage )){ newImage = CreateImage(M, SUBARRAY(rimg^, 0, f)); SavePatchMatrix(outPrefix, cont, newImage^); cont = cont+1;; }; } ; }; }; }; } } /* SplitPuzzle */ void SavePatchMatrix( char *fname, unsigned cont, pz_image_t *img ) { /* Writes an image with the puzzle piece stored in "img". */ { /* with */ ??? name = fname & "-" & Fmt.Pad(Fmt.Int(cont), 4, '0'); /* do */ fprintf(stderr, name); fprintf(stderr, "\n"); pz_image_write_pgm(name, img); } } /* SavePatchMatrix */ pz_image_t *CreateImage( pz_image_t *M, Pixels *img ) VAR x, y: unsigned; minX, maxX, minY, maxY : unsigned; void Transformxy( unsigned *x, unsigned *y, xi,yi : unsigned ) { x = xi - minX + 1; y = yi - minY + 1 } /* Transformxy */ { FindMinMax(img, minX, maxX, minY, maxY); { /* with */ ??? NX = maxX - minX + 3; ??? NY = maxY - minY + 3; ??? rp = pz_image_new(NY, NX); ??? p = rp^; /* do */ for (y = 0; y <= NY-1 ; y++){ for (x = 0; x <= NX-1 ; x++){ p[y,x] = 0; }; }; for (i = 0; i < (img.ne ) ; i++){ { /* with */ ??? pos = img[i].pos; ??? xp = pos[0]; ??? yp = pos[1]; /* do */ Transformxy(x, y, xp, yp); p[y, x] = img[i].level; if (( yp > 0 )){ if (( M[yp-1,xp] > 0 )){ p[y-1,x] = M[yp-1,xp];; } ; }; if (( xp > 0 )){ if (( M[yp,xp-1] > 0 )){ p[y, x-1] = M[yp,xp-1];; } ; }; if (( yp < (M.ne - 1) )){ if (( M[yp+1,xp] > 0 )){ p[y+1,x] = M[yp+1,xp];; } ; }; if (( xp < (M[0].ne - 1) )){ if (( M[yp,xp+1] > 0 )){ p[y,x+1] = M[yp,xp+1];; } ; }; }; }; return rp; } } /* CreateImage */ void FindMinMax( Pixels *img, unsigned *minX, unsigned *maxX, unsigned *minY, unsigned *maxY ) { minX = img[0].pos[0]; maxX = img[0].pos[0]; minY = img[0].pos[1]; maxY = img[0].pos[1]; for (i = 1; i < (img.ne ) ; i++){ if (( minX > img[i].pos[0] )){ minX = img[i].pos[0] ;}; if (( minY > img[i].pos[1] )){ minY = img[i].pos[1] ;}; if (( maxX < img[i].pos[0] )){ maxX = img[i].pos[0] ;}; if (( maxY < img[i].pos[1] )){ maxY = img[i].pos[1] ;};; } } /* FindMinMax */ Options pz_get_options(int argc, char **argv ) VAR o: Options; { argparser_t *pp = argparser_new(stderr, argc, argv); argparser_set_help(pp, PROG_NAME " version " PROG_VERS ", usage:\n" PROG_HELP); argparser_set_info(pp, PROG_INFO); argparser_process_help_info_options(pp); { /* with */ /* do */ TRY argparser_get_keyword(pp, "-inFile"); o.inFile = argparser_get_next(pp); if (( argparser_keyword_present(pp, "-outPrefix") )){ o.outPrefix = argparser_get_next(pp) }else{ o.outPrefix = o.inFile; }; if (( argparser_keyword_present(pp, "-startNum") )){ o.startNum = argparser_get_next_int(pp, 0, (unsigned.ne - 1)) }else{ o.startNum = 0; }; argparser_get_keyword(pp, "-black"); o.black = argparser_get_next_int(pp, 0, 254); argparser_finish(pp); EXCEPT | ParseParams.Error ==> fprintf(stderr, "Usage: pz_split \\\n"); fprintf(stderr, " -inFile \\\n"); fprintf(stderr, " [ -outPrefix ] [ -startNum ] \\\n"); fprintf(stderr, " -black \n"); Process.Exit(1);; };; }; return o } /* GetOptions */ { /* Copyright © 2001 Universidade Estadual de Campinas (UNICAMP). Authors: Helena C. G. Leitão and Jorge Stolfi. This file can be freely distributed, used, and modified, provided that this copyright and authorship notice is preserved, and that any modified versions are clearly marked as such. This software has NO WARRANTY of correctness or applicability for any purpose. Neither the authors nor their employers chall be held responsible for any losses or damages that may result from its use. */