// -*- C++ -*- // $RCSfile: automation.C,v $ // $Revision: 1.31 $ // $Author: langer $ // $Date: 2000/09/06 20:11:24 $ /* This software was produced by NIST, an agency of the U.S. government, * and by statute is not subject to copyright in the United States. * Recipients of this software assume all responsibilities associated * with its operation, modification and maintenance. However, to * facilitate maintenance we ask that before distributing modifed * versions of this software, you first contact the authors at * oof_manager@ctcms.nist.gov. */ #include "burn.h" #include "burner.h" #include "goof.h" #include "image.h" #include #include "menuinterrupt.h" #include "pixelgroups.h" #include "random.h" #include "stencil.h" #include "vec.h" void Goof::autoSelect(const Image & theImage, const CharString &grainGroupName, const CharString &boundaryGroupName, const Color &lowerColorBound, const Color &upperColorBound, const int localBurn, const int globalBurn, const int minSize, const double minAspect, const double maxAspect, const double maxPerimeter, bool verbose, bool auto_redraw) { //automated selection of regions on an image as Group A or B garcon()->msout << ms_info << "Starting automatic selection..." << endl; PixelGroup *grain, *boundary; //the two materials if(!(grain=get_group(grainGroupName))) grain=add_group(grainGroupName); if(!(boundary=get_group(boundaryGroupName))) boundary=add_group(boundaryGroupName); PixelGroup toBurn; toBurn.setphysicalsize(height*width); //so the group doesn't have to be //resized before every addition //(saves a lot of time) ArrayIterator iter(theImage); Cell_coordinate cell; while(iter(cell)){ if(theImage[cell].query_red()>=lowerColorBound.query_red() && theImage[cell].query_red()<=upperColorBound.query_red() && theImage[cell].query_blue()>=lowerColorBound.query_blue() && theImage[cell].query_blue()<=upperColorBound.query_blue() && theImage[cell].query_green()>=lowerColorBound.query_green() && theImage[cell].query_green()<=upperColorBound.query_green()) toBurn.append(cell); } int initialSize = toBurn.size(); if(verbose) garcon()->msout << " " << initialSize << " pixels to burn" << endl; if(toBurn.size()!=0){ Interrupter stop; Burn burner; //set burn parameters (Class Goof is a friend to Class Burn) burner.lcl=localBurn; burner.glbl=globalBurn; init_selection(0); //while there are unslected pixels still left while((toBurn.size()>0) && !stop()){ //pick random cell coordinate to burn and scale it to toBurn accordingly double random=rndm(); int index=(int)floor((random*(toBurn.size()))); if(index==toBurn.size()) index--; burner.igniteNoUndo(theImage, toBurn[index], 0); (void) current_goof->doDespeckle(5); double aspect=selected().aspectRatio(); double perimeter=selected().perimeter(); if(verbose) garcon()->msout << "At " << toBurn[index] << " selected " << selected().size() << " pixels that were " ; if(selected().size()msout << "not enough." << endl; } else if(((aspect>minAspect) && (perimeter>maxPerimeter)) || (aspect>maxAspect)){ //selection is probably part of Group B (boundary) toBurn.remove(toBurn[index]); if(verbose) garcon()->msout << "probably part of Group B." << endl; if(auto_redraw) redraw(); } else{ //selection is part of Group A (grain) toBurn.remove(selected()); grain->append(selected()); if(verbose) garcon()->msout << "added to Group A." << endl; if(auto_redraw) redraw(); } if(verbose) garcon()->msout << "Pixels left to burn: " << toBurn.size() << " (" << toBurn.size()*100./initialSize << "%)" << endl; } grain->weed(); if(verbose) garcon()->msout << "Total Group A pixels selected before expand: " << grain->size() << endl; expandgroup(*grain, 1); if(verbose) garcon()->msout << "Total Group A pixels selected after expand: " << grain->size() << endl; //invert Group A to get Group B select(*grain); select_complement(); boundary->append(selected()); unselect_all(); garcon()->msout << "Automated Selection Complete." << endl; } else garcon()->msout << ms_error << "No pixels in color range!" << endl << ms_normal; }