Hi .... I am writing (or rather have substantially written) a program in
Java to take a scanned page of stamps and attempt to create subimages of the stamps (and allow me to quickly save them in certain directories with particular names). I am struggling a little bit to come up with the right algorithm to "box off" the stamp images that I need to crop. I just need the rectangular bounding boxes so I can present these in my interface, make any changes and proceed in the application to burst them into subimages. An example image is here (warning it is a 50Mb image): http://stamps.drakeserver.com/scan005.jpg Though investigation I found ImageJ. One thing I have managed to use ImageJ for is to convert the image to binary format (and filter with a threshold). This gives me a working image (obviously my cropping will occur from the original) that is easier to deal with. I may also use their image object instead of BufferedImages as these are memory hogs: Here is the filtered image: http://stamps.drakeserver.com/scan005-5.jpg My current algorthim is quite dum.... I start in the top left and proceed on a forty-five degree angle toward the bottom right. As soon as a catch a color change I mark it and attempt to achieve a 10 pixel threshold. At this occurance, I will try and find the top left corner of a stamp, and conversely attempt to find the lower right corner. Since they are in rows, I will move to the right and attempt the same thing for stamps to the right (if I hit the edge I go to next row). I keep track of the lowest "y" value and use that for my next row. The perforations make this tricky. The algorithm is only ~ 80% efficient and struggles when I come into gaps (ie. stamps I have removed) I also can skip rows if there are not stamps in the first couple slots on the left..... Another thought I had was to start top right and simply scan to the right. As soon as I hit multiple "white" pixels (say 10) I start to determine if there is an area under them (ie. it isn't simply a reflection line but represents a stamp shape). I proceed down the rows until I hit matches. My background is engineering and computer science (but not graphics focussed) so I am not particularly up-to-speed with algorithms for this type of thing. I would welcome any input on how to computationally solve this. It will drastically save me time in scannign and cataloguing my collection (although I have to admit the time I have put into my program could've better been used on my hobby and just use Gimp, but well..... the computer scientist in me loves to tinker. -Jason |
jason,
I thgink you can what you want using existing ImageJ menu function and a macro without doing any pixel crunching algorithm development yourself. You may/will need to furthur preprocess your image by using Process/Binary/Make Binary and Process/Binary/Fill Holes. This converts the stamps to a bunch of solid white rectangular objects (or Particles). Then, do Analyze/Set Measurements and select Area, Bounding Box. and I think Shape Descriptors (this will get aspect ratio). Now run Analyze/Analyze Particles. You will get the selected properties including the Bounding Box spec in a Results Table. You may want to write some macro code to eliminate objects that are to small (area) or to "skinny" (aspect ratio). This can be done using built in macro functions to get Column/row data from the table and to delete rows as needed. David Webster On Fri, Jul 29, 2011 at 3:14 PM, Jason Drake <[hidden email]> wrote: > Hi .... I am writing (or rather have substantially written) a program in > Java to take a scanned page of stamps and attempt to create subimages of > the > stamps (and allow me to quickly save them in certain directories with > particular names). > > I am struggling a little bit to come up with the right algorithm to "box > off" the stamp images that I need to crop. I just need the rectangular > bounding boxes so I can present these in my interface, make any changes and > proceed in the application to burst them into subimages. > > An example image is here (warning it is a 50Mb image): > http://stamps.drakeserver.com/scan005.jpg > > Though investigation I found ImageJ. One thing I have managed to use > ImageJ > for is to convert the image to binary format (and filter with a threshold). > This gives me a working image (obviously my cropping will occur from the > original) that is easier to deal with. I may also use their image object > instead of BufferedImages as these are memory hogs: > > Here is the filtered image: http://stamps.drakeserver.com/scan005-5.jpg > > My current algorthim is quite dum.... I start in the top left and proceed > on > a forty-five degree angle toward the bottom right. As soon as a catch a > color change I mark it and attempt to achieve a 10 pixel threshold. At > this > occurance, I will try and find the top left corner of a stamp, and > conversely attempt to find the lower right corner. Since they are in rows, > I > will move to the right and attempt the same thing for stamps to the right > (if I hit the edge I go to next row). I keep track of the lowest "y" value > and use that for my next row. The perforations make this tricky. The > algorithm is only ~ 80% efficient and struggles when I come into gaps (ie. > stamps I have removed) I also can skip rows if there are not stamps in the > first couple slots on the left..... > > Another thought I had was to start top right and simply scan to the right. > As soon as I hit multiple "white" pixels (say 10) I start to determine if > there is an area under them (ie. it isn't simply a reflection line but > represents a stamp shape). I proceed down the rows until I hit matches. > > My background is engineering and computer science (but not graphics > focussed) so I am not particularly up-to-speed with algorithms for this > type > of thing. I would welcome any input on how to computationally solve this. > It will drastically save me time in scannign and cataloguing my collection > (although I have to admit the time I have put into my program could've > better been used on my hobby and just use Gimp, but well..... the computer > scientist in me loves to tinker. > > -Jason > |
In reply to this post by jadrake75
On Friday 29 Jul 2011, you wrote:
> Though investigation I found ImageJ. One thing I have managed to use > ImageJ for is to convert the image to binary format (and filter with a > threshold). This gives me a working image (obviously my cropping will > occur from the original) that is easier to deal with. I may also use > their image object instead of BufferedImages as these are memory hogs: > > Here is the filtered image: http://stamps.drakeserver.com/scan005-5.jpg Interesting problem. This is the way I would do it: Download the Morphology collection from here: http://www.dentistry.bham.ac.uk/landinig/software/software.html and expand in the Plugins folder. Once you have your image binarised as above: Fill the holes (Process>Binary>Fill Holes Then get rid of small noise remains with Plugins>Morphology>BinaryFilterReconstruct and try let's say 5 or more erosions, depending on the size of the noise particles You should now have an image with the profiles of the stamps only. Then apply the Particles8 plugin to the binary image and tick (important) the Morphological parameters option. This generates a table that has among other things the coordinates of the corners of the ROI (aligned to the image border) that bounds each object: the rectangle is defined by the corners (ROIX1, ROIY1) and (ROIX2, ROIY2). You could (now working on the original colour image) write a macro to go through the Results Table line by line (that is 1 particle at a time) and create a rectangular ROI using those coordinates to then Crop the image, reduce it and save it. In the same Morphology collection there is a macro called Catalogue Particles that does something similar to the above but not quite what you are looking for (the catalogue stack has the size of the largest object). Just make sure that when running it on the binary image, to choose the option to "redirect" to the colour version of the image, otherwise you get a catalogue of binary objects. Maybe this helps you to get started to modify the macro to save a reduced image rather than making the stack and montage. I set IJ to use white as the foreground and black as the background and I have not tested that macro on a "default" IJ setting. If you do not get the expected results you might try again using my StartupMacros file which is here and sets IJ exactly the way I have set it up (just make sure that before overwriting the file (which resides in the /macros folder) you save a backup to revert to the original state if you want to). My file is here: http://www.dentistry.bham.ac.uk/landinig/software/StartupMacros.txt If you succeed with a macro that does what you are looking for, please consider sharing it with the IJ community. Cheers Gabriel |
In reply to this post by David Webster
Thanks to everyone who provided feedback on the ideas.
Using David's result below actually worked like a charm. I need to go back and try some of the previous suggestions based on what I know now but this really worked for me - I realize I was using "fill holes" incorrectly. I now realize fill holes means "fill the areas within a bounding region" and not fill the edge holes (ie. the perforations - heh I am a stamp guy!). When I was running it was I doing an inverse bit mask (such that white became black and black become white) so when I ran fill holes... I got a black page! I have figured it out now. This looks like it will provide me with pretty close bounding boxes (with the exception of the skinny/abnomolies) which as suggested I should be able to remove from the result set by simply checking the area exceeds 10000+. Actually I found that when using the Analyze Particles, if I set the size^2 of 10000 to infinity this gets rid of all the small boundings (based on my scan sizes it is unlikely I'll ever scan a stamp less thant 10K sq pixels). Now it is just a matter of plugging in this via the APIs of the library (duplicating the manual user-interface actions). I can then extract the remaining bounding boxes add a padding (~ 10-15 pixels around) and display them in my user interface to allow me to make any small "tweaks" I may have API questions if I get bogged down, but given my Java experience/expertise this shouldn't be an issue. For me it was the theory and transformations I was not familiar with. Web devleopment, user-interfaces, encoding or databases -- not a problem. Cheers -Jason -Jason On Sat, Jul 30, 2011 at 12:36 AM, David Webster <[hidden email]>wrote: > jason, > > I thgink you can what you want using existing ImageJ menu function and a > macro without doing any pixel crunching algorithm development yourself. > > You may/will need to furthur preprocess your image by using > Process/Binary/Make Binary and Process/Binary/Fill Holes. This converts the > stamps to a bunch of solid white rectangular objects (or Particles). > > Then, do Analyze/Set Measurements and select Area, Bounding Box. and I > think > Shape Descriptors (this will get aspect ratio). > > Now run Analyze/Analyze Particles. You will get the selected properties > including the Bounding Box spec in a Results Table. You may want to write > some macro code to eliminate objects that are to small (area) or to > "skinny" > (aspect ratio). This can be done using built in macro functions to get > Column/row data from the table and to delete rows as needed. > > > David Webster > > On Fri, Jul 29, 2011 at 3:14 PM, Jason Drake <[hidden email]> wrote: > > > Hi .... I am writing (or rather have substantially written) a program in > > Java to take a scanned page of stamps and attempt to create subimages of > > the > > stamps (and allow me to quickly save them in certain directories with > > particular names). > > > > I am struggling a little bit to come up with the right algorithm to "box > > off" the stamp images that I need to crop. I just need the rectangular > > bounding boxes so I can present these in my interface, make any changes > and > > proceed in the application to burst them into subimages. > > > > An example image is here (warning it is a 50Mb image): > > http://stamps.drakeserver.com/scan005.jpg > > > > Though investigation I found ImageJ. One thing I have managed to use > > ImageJ > > for is to convert the image to binary format (and filter with a > threshold). > > This gives me a working image (obviously my cropping will occur from the > > original) that is easier to deal with. I may also use their image object > > instead of BufferedImages as these are memory hogs: > > > > Here is the filtered image: http://stamps.drakeserver.com/scan005-5.jpg > > > > My current algorthim is quite dum.... I start in the top left and proceed > > on > > a forty-five degree angle toward the bottom right. As soon as a catch a > > color change I mark it and attempt to achieve a 10 pixel threshold. At > > this > > occurance, I will try and find the top left corner of a stamp, and > > conversely attempt to find the lower right corner. Since they are in > rows, > > I > > will move to the right and attempt the same thing for stamps to the right > > (if I hit the edge I go to next row). I keep track of the lowest "y" > value > > and use that for my next row. The perforations make this tricky. The > > algorithm is only ~ 80% efficient and struggles when I come into gaps > (ie. > > stamps I have removed) I also can skip rows if there are not stamps in > the > > first couple slots on the left..... > > > > Another thought I had was to start top right and simply scan to the > right. > > As soon as I hit multiple "white" pixels (say 10) I start to determine if > > there is an area under them (ie. it isn't simply a reflection line but > > represents a stamp shape). I proceed down the rows until I hit matches. > > > > My background is engineering and computer science (but not graphics > > focussed) so I am not particularly up-to-speed with algorithms for this > > type > > of thing. I would welcome any input on how to computationally solve > this. > > It will drastically save me time in scannign and cataloguing my > collection > > (although I have to admit the time I have put into my program could've > > better been used on my hobby and just use Gimp, but well..... the > computer > > scientist in me loves to tinker. > > > > -Jason > > > |
Jason,
Whoops, I forgot to mention that you can use Plugins/Macros/Recorder.. to record manually selected menu functions and convert them to an ImageJ macro, Javascript, or plugin without fooling around with Java or the API. David On Sat, Jul 30, 2011 at 12:20 PM, Jason Drake <[hidden email]> wrote: > Thanks to everyone who provided feedback on the ideas. > > Using David's result below actually worked like a charm. I need to go back > and try some of the previous suggestions based on what I know now but this > really worked for me - I realize I was using "fill holes" incorrectly. I > now realize fill holes means "fill the areas within a bounding region" and > not fill the edge holes (ie. the perforations - heh I am a stamp guy!). > When I was running it was I doing an inverse bit mask (such that white > became black and black become white) so when I ran fill holes... I got a > black page! I have figured it out now. > > This looks like it will provide me with pretty close bounding boxes (with > the exception of the skinny/abnomolies) which as suggested I should be able > to remove from the result set by simply checking the area exceeds 10000+. > Actually I found that when using the Analyze Particles, if I set the > size^2 > of 10000 to infinity this gets rid of all the small boundings (based on my > scan sizes it is unlikely I'll ever scan a stamp less thant 10K sq pixels). > > Now it is just a matter of plugging in this via the APIs of the library > (duplicating the manual user-interface actions). I can then extract the > remaining bounding boxes add a padding (~ 10-15 pixels around) and display > them in my user interface to allow me to make any small "tweaks" > > I may have API questions if I get bogged down, but given my Java > experience/expertise this shouldn't be an issue. For me it was the theory > and transformations I was not familiar with. Web devleopment, > user-interfaces, encoding or databases -- not a problem. > > Cheers > > -Jason > > > > -Jason > > > > > On Sat, Jul 30, 2011 at 12:36 AM, David Webster <[hidden email] > >wrote: > > > jason, > > > > I thgink you can what you want using existing ImageJ menu function and a > > macro without doing any pixel crunching algorithm development yourself. > > > > You may/will need to furthur preprocess your image by using > > Process/Binary/Make Binary and Process/Binary/Fill Holes. This converts > the > > stamps to a bunch of solid white rectangular objects (or Particles). > > > > Then, do Analyze/Set Measurements and select Area, Bounding Box. and I > > think > > Shape Descriptors (this will get aspect ratio). > > > > Now run Analyze/Analyze Particles. You will get the selected properties > > including the Bounding Box spec in a Results Table. You may want to write > > some macro code to eliminate objects that are to small (area) or to > > "skinny" > > (aspect ratio). This can be done using built in macro functions to get > > Column/row data from the table and to delete rows as needed. > > > > > > David Webster > > > > On Fri, Jul 29, 2011 at 3:14 PM, Jason Drake <[hidden email]> > wrote: > > > > > Hi .... I am writing (or rather have substantially written) a program > in > > > Java to take a scanned page of stamps and attempt to create subimages > of > > > the > > > stamps (and allow me to quickly save them in certain directories with > > > particular names). > > > > > > I am struggling a little bit to come up with the right algorithm to > "box > > > off" the stamp images that I need to crop. I just need the rectangular > > > bounding boxes so I can present these in my interface, make any changes > > and > > > proceed in the application to burst them into subimages. > > > > > > An example image is here (warning it is a 50Mb image): > > > http://stamps.drakeserver.com/scan005.jpg > > > > > > Though investigation I found ImageJ. One thing I have managed to use > > > ImageJ > > > for is to convert the image to binary format (and filter with a > > threshold). > > > This gives me a working image (obviously my cropping will occur from > the > > > original) that is easier to deal with. I may also use their image > object > > > instead of BufferedImages as these are memory hogs: > > > > > > Here is the filtered image: > http://stamps.drakeserver.com/scan005-5.jpg > > > > > > My current algorthim is quite dum.... I start in the top left and > proceed > > > on > > > a forty-five degree angle toward the bottom right. As soon as a catch > a > > > color change I mark it and attempt to achieve a 10 pixel threshold. At > > > this > > > occurance, I will try and find the top left corner of a stamp, and > > > conversely attempt to find the lower right corner. Since they are in > > rows, > > > I > > > will move to the right and attempt the same thing for stamps to the > right > > > (if I hit the edge I go to next row). I keep track of the lowest "y" > > value > > > and use that for my next row. The perforations make this tricky. The > > > algorithm is only ~ 80% efficient and struggles when I come into gaps > > (ie. > > > stamps I have removed) I also can skip rows if there are not stamps in > > the > > > first couple slots on the left..... > > > > > > Another thought I had was to start top right and simply scan to the > > right. > > > As soon as I hit multiple "white" pixels (say 10) I start to determine > if > > > there is an area under them (ie. it isn't simply a reflection line but > > > represents a stamp shape). I proceed down the rows until I hit matches. > > > > > > My background is engineering and computer science (but not graphics > > > focussed) so I am not particularly up-to-speed with algorithms for this > > > type > > > of thing. I would welcome any input on how to computationally solve > > this. > > > It will drastically save me time in scannign and cataloguing my > > collection > > > (although I have to admit the time I have put into my program could've > > > better been used on my hobby and just use Gimp, but well..... the > > computer > > > scientist in me loves to tinker. > > > > > > -Jason > > > > > > |
In reply to this post by jadrake75
Jason,
You can also filter out long skinny things using the aspect ratio (AR column) computed by Analyze Particles... Just go to Set Measurements and click the Shape Descriptors button. Then you can filter your results table twice,, once for AR and other for size. If there is any other way I can help, email directly at [hidden email]. I always liuke to see application of ImageJ to non biomedical problems, David On Sat, Jul 30, 2011 at 12:20 PM, Jason Drake <[hidden email]> wrote: > Thanks to everyone who provided feedback on the ideas. > > Using David's result below actually worked like a charm. I need to go back > and try some of the previous suggestions based on what I know now but this > really worked for me - I realize I was using "fill holes" incorrectly. I > now realize fill holes means "fill the areas within a bounding region" and > not fill the edge holes (ie. the perforations - heh I am a stamp guy!). > When I was running it was I doing an inverse bit mask (such that white > became black and black become white) so when I ran fill holes... I got a > black page! I have figured it out now. > > This looks like it will provide me with pretty close bounding boxes (with > the exception of the skinny/abnomolies) which as suggested I should be able > to remove from the result set by simply checking the area exceeds 10000+. > Actually I found that when using the Analyze Particles, if I set the > size^2 > of 10000 to infinity this gets rid of all the small boundings (based on my > scan sizes it is unlikely I'll ever scan a stamp less thant 10K sq pixels). > > Now it is just a matter of plugging in this via the APIs of the library > (duplicating the manual user-interface actions). I can then extract the > remaining bounding boxes add a padding (~ 10-15 pixels around) and display > them in my user interface to allow me to make any small "tweaks" > > I may have API questions if I get bogged down, but given my Java > experience/expertise this shouldn't be an issue. For me it was the theory > and transformations I was not familiar with. Web devleopment, > user-interfaces, encoding or databases -- not a problem. > > Cheers > > -Jason > > > > -Jason > > > > > On Sat, Jul 30, 2011 at 12:36 AM, David Webster <[hidden email] > >wrote: > > > jason, > > > > I thgink you can what you want using existing ImageJ menu function and a > > macro without doing any pixel crunching algorithm development yourself. > > > > You may/will need to furthur preprocess your image by using > > Process/Binary/Make Binary and Process/Binary/Fill Holes. This converts > the > > stamps to a bunch of solid white rectangular objects (or Particles). > > > > Then, do Analyze/Set Measurements and select Area, Bounding Box. and I > > think > > Shape Descriptors (this will get aspect ratio). > > > > Now run Analyze/Analyze Particles. You will get the selected properties > > including the Bounding Box spec in a Results Table. You may want to write > > some macro code to eliminate objects that are to small (area) or to > > "skinny" > > (aspect ratio). This can be done using built in macro functions to get > > Column/row data from the table and to delete rows as needed. > > > > > > David Webster > > > > On Fri, Jul 29, 2011 at 3:14 PM, Jason Drake <[hidden email]> > wrote: > > > > > Hi .... I am writing (or rather have substantially written) a program > in > > > Java to take a scanned page of stamps and attempt to create subimages > of > > > the > > > stamps (and allow me to quickly save them in certain directories with > > > particular names). > > > > > > I am struggling a little bit to come up with the right algorithm to > "box > > > off" the stamp images that I need to crop. I just need the rectangular > > > bounding boxes so I can present these in my interface, make any changes > > and > > > proceed in the application to burst them into subimages. > > > > > > An example image is here (warning it is a 50Mb image): > > > http://stamps.drakeserver.com/scan005.jpg > > > > > > Though investigation I found ImageJ. One thing I have managed to use > > > ImageJ > > > for is to convert the image to binary format (and filter with a > > threshold). > > > This gives me a working image (obviously my cropping will occur from > the > > > original) that is easier to deal with. I may also use their image > object > > > instead of BufferedImages as these are memory hogs: > > > > > > Here is the filtered image: > http://stamps.drakeserver.com/scan005-5.jpg > > > > > > My current algorthim is quite dum.... I start in the top left and > proceed > > > on > > > a forty-five degree angle toward the bottom right. As soon as a catch > a > > > color change I mark it and attempt to achieve a 10 pixel threshold. At > > > this > > > occurance, I will try and find the top left corner of a stamp, and > > > conversely attempt to find the lower right corner. Since they are in > > rows, > > > I > > > will move to the right and attempt the same thing for stamps to the > right > > > (if I hit the edge I go to next row). I keep track of the lowest "y" > > value > > > and use that for my next row. The perforations make this tricky. The > > > algorithm is only ~ 80% efficient and struggles when I come into gaps > > (ie. > > > stamps I have removed) I also can skip rows if there are not stamps in > > the > > > first couple slots on the left..... > > > > > > Another thought I had was to start top right and simply scan to the > > right. > > > As soon as I hit multiple "white" pixels (say 10) I start to determine > if > > > there is an area under them (ie. it isn't simply a reflection line but > > > represents a stamp shape). I proceed down the rows until I hit matches. > > > > > > My background is engineering and computer science (but not graphics > > > focussed) so I am not particularly up-to-speed with algorithms for this > > > type > > > of thing. I would welcome any input on how to computationally solve > > this. > > > It will drastically save me time in scannign and cataloguing my > > collection > > > (although I have to admit the time I have put into my program could've > > > better been used on my hobby and just use Gimp, but well..... the > > computer > > > scientist in me loves to tinker. > > > > > > -Jason > > > > > > |
In reply to this post by David Webster
oh.... well - I did figure it out... Originally I wrote the java code, but
ran into a few issues with the Thresholder class since it is assuming to be run in a ImageJ application (as opposed to as a library - it gets it's image from the WindowManager instead of accepting one). After the macro suggestion I did some reading and here is what I came up with... ImagePlus the_image = new ImagePlus("imported image...", bufferedImage); IJ.run(the_image, "8-bit", ""); IJ.run(the_image,"Make Binary", ""); IJ.run(the_image,"Fill Holes", ""); IJ.run(the_image,"Despeckle", ""); // probably not needed given the results IJ.run(the_image,"Set Measurements...", "area bounding redirect=None decimal=3"); // IJ.run(the_image,"Analyze Particles...", "size=10000-Infinity circularity=0.00-1.00 show=Nothing exclude clear"); ResultsTable table = new ResultsTable(); ParticleAnalyzer partAnalyzer = new ParticleAnalyzer(ParticleAnalyzer.EXCLUDE_EDGE_PARTICLES + ParticleAnalyzer.SHOW_NONE, Measurements.AREA + Measurements.RECT,table,10000.0,Double.MAX_VALUE,0.0, 1.0); partAnalyzer.analyze(the_image, the_image.getProcessor()); int total = table.getCounter(); List<Rectangle> rectangle = new ArrayList<Rectangle>(); for(int row = 0 ; row < total; row++ ) { Rectangle r = new Rectangle(); r.x = Math.max(0,Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_X,row)).intValue() - IMAGE_PADDING); r.y = Math.max(0, Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_Y, row)).intValue() - IMAGE_PADDING); r.width = Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_WIDTH, row)).intValue() + (2*IMAGE_PADDING); r.height = Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_HEIGHT,row)).intValue() + (2*IMAGE_PADDING); if( r.width > MIN_SIZE && r.height > MIN_SIZE ) { // MIN_SIZE is 100 - will filter skinny areas rectangle.add(r); } } return rectangle; I needed a way to get the results table and I didn't see a way to do it with IJ.run( ) stuff. Since I had this working with full fledged APIs I figured I could just use what I had, build a resultsTable and pass it into my ParticlAnalyzer. Seems to work. Never a big fan of calling static "run()" APIs but this seems to work. -Jason On Sat, Jul 30, 2011 at 8:53 PM, David Webster <[hidden email]>wrote: > Jason, > > Whoops, I forgot to mention that you can use Plugins/Macros/Recorder.. to > record manually selected menu functions and convert them to an ImageJ > macro, > Javascript, or plugin without fooling around with Java or the API. > > David > > On Sat, Jul 30, 2011 at 12:20 PM, Jason Drake <[hidden email]> wrote: > > > Thanks to everyone who provided feedback on the ideas. > > > > Using David's result below actually worked like a charm. I need to go > back > > and try some of the previous suggestions based on what I know now but > this > > really worked for me - I realize I was using "fill holes" incorrectly. I > > now realize fill holes means "fill the areas within a bounding region" > and > > not fill the edge holes (ie. the perforations - heh I am a stamp guy!). > > When I was running it was I doing an inverse bit mask (such that white > > became black and black become white) so when I ran fill holes... I got a > > black page! I have figured it out now. > > > > This looks like it will provide me with pretty close bounding boxes (with > > the exception of the skinny/abnomolies) which as suggested I should be > able > > to remove from the result set by simply checking the area exceeds 10000+. > > Actually I found that when using the Analyze Particles, if I set the > > size^2 > > of 10000 to infinity this gets rid of all the small boundings (based on > my > > scan sizes it is unlikely I'll ever scan a stamp less thant 10K sq > pixels). > > > > Now it is just a matter of plugging in this via the APIs of the library > > (duplicating the manual user-interface actions). I can then extract the > > remaining bounding boxes add a padding (~ 10-15 pixels around) and > display > > them in my user interface to allow me to make any small "tweaks" > > > > I may have API questions if I get bogged down, but given my Java > > experience/expertise this shouldn't be an issue. For me it was the > theory > > and transformations I was not familiar with. Web devleopment, > > user-interfaces, encoding or databases -- not a problem. > > > > Cheers > > > > -Jason > > > > > > > > -Jason > > > > > > > > > > On Sat, Jul 30, 2011 at 12:36 AM, David Webster <[hidden email] > > >wrote: > > > > > jason, > > > > > > I thgink you can what you want using existing ImageJ menu function and > a > > > macro without doing any pixel crunching algorithm development yourself. > > > > > > You may/will need to furthur preprocess your image by using > > > Process/Binary/Make Binary and Process/Binary/Fill Holes. This converts > > the > > > stamps to a bunch of solid white rectangular objects (or Particles). > > > > > > Then, do Analyze/Set Measurements and select Area, Bounding Box. and I > > > think > > > Shape Descriptors (this will get aspect ratio). > > > > > > Now run Analyze/Analyze Particles. You will get the selected properties > > > including the Bounding Box spec in a Results Table. You may want to > write > > > some macro code to eliminate objects that are to small (area) or to > > > "skinny" > > > (aspect ratio). This can be done using built in macro functions to get > > > Column/row data from the table and to delete rows as needed. > > > > > > > > > David Webster > > > > > > On Fri, Jul 29, 2011 at 3:14 PM, Jason Drake <[hidden email]> > > wrote: > > > > > > > Hi .... I am writing (or rather have substantially written) a program > > in > > > > Java to take a scanned page of stamps and attempt to create subimages > > of > > > > the > > > > stamps (and allow me to quickly save them in certain directories with > > > > particular names). > > > > > > > > I am struggling a little bit to come up with the right algorithm to > > "box > > > > off" the stamp images that I need to crop. I just need the > rectangular > > > > bounding boxes so I can present these in my interface, make any > changes > > > and > > > > proceed in the application to burst them into subimages. > > > > > > > > An example image is here (warning it is a 50Mb image): > > > > http://stamps.drakeserver.com/scan005.jpg > > > > > > > > Though investigation I found ImageJ. One thing I have managed to use > > > > ImageJ > > > > for is to convert the image to binary format (and filter with a > > > threshold). > > > > This gives me a working image (obviously my cropping will occur from > > the > > > > original) that is easier to deal with. I may also use their image > > object > > > > instead of BufferedImages as these are memory hogs: > > > > > > > > Here is the filtered image: > > http://stamps.drakeserver.com/scan005-5.jpg > > > > > > > > My current algorthim is quite dum.... I start in the top left and > > proceed > > > > on > > > > a forty-five degree angle toward the bottom right. As soon as a > catch > > a > > > > color change I mark it and attempt to achieve a 10 pixel threshold. > At > > > > this > > > > occurance, I will try and find the top left corner of a stamp, and > > > > conversely attempt to find the lower right corner. Since they are in > > > rows, > > > > I > > > > will move to the right and attempt the same thing for stamps to the > > right > > > > (if I hit the edge I go to next row). I keep track of the lowest "y" > > > value > > > > and use that for my next row. The perforations make this tricky. > The > > > > algorithm is only ~ 80% efficient and struggles when I come into gaps > > > (ie. > > > > stamps I have removed) I also can skip rows if there are not stamps > in > > > the > > > > first couple slots on the left..... > > > > > > > > Another thought I had was to start top right and simply scan to the > > > right. > > > > As soon as I hit multiple "white" pixels (say 10) I start to > determine > > if > > > > there is an area under them (ie. it isn't simply a reflection line > but > > > > represents a stamp shape). I proceed down the rows until I hit > matches. > > > > > > > > My background is engineering and computer science (but not graphics > > > > focussed) so I am not particularly up-to-speed with algorithms for > this > > > > type > > > > of thing. I would welcome any input on how to computationally solve > > > this. > > > > It will drastically save me time in scannign and cataloguing my > > > collection > > > > (although I have to admit the time I have put into my program > could've > > > > better been used on my hobby and just use Gimp, but well..... the > > > computer > > > > scientist in me loves to tinker. > > > > > > > > -Jason > > > > > > > > > > |
Jason,
There is a macro function to do this. It looks the same in a plugin. saveAs("Results", full_file_name); David On Sat, Jul 30, 2011 at 9:44 PM, Jason Drake <[hidden email]> wrote: > oh.... well - I did figure it out... Originally I wrote the java code, but > ran into a few issues with the Thresholder class since it is assuming to be > run in a ImageJ application (as opposed to as a library - it gets it's > image > from the WindowManager instead of accepting one). > > After the macro suggestion I did some reading and here is what I came up > with... > > ImagePlus the_image = new ImagePlus("imported image...", > bufferedImage); > IJ.run(the_image, "8-bit", ""); > IJ.run(the_image,"Make Binary", ""); > IJ.run(the_image,"Fill Holes", ""); > IJ.run(the_image,"Despeckle", ""); // probably not needed given the > results > IJ.run(the_image,"Set Measurements...", "area bounding redirect=None > decimal=3"); > // IJ.run(the_image,"Analyze Particles...", "size=10000-Infinity > circularity=0.00-1.00 show=Nothing exclude clear"); > > ResultsTable table = new ResultsTable(); > ParticleAnalyzer partAnalyzer = new > ParticleAnalyzer(ParticleAnalyzer.EXCLUDE_EDGE_PARTICLES + > ParticleAnalyzer.SHOW_NONE, Measurements.AREA + > Measurements.RECT,table,10000.0,Double.MAX_VALUE,0.0, 1.0); > partAnalyzer.analyze(the_image, the_image.getProcessor()); > int total = table.getCounter(); > List<Rectangle> rectangle = new ArrayList<Rectangle>(); > for(int row = 0 ; row < total; row++ ) { > Rectangle r = new Rectangle(); > r.x = > > Math.max(0,Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_X,row)).intValue() > - IMAGE_PADDING); > r.y = Math.max(0, > Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_Y, row)).intValue() > - > IMAGE_PADDING); > r.width = > Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_WIDTH, > row)).intValue() + (2*IMAGE_PADDING); > r.height = > > Double.valueOf(table.getValueAsDouble(ResultsTable.ROI_HEIGHT,row)).intValue() > + (2*IMAGE_PADDING); > if( r.width > MIN_SIZE && r.height > MIN_SIZE ) { // MIN_SIZE is > 100 - will filter skinny areas > rectangle.add(r); > } > } > return rectangle; > > I needed a way to get the results table and I didn't see a way to do it > with > IJ.run( ) stuff. Since I had this working with full fledged APIs I figured > I could just use what I had, build a resultsTable and pass it into my > ParticlAnalyzer. Seems to work. > > Never a big fan of calling static "run()" APIs but this seems to work. > > -Jason > > > > > On Sat, Jul 30, 2011 at 8:53 PM, David Webster <[hidden email] > >wrote: > > > Jason, > > > > Whoops, I forgot to mention that you can use Plugins/Macros/Recorder.. to > > record manually selected menu functions and convert them to an ImageJ > > macro, > > Javascript, or plugin without fooling around with Java or the API. > > > > David > > > > On Sat, Jul 30, 2011 at 12:20 PM, Jason Drake <[hidden email]> > wrote: > > > > > Thanks to everyone who provided feedback on the ideas. > > > > > > Using David's result below actually worked like a charm. I need to go > > back > > > and try some of the previous suggestions based on what I know now but > > this > > > really worked for me - I realize I was using "fill holes" incorrectly. > I > > > now realize fill holes means "fill the areas within a bounding region" > > and > > > not fill the edge holes (ie. the perforations - heh I am a stamp guy!). > > > When I was running it was I doing an inverse bit mask (such that white > > > became black and black become white) so when I ran fill holes... I got > a > > > black page! I have figured it out now. > > > > > > This looks like it will provide me with pretty close bounding boxes > (with > > > the exception of the skinny/abnomolies) which as suggested I should be > > able > > > to remove from the result set by simply checking the area exceeds > 10000+. > > > Actually I found that when using the Analyze Particles, if I set the > > > size^2 > > > of 10000 to infinity this gets rid of all the small boundings (based on > > my > > > scan sizes it is unlikely I'll ever scan a stamp less thant 10K sq > > pixels). > > > > > > Now it is just a matter of plugging in this via the APIs of the library > > > (duplicating the manual user-interface actions). I can then extract > the > > > remaining bounding boxes add a padding (~ 10-15 pixels around) and > > display > > > them in my user interface to allow me to make any small "tweaks" > > > > > > I may have API questions if I get bogged down, but given my Java > > > experience/expertise this shouldn't be an issue. For me it was the > > theory > > > and transformations I was not familiar with. Web devleopment, > > > user-interfaces, encoding or databases -- not a problem. > > > > > > Cheers > > > > > > -Jason > > > > > > > > > > > > -Jason > > > > > > > > > > > > > > > On Sat, Jul 30, 2011 at 12:36 AM, David Webster <[hidden email] > > > >wrote: > > > > > > > jason, > > > > > > > > I thgink you can what you want using existing ImageJ menu function > and > > a > > > > macro without doing any pixel crunching algorithm development > yourself. > > > > > > > > You may/will need to furthur preprocess your image by using > > > > Process/Binary/Make Binary and Process/Binary/Fill Holes. This > converts > > > the > > > > stamps to a bunch of solid white rectangular objects (or Particles). > > > > > > > > Then, do Analyze/Set Measurements and select Area, Bounding Box. and > I > > > > think > > > > Shape Descriptors (this will get aspect ratio). > > > > > > > > Now run Analyze/Analyze Particles. You will get the selected > properties > > > > including the Bounding Box spec in a Results Table. You may want to > > write > > > > some macro code to eliminate objects that are to small (area) or to > > > > "skinny" > > > > (aspect ratio). This can be done using built in macro functions to > get > > > > Column/row data from the table and to delete rows as needed. > > > > > > > > > > > > David Webster > > > > > > > > On Fri, Jul 29, 2011 at 3:14 PM, Jason Drake <[hidden email]> > > > wrote: > > > > > > > > > Hi .... I am writing (or rather have substantially written) a > program > > > in > > > > > Java to take a scanned page of stamps and attempt to create > subimages > > > of > > > > > the > > > > > stamps (and allow me to quickly save them in certain directories > with > > > > > particular names). > > > > > > > > > > I am struggling a little bit to come up with the right algorithm to > > > "box > > > > > off" the stamp images that I need to crop. I just need the > > rectangular > > > > > bounding boxes so I can present these in my interface, make any > > changes > > > > and > > > > > proceed in the application to burst them into subimages. > > > > > > > > > > An example image is here (warning it is a 50Mb image): > > > > > http://stamps.drakeserver.com/scan005.jpg > > > > > > > > > > Though investigation I found ImageJ. One thing I have managed to > use > > > > > ImageJ > > > > > for is to convert the image to binary format (and filter with a > > > > threshold). > > > > > This gives me a working image (obviously my cropping will occur > from > > > the > > > > > original) that is easier to deal with. I may also use their image > > > object > > > > > instead of BufferedImages as these are memory hogs: > > > > > > > > > > Here is the filtered image: > > > http://stamps.drakeserver.com/scan005-5.jpg > > > > > > > > > > My current algorthim is quite dum.... I start in the top left and > > > proceed > > > > > on > > > > > a forty-five degree angle toward the bottom right. As soon as a > > catch > > > a > > > > > color change I mark it and attempt to achieve a 10 pixel threshold. > > At > > > > > this > > > > > occurance, I will try and find the top left corner of a stamp, and > > > > > conversely attempt to find the lower right corner. Since they are > in > > > > rows, > > > > > I > > > > > will move to the right and attempt the same thing for stamps to the > > > right > > > > > (if I hit the edge I go to next row). I keep track of the lowest > "y" > > > > value > > > > > and use that for my next row. The perforations make this tricky. > > The > > > > > algorithm is only ~ 80% efficient and struggles when I come into > gaps > > > > (ie. > > > > > stamps I have removed) I also can skip rows if there are not stamps > > in > > > > the > > > > > first couple slots on the left..... > > > > > > > > > > Another thought I had was to start top right and simply scan to the > > > > right. > > > > > As soon as I hit multiple "white" pixels (say 10) I start to > > determine > > > if > > > > > there is an area under them (ie. it isn't simply a reflection line > > but > > > > > represents a stamp shape). I proceed down the rows until I hit > > matches. > > > > > > > > > > My background is engineering and computer science (but not graphics > > > > > focussed) so I am not particularly up-to-speed with algorithms for > > this > > > > > type > > > > > of thing. I would welcome any input on how to computationally > solve > > > > this. > > > > > It will drastically save me time in scannign and cataloguing my > > > > collection > > > > > (although I have to admit the time I have put into my program > > could've > > > > > better been used on my hobby and just use Gimp, but well..... the > > > > computer > > > > > scientist in me loves to tinker. > > > > > > > > > > -Jason > > > > > > > > > > > > > > > |
Free forum by Nabble | Edit this page |