docs: private void extractImageFeatures(final ProgressMonitor progressMonitor, final int progress,
  									  T image,
  									  List<TupleDesc> descs, List<Point2D_F64> locs) {
  		SwingUtilities.invokeLater(new Runnable() {
  			public void run() {
  				progressMonitor.setNote("Detecting");
  			}
  		});
  		detector.detect(image);
  		SwingUtilities.invokeLater(new Runnable() {
  			public void run() {
  				progressMonitor.setProgress(progress + 1);
  				progressMonitor.setNote("Describing");
  			}
  		});
  		describe.setImage(image);
  		orientation.setImage(image);
  
  		// See if the detector can detect the feature's scale
  		if (detector.hasScale()) {
  			for (int i = 0; i < detector.getNumberOfFeatures(); i++) {
  				double yaw = 0;
  
  				Point2D_F64 pt = detector.getLocation(i);
  				double radius = detector.getRadius(i);
  				if (describe.requiresOrientation()) {
  					orientation.setObjectRadius(radius);
  					yaw = orientation.compute(pt.x, pt.y);
  				}
  
  				TupleDesc d = describe.createDescription();
  				if ( describe.process(pt.x, pt.y, yaw, radius, d) ) {
  					descs.add(d);
  					locs.add(pt.copy());
  				}
  			}
  		} else {
  			// just set the radius to one in this case
  			orientation.setObjectRadius(1);
  			for (int i = 0; i < detector.getNumberOfFeatures(); i++) {
  				double yaw = 0;
  
  				Point2D_F64 pt = detector.getLocation(i);
  				if (describe.requiresOrientation()) {
  					yaw = orientation.compute(pt.x, pt.y);
  				}
  
  				TupleDesc d = describe.createDescription();
  				if (describe.process(pt.x, pt.y, yaw, 1, d)) {
  					descs.add(d);
  					locs.add(pt.copy());
  				}
  			}
  		}
  		SwingUtilities.invokeLater(new Runnable() {
  			public void run() {
  				progressMonitor.setProgress(progress + 2);
  			}
  		});
  	}