FiberTracker.java

Go to the documentation of this file.
00001 package theba.trackers;
00002 
00003 import java.awt.Point;
00004 import java.awt.Rectangle;
00005 import java.util.ArrayList;
00006 import java.util.Collections;
00007 import java.util.Iterator;
00008 import java.util.LinkedList;
00009 
00010 import javax.swing.JOptionPane;
00011 import javax.swing.JToggleButton;
00012 
00013 import theba.core.BackTrack;
00014 import theba.core.ImageFunctions;
00015 import theba.core.LumenCandidate;
00016 import theba.core.RegionMask2D;
00017 import theba.core.Seed;
00018 import theba.core.Stack;
00019 import theba.core.Tracker;
00020 import theba.core.gui.ThebaGUI;
00021 import theba.core.math.Point3D;
00022 import theba.descriptors.AvgYoungCurvature;
00023 import theba.descriptors.CircularityDescriptor;
00024 import theba.descriptors.ConvexityDescriptor;
00025 import theba.descriptors.EccentricityDescriptor;
00026 import theba.descriptors.InternalRegionDescriptor;
00027 import theba.descriptors.SolidityDescriptor;
00028 import theba.descriptors.YoungBendingEnergy;
00029 
00030 
00039 public class FiberTracker extends Tracker {
00040 //      private LinkedList fibers = new LinkedList();
00041 
00042         private JToggleButton seedButton;
00043 
00044         private LinkedList<Seed> seedQueue;
00045 
00046         private LinkedList<LumenCandidate> seeds = new LinkedList<LumenCandidate>();
00047 
00048         boolean seedStillValid = true;
00049 
00050         private short currentId;
00051 
00052         private short[] map = null;
00053 
00054         private short[] map2;
00055 
00056         // configurable options
00057         private boolean automerge = false;
00058 
00059         private int minimumFiberSize = 50;
00060 
00061         private boolean removeShortFibers = false;
00062 
00066         @SuppressWarnings("unchecked")
00067         @Override
00068         public void track() {
00069 
00070                 int width = control.getStack().getWidth();
00071                 int height = control.getStack().getHeight();
00072                 int depth = control.getStack().getDepth();
00073 
00074                 automerge = (1 == control.getPreferences().getInt("autoMerge", 0));
00075 
00076 //              Skeleton structure for each fiber based on 2D centroids
00077                 Point[][] skeleton = new Point[control.MAX_FIBERS][depth];
00078 
00079                 Collections.sort(seeds); //sort seeds according to size (biggest seeds first)
00080                 Point3D s = null;
00081                 Iterator<LumenCandidate> iter = seeds.iterator();
00082                 int count = 0;
00083                 keepTracking = true;
00084 
00085                 while (iter.hasNext() && keepTracking && !control.isStopped()) {
00086                         s = iter.next();
00087                         seedQueue = new LinkedList<Seed>();
00088                         count++;
00089                         System.out.println("\nTracking seed " + count + " of "
00090                                         + seeds.size() + " starting at " + s);
00091                         short[] data = control.getSlice(s.z);
00092                         if (data[s.x + s.y * width] != 0) {
00093                                 continue;
00094                         }
00095 
00096                         currentId = (control.getNewFiberId());
00097                         ImageFunctions.delete3D(control.getStack(), s.x, s.y, s.z);
00098                         //Init seedQue with initial seed
00099                         seedQueue.addLast(new Seed(s.x, s.y, s.z, 1, null, null, 0));
00100                         log("***************************");
00101                         log("Tracking seed with origin " + s);
00102                         StringBuffer results = new StringBuffer();
00103                         results.append("Tracking seed  " + count + " of " + seeds.size()
00104                                         + "\n from " + s);
00105                         control.showResults(results, "Lumen tracking");
00106                         short[] lumenMask = new short[data.length];
00107                         int slice = s.z;
00108 
00109                         ImageFunctions.floodFill2D(s.x, s.y, width, height, data, lumenMask, currentId);
00110                         short[] lcopy = lumenMask.clone();
00111 
00112                         seedStillValid = true;
00113                         int length = 0;
00114 
00115                         //Trace forward from seed
00116 
00117                         while (slice < depth && seedStillValid && keepTracking) {
00118                                 control.setProgress(slice);
00119                                 removeCrack(slice, lumenMask);
00120                                 removeStuff(slice, lumenMask);
00121                                 if (automerge)
00122                                         skeleton[currentId][slice] = ImageFunctions.getAveragePoint(lumenMask, width, height);
00123                                 if (slice % 2 == 0)
00124                                         control.showImage(control.getSlice(slice));
00125                                 slice++;
00126                         }
00127 
00128                         seedStillValid = true;
00129                         slice = s.z - 1;
00130                         lumenMask = lcopy;
00131                         // Trace backward from seed
00132                         while (slice >= 0 && seedStillValid && keepTracking
00133                                         && !control.isStopped()) {
00134                                 control.setProgress(slice);
00135                                 removeCrack(slice, lumenMask);
00136                                 removeStuff(slice, lumenMask);
00137                                 if (slice % 2 == 0)
00138                                         control.showImage(control.getSlice(slice));
00139                                 if (automerge)
00140                                         skeleton[currentId][slice] = ImageFunctions
00141                                                         .getAveragePoint(lumenMask, width, height);
00142                                 slice--;
00143                         }
00144 
00145                         control.showImage(control.getSlice(slice + 1));
00146 
00147                         if (automerge)
00148                                 checkMerges(skeleton);
00149                         // We must recalculate length, since the total length may have grown
00150                         // after merges have been applied!
00151                         length = 0;
00152                         for (int z = 0; z < depth; z++) {
00153                                 if (skeleton[currentId][z] != null)
00154                                         length++;
00155                         }
00156 
00157                         if (removeShortFibers) {
00158                                 if (length < minimumFiberSize) {
00159                                         //Fiber is rejected, reclaiming space by marking this seed as invalid
00160                                         for (int z = 0; z < depth; z++) {
00161                                                 short[] pixels = control.getSlice(z);
00162                                                 for (int i = 0; i < pixels.length; i++) {
00163                                                         if (pixels[i] == currentId)
00164                                                                 pixels[i] = control.INVALID;
00165                                                 }
00166                                         }
00167                                         control.releaseFiberId(currentId);
00168                                         skeleton[currentId] = new Point[depth];
00169                                 }
00170                         }
00171 
00172                 }
00173 
00174                 control.setProgressComplete();
00175                 control.updateImage();
00176                 seeds.clear(); // Clear seeds marks
00177                 control.showResults("Tracking lumens complete");
00178         }
00179 
00180         public FiberTracker(ThebaGUI f) {
00181                 super(f);
00182         }
00183 
00184         @Override
00185         public void setup() {
00186                 seedButton = new JToggleButton("Mark seed");
00187                 control.addToolbarButton(seedButton);
00188                 Runnable lumenAction = new Runnable() {
00189                         public void run() {
00190                                 track();
00191                         }
00192                 };
00193 
00194                 Runnable wallAction2 = new Runnable() {
00195                         public void run() {
00196                                 traceWalls3d();
00197                         }
00198 
00199                 };
00200 
00201                 FindCandidatesAction findCandidates = new FindCandidatesAction();
00202                 FindAllCandidatesAction findAllCandidates = new FindAllCandidatesAction();
00203                 Runnable clearAction = new Runnable() {
00204                         public void run() {
00205                                 seeds.clear();
00206                         }
00207                 };
00208                 control.addMenuItem("Track lumens", lumenAction);
00209                 control.addMenuItem("Track walls 3D", wallAction2);
00210                 control.addMenuSeparator();
00211                 control.addMenuItem("Find seeds in this slice", findCandidates);
00212                 control.addMenuItem("Find seeds for every n'th slice",
00213                                 findAllCandidates);
00214                 control.addMenuSeparator();
00215                 control.addMenuItem("Autosegment", new AutosegmentAction());
00216                 control.addMenuSeparator();
00217                 control.addMenuItem("Clear seeds", clearAction);
00218 
00219         }
00220 
00221         public void autoSegment() {
00222 
00223                 Stack v = control.getStack();
00224                 for (int i = 0; i < v.getDepth(); i += 100) {
00225                         findCandidates(i);
00226                 }
00227                 track();
00228                 control.flipVolume();
00229                 v = control.getStack();
00230                 for (int i = 0; i < v.getDepth(); i += 100) {
00231                         findCandidates(i);
00232                 }
00233                 track();
00234                 control.flipVolume();
00235 
00236                 // traceWalls3d();
00237         }
00238 
00239         static final short max(short x, short y) {
00240                 if ((x) > (y))
00241                         return x;
00242                 return y;
00243         }
00244 
00250         public static void dilate3d_toWhite(Stack voxels, long[] counts) {
00251 
00252                 int width = voxels.getWidth();
00253                 int height = voxels.getHeight();
00254                 int depth = voxels.getDepth();
00255 
00256                 short[] prevdata = new short[width * height];
00257                 short[] data = new short[width * height];
00258                 short[] nextdata = new short[width * height];
00259 
00260                 ThebaGUI control = ThebaGUI.getInstance();
00261 
00262                 System.arraycopy(voxels.getSlice(1), 0, nextdata, 0, nextdata.length);
00263                 System.arraycopy(voxels.getSlice(0), 0, data, 0, data.length);
00264 
00265                 for (int z = 0; z < depth; z++) {
00266 
00267                         short[] origdata = voxels.getSlice(z);
00268 
00269                         control.setProgress(z);
00270 
00271                         if (control.isStopped())
00272                                 return;
00273 
00274                         int index = 0;
00275 
00276                         for (int y = 0; y < height; y++) {
00277                                 for (int x = 0; x < width; x++) {
00278 
00279                                         short max = data[index];
00280 
00281                                         if (max == 255) {
00282                                                 /*
00283                                                  * Consider only propagating pixels that are not marked
00284                                                  * by a negative value in the counts table, this
00285                                                  * indicates that they are beyond their detected wall
00286                                                  * size and should not be propagated further
00287                                                  */
00288                                                 if (x > 0)
00289                                                         max = max(max, data[index - 1]);
00290 
00291                                                 if (x < width - 1)
00292                                                         max = max(max, data[index + 1]);
00293 
00294                                                 if (y > 0)
00295                                                         max = max(max, data[index - width]);
00296 
00297                                                 if (y < height - 1)
00298                                                         max = max(max, data[index + width]);
00299 
00300                                                 if (z > 0)
00301                                                         max = max(max, prevdata[index]);
00302 
00303                                                 if (z < depth - 1)
00304                                                         max = max(max, nextdata[index]);
00305 
00306                                                 int id = max & (~(1 << 12));
00307                                                 if (max > data[index] && counts[id] != -1) {
00308                                                         origdata[index] = (short) (max | (1 << 12));
00309                                                         counts[id]++;
00310                                                 }
00311                                         }
00312                                         index++;
00313                                 }
00314                         }
00315 
00316                         if (z > 0)
00317                                 System.arraycopy(data, 0, prevdata, 0, prevdata.length);
00318 
00319                         System.arraycopy(nextdata, 0, data, 0, data.length);
00320 
00321                         if (z < depth - 2)
00322                                 System.arraycopy(voxels.getSlice(z + 2), 0, nextdata, 0,
00323                                                 nextdata.length);
00324 
00325                 }
00326         }
00327 
00333         private void traceWalls3d() {
00334 
00335                 Stack stack = control.getStack();
00336 
00337                 int width = stack.getWidth();
00338                 int height = stack.getHeight();
00339                 int depth = stack.getDepth();
00340 
00341                 long[] startvals = new long[control.MAX_FIBERS];
00342                 long[] lumenvals = new long[control.MAX_FIBERS];
00343 
00344                 for (int i = 0; i < 15; i++) {
00345                         //reset all non-negative values
00346                         for (int k = 0; k < lumenvals.length; k++) {
00347                                 if (lumenvals[k] > 0)
00348                                         lumenvals[k] = 0;
00349                         }
00355                         dilate3d_toWhite(control.getStack(), lumenvals);
00356                         for (int k = 0; k < lumenvals.length; k++) {
00357                                 if (lumenvals[k] > 0) {
00358                                         if (i == 0)
00359                                                 startvals[k] = lumenvals[k];
00360                                         if (lumenvals[k] < startvals[k] / 4) {
00361                                                 lumenvals[k] = -1;
00362                                         }
00363                                 }
00364                         }
00365                         control.updateImage();
00366                 }
00367 
00368                 ThebaGUI control = ThebaGUI.getInstance();
00369                 for (int z = 0; z < depth; z++) {
00370 
00371                         short[] data = control.getSlice(z);
00372                         control.setProgress(z);
00373                         if (control.isStopped())
00374                                 return;
00375 
00376                         for (int x = 0; x < width; x++) {
00377                                 for (int y = 0; y < height; y++) {
00378                                         int index = x + y * width;
00379                                         if (data[index] == 255)
00380                                                 continue;
00381                                         if ((data[index] & (1 << 12)) != 0) {
00382                                                 data[index] = (short) (data[index] & ~(1 << 12));
00383                                         } else {
00384                                                 data[index] = 0;
00385                                         }
00386                                 }
00387                         }
00388                 }
00389 
00390                 control.updateImage();
00391 
00392         }
00393 
00394         /*
00395          * Returns a factor describing the percentage of border-pixels that are
00396          * adjacent to a white border-area A too low percentage is a strong
00397          * indication that this region is not a valid fiber
00398          */
00399         public float checkReg(int xp, int yp, final short[] input) {
00400                 short[] mark = new short[input.length];
00401                 int width = control.getStack().getWidth();
00402                 int height = control.getStack().getHeight();
00403                 //int depth = control.getStack().getDepth();
00404                 LinkedList<Point> queue = new LinkedList<Point>();
00405                 queue.addFirst(new Point(xp, yp));
00406                 float whiteCount = 0;
00407                 float borderCount = 0;
00408                 short col = input[xp + yp * width];
00409                 while (queue.isEmpty() == false) {
00410                         Point p = queue.removeLast();
00411                         int x = p.x;
00412                         int y = p.y;
00413                         int index = x + y * width;
00414                         if (x + 1 < width) {
00415                                 if (input[index + 1] == 255)
00416                                         whiteCount++;
00417                                 else if (input[index + 1] == 0)
00418                                         borderCount++;
00419                                 if (mark[index + 1] == 0 && input[index + 1] == col) {
00420                                         mark[index + 1] = 1;
00421                                         queue.addFirst(new Point(x + 1, y));
00422                                 }
00423                         }
00424                         if (y + 1 < height) {
00425                                 if (input[index + width] == 255)
00426                                         whiteCount++;
00427                                 else if (input[index + width] == 0)
00428                                         borderCount++;
00429                                 if (mark[index + width] == 0 && input[index + width] == col) {
00430                                         mark[index + width] = 1;
00431                                         queue.addFirst(new Point(x, y + 1));
00432                                 }
00433                         }
00434                         if (y - 1 >= 0) {
00435                                 if (input[index - width] == 255)
00436                                         whiteCount++;
00437                                 else if (input[index - width] == 0)
00438                                         borderCount++;
00439                                 if (mark[index - width] == 0 && input[index - width] == col) {
00440                                         mark[index - width] = 1;
00441                                         queue.addFirst(new Point(x, y - 1));
00442                                 }
00443                         }
00444                         if (x - 1 >= 0) {
00445                                 if (input[index - 1] == 255)
00446                                         whiteCount++;
00447                                 else if (input[index - 1] == 0)
00448                                         borderCount++;
00449                                 if (mark[index - 1] == 0 && input[index - 1] == col) {
00450                                         mark[index - 1] = 1;
00451                                         queue.addFirst(new Point(x - 1, y));
00452                                 }
00453                         }
00454                 }
00455                 borderCount += whiteCount;
00456                 return whiteCount / borderCount;
00457         }
00458 
00466         public void findCandidates(int slice) {
00467                 int width = control.getStack().getWidth();
00468                 int height = control.getStack().getHeight();
00469                 //int depth = control.getStack().getDepth();
00470                 short[] pixels = control.getSlice(slice);
00471                 short[] copy = pixels.clone();
00472                 for (int y = 0; y < height; y++) {
00473                         for (int x = 0; x < width; x++) {
00474                                 int index = x + y * width;
00475                                 if (copy[index] == 0) {
00476                                         short[] mask = new short[pixels.length];
00477                                         short color = (short) 0xf0;
00478                                         int lumenArea = ImageFunctions.floodFill2D(x, y, width,
00479                                                         height, copy, mask, color);
00480                                         for (int i = 0; i < pixels.length; i++)
00481                                                 if (mask[i] != 0)
00482                                                         copy[i] = (short) 1;
00483 
00484                                         // Decide if this area is a ok lumen.
00485                                         boolean okLumen = true;
00486 
00487                                         okLumen = okLumen && lumenArea < 8000 && lumenArea > 500;
00488 
00489                                         RegionMask2D maskreg = new RegionMask2D(mask, width, height);
00490 
00491                                         // get bounds, use bounds
00492                                         if (okLumen) {
00493                                                 double circularity = (new CircularityDescriptor())
00494                                                                 .measure(mask, width, height);
00495                                                 okLumen = okLumen && circularity < 3.8
00496                                                                 && circularity > 0.7;
00497                                         }
00498 
00499                                         if (okLumen) {
00500                                                 double curvature = (new AvgYoungCurvature()).measure(
00501                                                                 mask, width, height);
00502                                                 okLumen = okLumen && curvature > 0 && curvature < 1.6;
00503                                         }
00504                                         if (okLumen) {
00505                                                 double bending_energy = (new YoungBendingEnergy())
00506                                                                 .measure(mask, width, height);
00507                                                 okLumen = okLumen && bending_energy > 0
00508                                                                 && bending_energy < 8.0; // 4.0
00509                                         }
00510                                         if (okLumen) {
00511                                                 double convexity = (Double) (new ConvexityDescriptor())
00512                                                                 .measure(maskreg);
00513                                                 okLumen = okLumen && convexity > 0.8 && convexity < 1.0;
00514                                         }
00515                                         if (okLumen) {
00516                                                 double solidity = (new SolidityDescriptor()).measure(
00517                                                                 mask, width, height);
00518                                                 okLumen = okLumen && solidity < 1.3 && solidity > 0.7;
00519                                         }
00520 
00521                                         if (okLumen) {
00522                                                 double eccentricity = (new EccentricityDescriptor())
00523                                                                 .measure(mask, width, height);
00524                                                 okLumen = okLumen && eccentricity < 15
00525                                                                 && eccentricity > 1; // 4
00526                                         }
00527 
00528                                         // if the area is very small and the eccentricity is large,
00529                                         // then we have a small thin region found in
00530                                         // ring-like fiber
00531                                         if (!okLumen && lumenArea < 200 && lumenArea > 80) {
00532                                                 double eccentricity = (new EccentricityDescriptor())
00533                                                                 .measure(mask, width, height);
00534                                                 okLumen = eccentricity > 15;
00535                                         }
00536 
00537                                         if (okLumen) {
00538                                                 int internalRegionCount = (Integer) (new InternalRegionDescriptor())
00539                                                                 .measure(maskreg);
00540                                                 okLumen = okLumen && internalRegionCount < 2;
00541                                         }
00542 
00543                                         if (okLumen) {
00544                                                 okLumen = okLumen
00545                                                                 && !ImageFunctions.touchBorder(mask, width,
00546                                                                                 height);
00547                                         }
00548 
00549                                         // Ok, let's assume this is a lumen now
00550                                         if (okLumen) {
00551                                                 LumenCandidate newSeed = new LumenCandidate(x, y,
00552                                                                 slice, (lumenArea));
00553                                                 seeds.add(newSeed);
00554                                                 for (int i = 0; i < pixels.length; i++)
00555                                                         if (mask[i] != 0)
00556                                                                 copy[i] = 0xcc;
00557                                         }
00558                                 }
00559                         }
00560                 }
00561                 control.showImage(copy);
00562         }
00563 
00564         public boolean isReserved(short val) {
00565                 if (val == 255 || val == control.INVALID)
00566                         return true;
00567                 return false;
00568         }
00569 
00570         @Override
00571         public void mouseClicked(Point3D p) {
00572                 if (seedButton.isSelected())
00573                         selectSeed(new Point(p.x, p.y));
00574         }
00575 
00576         public boolean removeCrack(int slice, short[] lumen) {
00577                 int width = control.getStack().getWidth();
00578                 int height = control.getStack().getHeight();
00579                 int depth = control.getStack().getDepth();
00580                 short[] data = control.getSlice(slice);
00581                 short[] invdata = ImageFunctions.invertMask(data, false);
00582                 ImageFunctions.invertMask(lumen, false);
00583                 Rectangle bounds = ImageFunctions.getBounds(lumen, width, height, 12);
00584                 // End search if fibre is outside volume (bounds==null indicates no
00585                 // pixels found)
00586                 if (bounds == null || bounds.x < 0 || bounds.y < 0
00587                                 || bounds.width > width || bounds.height > height) {
00588                         seedStillValid = false;
00589                         slice = depth;
00590                         return true;
00591                 }
00592 
00593                 if (map == null || map.length != data.length) {
00594                         map = new short[data.length];
00595                         map2 = new short[data.length];
00596                 }
00597 
00598                 //Create a distancemap for use by backtracking, where lumen= distance 1
00599                 for (int i = 0; i < map.length; i++) {
00600                         if (lumen[i] != 0)
00601                                 map[i] = 1;
00602                         else
00603                                 map[i] = 0;
00604                 }
00605                 map = ImageFunctions.dilate(lumen, map, width, height, bounds, (short) 2);
00606                 int maxDilations = control.getPreferences().getInt("maxDilations", 12);
00607                 for (int i = 3; i < maxDilations; i++) {
00608                         System.arraycopy(map, 0, map2, 0, map.length);
00609                         map = ImageFunctions.dilateMasked(map2, map, invdata, width, height, bounds, (short) i);
00610                 }
00611 
00612                 map = ImageFunctions.mask(map, invdata, true);
00613 
00614                 //Heal cracks detected based on distances with few occurances in the map
00615                 BackTrack.backTrack(map, 9, width, height, bounds);
00616 
00617                 //copy new lumen back to source
00618                 for (int i = 0; i < map.length; i++) {
00619                         lumen[i] = map[i];
00620                         if (lumen[i] != 0)
00621                                 data[i] = currentId;
00622                 }
00623                 return false;
00624         }
00625 
00632         @SuppressWarnings("unchecked")
00633         public void removeStuff(int slice, short[] lumen) {
00634                 int width = control.getStack().getWidth();
00635                 int height = control.getStack().getHeight();
00636                 //int depth = control.getStack().getDepth();
00637                 int regId = 1;
00638                 short[] mark = new short[width * height];
00639                 short[] slicedata = control.getSlice(slice);
00640                 ArrayList<LumenCandidate> liste = new ArrayList<LumenCandidate>();
00641                 for (int x = 0; x < width; x++) {
00642                         for (int y = 0; y < height; y++) {
00643                                 if (mark[x + y * width] == 0 && lumen[x + y * width] != 0) {
00644                                         regId++;
00645                                         int size = ImageFunctions.floodFill2D(x, y, width, height, lumen, mark, (short) regId);
00646                                         LumenCandidate thisCandidate = new LumenCandidate(x, y, 0,
00647                                                         size);
00648                                         float borderRatio = checkReg(x, y, slicedata);
00649                                         if (borderRatio < 0.7) {
00650                                                 // no pixels have a white border, so we remove it!
00651                                                 log("Removed isolated region");
00652                                                 ImageFunctions.floodFill2D(x, y, width, height, slicedata, (short) 0);
00653                                                 ImageFunctions.floodFill2D(x, y, width, height, lumen, (short) 0);
00654                                         } else {
00655                                                 liste.add(thisCandidate);
00656                                         }
00657 
00658                                 }
00659                         }
00660                 }
00661 
00662                 int numberOfRegionsToKeep = 2;
00663 
00664                 if (liste.size() > 1) {
00665                         Collections.sort(liste);
00666                         boolean useMR_rules = true;
00667                         if (useMR_rules) {
00668                                 LumenCandidate A = liste.get(0);
00669                                 LumenCandidate B = liste.get(1);
00670                                 // Using rules that may be data dependent
00671                                 if (A.getSize() > 5 * B.getSize()) {
00672                                         numberOfRegionsToKeep--;
00673                                 }
00674                         }
00675                         for (int i = numberOfRegionsToKeep; i < liste.size(); i++) {
00676                                 LumenCandidate l = liste.remove(i);
00677                                 ImageFunctions.floodFill2D(l.x, l.y, width, height, slicedata, (short) 0);
00678                                 ImageFunctions.floodFill2D(l.x, l.y, width, height, lumen, (short) 0);
00679                         }
00680                 }
00681         }
00682 
00683         public void selectSeed(Point e) {
00684                 int width = control.getStack().getWidth();
00685                 int height = control.getStack().getHeight();
00686                 //int depth = control.getStack().getDepth();
00687                 short[] data = control.getCurrentPixels();
00688                 short[] filledRegion = new short[data.length];
00689                 if (data[(int) e.getX() + (int) e.getY() * width] == 255)
00690                         return;
00691                 int count = ImageFunctions.floodFill2D(data, filledRegion, (int) e
00692                                 .getX(), (int) e.getY(), width, height, (short) 200);
00693 
00694                 Point p = e.getLocation();
00695 
00696                 short[] displayedImage = data.clone();
00697                 if (p != null) {
00698                         // copy marked pixels to output
00699                         for (int i = 0; i < data.length; i++) {
00700                                 if (filledRegion[i] != 0) {
00701                                         displayedImage[i] = filledRegion[i];
00702                                 }
00703                         }
00704                         control.showImage(displayedImage);
00705 
00706                         if (count > 10000) {
00707                                 int ans = JOptionPane
00708                                                 .showConfirmDialog(
00709                                                                 null,
00710                                                                 "This regions has "
00711                                                                                 + count
00712                                                                                 + " pixels \nAre you sure you want to add this region?",
00713                                                                 "Confirm seed", JOptionPane.YES_NO_OPTION);
00714                                 if (ans == JOptionPane.NO_OPTION) {
00715                                         control.updateImage();
00716                                         return;
00717                                 }
00718 
00719                         }
00720                         seeds.add(new LumenCandidate(p.x, p.y, control.currentSlice(),
00721                                         count));
00722                 }
00723         }
00724 
00725         private void checkMerges(Point[][] skel) {
00726                 int width = control.getStack().getWidth();
00727                 int height = control.getStack().getHeight();
00728                 int depth = control.getStack().getDepth();
00729                 int[] mergeList = new int[control.MAX_FIBERS];
00730                 for (int z = 1; z < depth - 1; z++) {
00731                         short[] slice = control.getSlice(z);
00732                         short[] next = control.getSlice(z + 1);
00733                         short[] prev = control.getSlice(z - 1);
00734                         for (int x = 1; x < width - 1; x++) {
00735                                 for (int y = 1; y < height - 1; y++) {
00736                                         int index = x + y * width;
00737                                         if (slice[index] == currentId) {
00738                                                 // merge only fibres that touch from above or below
00739                                                 mergeList[next[index]] = 1;
00740                                                 mergeList[prev[index]] = 1;
00741                                         }
00742                                 }
00743                         }
00744                 }
00745                 for (short color = 1; color < control.MAX_FIBERS; color++) {
00746                         if (isReserved(color))
00747                                 continue;
00748                         if (mergeList[color] != 0 && color != currentId) {
00749                                 double avgDist = 0;
00750                                 double count = 0;
00751                                 for (int i = 0; i < depth; i++) {
00752                                         if (skel[currentId][i] != null && skel[color][i] != null) {
00753                                                 double a = skel[currentId][i].x - skel[color][i].x;
00754                                                 double b = skel[currentId][i].y - skel[color][i].y;
00755                                                 double dist = Math.sqrt(a * a + b * b);
00756                                                 avgDist += dist;
00757                                                 count++;
00758                                         }
00759                                 }
00760                                 if (count > 0)
00761                                         avgDist /= count;
00762                                 System.out.println("Overlaps " + count);
00763                                 System.out.println("Avgdist " + avgDist);
00764                                 // Only merge regions of they have an average distance
00765                                 // across all coinciding lumen sections below this threshold
00766                                 if (avgDist < 50 || count == 0) {
00767                                         System.out.println("Merging " + color + " with "
00768                                                         + (currentId));
00769                                         control.releaseFiberId(color);
00770                                         for (int z = 0; z < depth; z++) {
00771                                                 short[] slice = control.getSlice(z);
00772                                                 for (int x = 1; x < width - 1; x++) {
00773                                                         for (int y = 1; y < height - 1; y++) {
00774                                                                 int index = x + y * width;
00775                                                                 if (slice[index] == color) {
00776                                                                         slice[index] = currentId;
00777                                                                 }
00778                                                         }
00779                                                 }
00780                                                 skel[currentId][z] = ImageFunctions.getAveragePoint(
00781                                                                 slice, width, height, currentId);
00782                                                 skel[color][z] = null;
00783                                         }
00784                                 } else {
00785                                         System.out.println("Rejected merge!");
00786                                 }
00787                         }
00788                 }
00789         }
00790 
00791         @Override
00792         public void reset() {
00793         }
00794 
00795         @Override
00796         public void stop() {
00797         }
00798 
00799         // ************* Menu actions ****************
00800 
00801         private final class FindAllCandidatesAction implements Runnable {
00802                 public void run() {
00803                         int depth = control.getStack().getDepth();
00804                         String s = JOptionPane.showInputDialog("How many slices to skip?",
00805                                         "10");
00806                         try {
00807                                 final int num = Integer.parseInt(s);
00808                                 for (int z = 0; z < depth; z += num) {
00809                                         control.setProgress(z);
00810                                         findCandidates(z);
00811                                 }
00812                         } catch (NumberFormatException ee) {
00813                         }
00814                 }
00815         }
00816 
00817         private final class FindCandidatesAction implements Runnable {
00818                 public void run() {
00819                         findCandidates(control.currentSlice());
00820                 }
00821         }
00822 
00823         private final class AutosegmentAction implements Runnable {
00824                 public void run() {
00825                         automerge = (1 == control.getPreferences().getInt("autoMerge", 0));
00826                         autoSegment();
00827                 }
00828         }
00829 
00830 }

Generated on Fri Nov 13 08:57:07 2009 for Theba by  doxygen 1.6.1