Posted by
jadrake75 on
Jul 31, 2011; 4:44am
URL: http://imagej.273.s1.nabble.com/Ideas-for-Algorithm-tp3683675p3683679.html
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
> > > >
> > >
> >
>