PlugIn Algorithm Median (con't, part 4)

From MIPAV
Revision as of 14:56, 16 February 2012 by Angelfish100 (Talk)

(diff) <previousrevision> | Latest revision (diff) | <nextrevision> (diff)
Jump to: navigation, search
1200 else if (!sliceFiltering)
1201 kernel = new byte[kernelSize*kernelSize*kernelSize];
1202 }
1203 catch (OutOfMemoryError e) {
1204 displayError("Algorithm Median reports: not enough memory to form a kernel mask.");
1205 setCompleted(false);
1206 setThreadStopped(true);
1207 return;
1208 }
1209 setKernel();
1210 makeKernelMask();
1211 }
1212
1213 /**
1214 * Fill in the mask for which pixels are used in filtering.
1215 *
1216 */
1217 private void setKernel() {
1218 int i;
1219 int halfK = kernelSize/2;
1220
1221 // square/box
1222 if ( (kernelShape == SQUARE_KERNEL) ||
1223 (kernelShape == CUBE_KERNEL)) {
|- |
1224 for (i=0; i < kernel.length; i )
1225 kernel[i] = 1;
1226
1227 } // end square/cube kernel
1228
1229 // cross/axial
1230 else if ((kernelShape == CROSS_KERNEL) ||
1231 (kernelShape == AXIAL_KERNEL)) {
1232 int row; // indicates current row
1233 int col; // indicates current column
1234 if (sliceFiltering) {
1235 for (i = 0; i < kernel.length; i ) {
1236 row = i/kernelSize;
1237 col = i%kernelSize;
1238
1239 if (col == halfK) {kernel[i] = 1;}
1240 else if (row == halfK) {kernel[i] = 1;} // should be for a cross ->
1241 // else if
1242 // (row == halfK) {kernel[i] = 1;}
1243 else {kernel[i] = 0;}
1244 }
1245 }
1246 else { // volume filtering
1247 int slice;
1248 for (i = 0; i < kernel.length; i ) {
1249 slice = i/(kernelSize*kernelSize);
1250 row = (i%(kernelSize*kernelSize))/kernelSize;
1251 col = i%kernelSize;
1252
1253 if (slice == halfK) {
1254 if (col == halfK) {kernel[i] = 1;}
1255 else if (row == halfK) {kernel[i] = 1;}
1256 else {kernel[i] = 0;}
1257 }
1258 else if ((row == halfK) && (col == halfK)) {
1259 kernel[i] = 1;
1260 }
1261 else {kernel[i] = 0;}
1262 }
1263 }
1264 } // end cross/axial
1265 else if ( kernelShape == VERT_KERNEL) {
1266 int row; // indicates current row
1267 int col; // indicates current column
1268 if (sliceFiltering) {
1269 for (i = 0; i < kernel.length; i ) {
1270 row = i/kernelSize;
1271 col = i%kernelSize;
1272
1273 if (col == halfK) {kernel[i] = 1;}
1274 else if (row == halfK) {kernel[i] = 0;}
1275 else {kernel[i] = 0;}
1276 }
1277 }
1278 else { // volume filtering
1279 }
1280 } // end vert
1281
|- |
1282 else if ( kernelShape == HORZ_KERNEL) {
1283 int row; // indicates current row
1284 int col; // indicates current column
1285 if (sliceFiltering) {
1286 for (i = 0; i < kernel.length; i ) {
1287 row = i/kernelSize;
1288 col = i%kernelSize;
1289
1290 if (col == halfK) {kernel[i] = 0;}
1291 else if (row == halfK) {kernel[i] = 1;}
1292 else {kernel[i] = 0;}
1293 }
1294 }
1295 else { // volume filtering
1296 }
1297 } // end vert
1298
1299 // 'x' kernel
1300 else if (kernelShape == X_KERNEL) {
1301 int row; // indicates current row
1302 int col; // indicates current column
1303 int revcol; // runs opposite of the col.
1304 if (sliceFiltering) {
1305 for (i = 0; i < kernel.length; i ) {
1306 row = i/kernelSize;
1307 col = i%kernelSize;
1308 revcol = kernelSize - 1 - col;
1309
1310 if (row == col) {kernel[i] = 1;}
1311 else if (row == revcol) {kernel[i] = 1;}
1312 else {kernel[i] = 0;}
1313 }
1314 }
1315 else { // volume filtering
1316 int slice;
1317 for (i = 0; i < kernel.length; i ) {
1318 slice = i/(kernelSize*kernelSize);
1319 row = (i%(kernelSize*kernelSize))/kernelSize;
1320 col = i%kernelSize;
1321 revcol = kernelSize - 1 - col;
1322
1323 if ((slice == col) ||
1324 (slice == revcol)) {
1325 if (row == col) {kernel[i] = 1;}
1326 else if (row == revcol) {kernel[i] = 1;}
1327 else {kernel[i] = 0;}
1328 }
1329 else {kernel[i] = 0;}
1330 }
1331 }
1332 } // end 'x' kernel
1333
1334 }
1335
1336 /**
1337
|- |
1338 * Makes the kernel mask.
1339 * The kernel mask is the list of values pulled from the
1340 * image which will be used to find the median of the
1341 * central pixel. Its length is
1342 * <i>(number of pixels to be used to determine median) 1</i>.
1343 * <p>
1344 * Thus the kernel center (decided here), has the value of
1345 * the location of the central pixel shown in the window.
1346 * The value of the kernel center is the number of pixels picked
1347 * up to median sort.
1348 *
1349 * Since the kernel mask is <i>number of pixels 1</i>,
1350 * the maskCenter must be
1351 */
1352 private void makeKernelMask() {
1353 halfK = kernelSize/2;
1354 // figure how many kernel elements are actually in the kernel-mask
1355 int count = 1; // start counting from one, since sort starts with element 1
1356 // (even empty mask must have 1 element!)
1357 for (int m = 0; m < kernel.length; m ) {
1358 if (kernel[m] != 0) // if this element is marked 'on'
1359 count ;
1360 }
1361 kernelMask = new float[count]; // must have the leading element empty: the sort
1362 // starts with element 1
1363 if (sliceFiltering) {// 2D
1364
1365 if (kernelShape == SQUARE_KERNEL){
1366 kernelCenter = count/2 - 1; // whole square
1367 maskCenter = halfK*(kernelSize 1) 1; // count/2 : I feel dumb
1368 }
1369 else if (kernelShape == CROSS_KERNEL || kernelShape == VERT_KERNEL || kernelShape ==
1370 HORZ_KERNEL) {
1371 kernelCenter = halfK*(kernelSize 1);
1372 maskCenter = kernelSize;
1373 }
1374 else if (kernelShape == X_KERNEL) { // sizeof kernel is same as CROSS_KERNEL
1375 kernelCenter = halfK*(kernelSize 1); // whole square -- (count/2-1)??
1376 maskCenter = kernelSize;
1377 }
1378 }
1379 else {//3D
1380 if (kernelShape == CUBE_KERNEL) {
1381 kernelCenter = count/2 - 1;
1382 maskCenter = halfK*(kernelSize*kernelSize kernelSize 1) 1;
1383 }
1384 else if (kernelShape == AXIAL_KERNEL) {
1385 kernelCenter = (kernelSize*kernelSize*kernelSize)/2; // whole cube
1386 maskCenter = count/2; // i feel dumb...
1387 }
1388 else if (kernelShape == X_KERNEL) { // sizeof kernel is same as AXIAL_KERNEL
1389 kernelCenter = (kernelSize*kernelSize*kernelSize)/2; // whole cube
1390 maskCenter = count/2; // i feel dumb...
1391 }
1392 }
|- |
1393 // not entirely dumb. mc = count/2 because of the symmetry of the mask. Custom masks
1394 // may be diff. & i'd like to include custom masks someday....
1395 }
1396
1397 /**
1398 * Compiles a list of the values neighboring the desired pixel, that are defined
1399 * in the kernel. Be careful because although the kernel starts its index at 0,
1400 * the list that is returned starts indexing at 1.
1401 * <p>
1402 * Color images are processed differently from the monochrome images because
1403 * although color images use the same size kernel as mono images, it fills the
1404 * kernel with brightness levels that are spread out in the data set. The
1405 * Neighbor list still reports the monochromatic brightness values. That is, for
1406 * a color image: the neighbors of the central pixel with the same color are
1407 * returned in the neighbor list's kernel.
1408 * @param i The central pixel to find neighbors for.
1409 * @param data Image data
1410 * @param is2D True indicates that the neighbors are found along a
1411 * 2D slice (or 2D image) instead of neighbors in a 3D volume.
1412 * @return The neighboring pixel list, where the list starts at 1 (leaving the
1413 initial
1414 * element 0), and corresponds to the kernel chosen.
1415 */
1416 private final float[] getNeighborList(int i, float[] data, boolean is2D) {
1417 int row, col;
1418 int kCenter = kernelCenter; // index to the central element of the kernel
1419 // (this is the mask for which elements in data are
1420 // used.)
1421 int width = 0; // width of slice in number of pixels
1422 int height = 0; // height of slice in number of pixels
1423
1424 try {
1425 width = srcImage.getExtents()[0];
1426 height = srcImage.getExtents()[1];
1427 } catch (NullPointerException npe) {
1428 Preferences.debug("AlgorithmMedian: null pointer while making neighbor list.");
1429 setThreadStopped(true);
1430 setCompleted(false);
1431 }
1432 int sliceWidth = width * valuesPerPixel; // width of slice in number of
1433 // elements
1434
1435 // place all the masked 'on' elements into the data-list
1436 int count = 1;
1437 // color images are different from the mono images in that though color images
1438 // use the same size kernel as mono images, but fill it with brightness levels
1439 // that are spread out in the data set.
1440
|- |
1441 int kcol;
1442 int leftBound = -halfK * 4;
1443 int rightBound = halfK * 4;
1444 if (is2D) {
1445 for (row = -halfK; row <= halfK; row ) { // go through all rows
1446 for (col = leftBound, kcol = -halfK; col <= rightBound; col = 4, kcol ) {
1447 // go through every 4th column
1448 if (kernel[kCenter kcol row*kernelSize] != 0) {// but don't bother
1449 // copying into the list
1450 // if we don't want that
1451 // that element (the
1452 // kernel's pixl is zero)
1453 kernelMask[count ] = data[i col row*sliceWidth];
1454 }
1455 }
1456 }
1457 }
1458 else { // find neighbors in a volume
1459 int slice;
1460 // halfK-number of kernelSize slices (to get to the center slice)
1461 for (slice = -halfK; slice <= halfK; slice ) {
1462 for (row = -halfK; row <= halfK; row ) {
1463 for (col = leftBound, kcol = -halfK; col <= rightBound; col = 4, kcol ) {
1464 if (kernel[kCenter kcol row*kernelSize slice*kernelSize*kernelSize]
1465 != 0) {
1466 kernelMask[count ] =
1467 data[i col row*sliceWidth slice*sliceWidth*height];
1468 }
1469 }
1470 }
1471 }
1472 }
1473 }
1474 else { // a mono image
1475 if (is2D) {
1476 for (row = -halfK; row <= halfK; row ) { // go through all rows
1477 for (col = -halfK; col <= halfK; col ) { // go through all columns
1478 if (kernel[kCenter col row*kernelSize] != 0) { // but don't bother
1479 // copying into the list
1480 // if we don't want
1481 // that element (the
1482 // kernel's pixl is zero)
1483 kernelMask[count ] = data[i col row*width];
1484 }
1485 }
1486 }
1487 }
1488 if (isColorImage) { // 2D filtering of color images is a little different
1489 // than of mono images
1490 else { // find neighbors in a volume
1491 int slice;
1492 // halfK-number of kernelSize slices (to get to the center slice)
1493 for (slice = -halfK; slice <= halfK; slice ) {
1494 for (row = -halfK; row <= halfK; row ) {
|- |
1495 for (col = -halfK; col <= halfK; col ) {
1496 if (kernel[kCenter col row*kernelSize slice*kernelSize*kernelSize] !=
1497 0) {
1498 kernelMask[count ] = data[i col row*width slice*width*height];
1499 }
1500 }
1501 }
1502 }
1503 }
1504 }
1505 return (kernelMask);
1506 }
1507
1508 /**
1509 * Sorts a list of values. Taken from Numerical Recipes in C, 2nd ed. William H.
1510 * Press, et al, page 332. Chose shell sort over a quicksort because both shell
1511 * and quick are about the same speed for the middle range of sizes of the list.
1512 * The list is more likely during a slice-filter operation to be smaller than the
1513 * maximum 121 length. The list could be as much as 1331 elements, but according
1514 * to Numerical Recipes, it still runs fast enough at only N**1.25 an average for
1515 * N < 60000). My guess is that sliceFilter is more useful than a volumeFilter
1516 * and will be plenty fast enough to not necessitate a quicksort for a
1517 * debatable speed-increase.
1518 *
1519 * @param float a[] The list to sort.
1520 */
1521 private final void shellSort(float a[]) {
1522 int N = a.length - 1;
1523 int i, j;
1524 int inc = 1;
1525 float val;
1526
1527 do {
1528 inc *=3;
1529 inc ;
1530 } while (inc <= N);
1531 do {
1532 inc /=3;
1533 for (i = inc 1; i <= N; i ) {
1534 val = a[i];
1535 j = i;
1536 while (a[j - inc] > val) {
1537 a[j] = a[j - inc];
1538 j -= inc;
1539 if (j <= inc) break;
1540 }
1541 a[j] = val;
1542 }
1543 }while (inc > 1);
1544 }
1545 /**
1546 * Finds the median value of the list. Median assumes the list of values starts
1547 * at index 1, not an index of 0. (i.e., 1st element is not included.)
1548 * @param list List of numbers
1549 * @return The median.
|- |
1550 * @author parsonsd
1551 */
1552 private final float median(float list[]) {
1553 int N;
1554 float med;
1555
1556 N = list.length - 1;
1557
1558 if ((N%2) != 0) {
1559 med = list[N/2];
1560 }
1561 else {
1562 med = (list[N/2] list[N/2 1])/2;
1563 }
1564 return (med);
1565 }
1566
1567 /**
1568 * Finds the mean value (average) in the list. Mean assumes the list of
1569 * values starts at index 1, not an index of 0. (i.e., 1st element is not
1570 * included.)
1571 * @param list List of numbers
1572 * @return float The mean.
1573 * @author parsonsd
1574 */
1575 private final float mean(float list[]) {
1576 int i;
1577 float sum = 0;
1578
1579 for (i = 1; i < list.length; i ) {
1580 sum = list[i];
1581 }
1582 return (float)(sum/(list.length - 1)); // length-1 because list goes from
1583 // [1 ... N]
1584 }
1585
1586 /**
1587 * Finds the standard deviation of the values in the input list
1588 * (defined as: s = [(1/(N-2))*SUM (from 1 to N-1)[ (Xi - <bold>X</
1589 * bold>)^2]]^(1/2))
1590 * @param list The list of numbers.
1591 * @param average Arithmetic mean of the values in list.
1592 * @return The standard deviation.
1593 */
|- |
1594 private final float standardDeviation(float list[], float average) {
1595 int i;
1596 int N = list.length;
1597
1598 double sum = 0.0;
1599
1600 for (i = 1; i < N; i ) {
1601 sum = (list[i] - average)*(list[i] - average);
1602 }
1603 return ((float) Math.sqrt(sum/(N-2))); // sqrt((1/(N-2)) * sum)
1604 }
1605
1606
1607 /**
1608 * Creates the standard progressBar. Stores in the class-global, progressBar.
1609 */
1610 private void buildProgressBar(){
1611 try {
1612 if (pBarVisible == true) {
1613 progressBar = new ViewJProgressBar(srcImage.getImageName(), "Filtering
1614 image ...",
1615 0, 100, true, this, this);
1616 int xScreen = Toolkit.getDefaultToolkit().getScreenSize().width;
1617 int yScreen = Toolkit.getDefaultToolkit().getScreenSize().height;
1618 progressBar.setLocation(xScreen/2, yScreen/2);
1619 progressBar.setVisible(true);
1620 }
1621 } catch (NullPointerException npe) {
1622 if (Preferences.isDebug()) {
1623 Preferences.debug("AlgrithmMedian: NullPointerException found while building
1624 progress bar.");
1625 }
1626 }
1627 }
1628
1629 /**
1630 * If the progress bar is visible, sets the text to: <br><tt>Copying all <i>color</i> values
1631 * ... </tt>
1632 * @param colorText The color to use. E.g., "red" or "blue".
1633 */
1634 private void setCopyColorText(String colorText)
1635 {
1636 try {
1637 if (pBarVisible == true) {
1638 progressBar.setMessage("Copying all " colorText " values ... ");
1639 }
1640 } catch (NullPointerException npe) {
1641 if (Preferences.isDebug()) {
1642 Preferences.debug("AlgrithmMedian: NullPointerException found while setting
1643 progress bar text.");
1644 }
1645 }
1646 }
|}