PlugIn Algorithm Median (con't, part 3)

From MIPAV
Jump to: navigation, search
804 if (numberOfSlices > 1) { //3D image update progressBar
</font></div>
805 // do a progress bar update
806 progressBar.setValue(Math.round
807 (( ( (float)(currentSlice*iterations pass)/
808 (iterations*numberOfSlices))* 100)));
809 }
810 }
811 for ( i = 0; i < imageSliceLength && !threadStopped; i ){
812 if (numberOfSlices == 1) { // 2D image update progressBar
813 if (i%mod == 0 && pBarVisible == true) {
814 progressBar.setValue(Math.round
815 ( ( (float)( (pass*imageSliceLength) i)
816 /(iterations*(imageSliceLength -1))*100)) );
817 }
818 }
819 if (entireImage == true || mask.get(a) ) {
820 // Median stuff here
821 row = i/width;
822 col = i%width;
823 if ( (row < upperBound) || (row > lowerBound) ) {
824 destBuffer[a] = srcBuffer[a]; // row too far up or down--out of
825 // bounds
826 }
827 else if ((col < leftBound) || (col > rightBound)) {
828 destBuffer[a] = srcBuffer[a]; // column too far left or right-
829 // -out of bounds
830 }
831
|- |
832 else { // in bounds
833 maskedList = getNeighborList(a, srcBuffer, true);
834 // verify that this element is an outlier
835 if (stdDevLimit == 0.0) { // anything is an outlier
836 shellSort(maskedList);
837 destBuffer[a] = median(maskedList);
838 }
839 else { // look for outlierness
840 average = mean(maskedList);
841 sigma = standardDeviation(maskedList, average);
842 if ((maskedList[kCenter] > (average stdDevLimit*sigma)) ||
843 (maskedList[kCenter] < (average - stdDevLimit*sigma))) {
844 shellSort(maskedList);
845 destBuffer[a] = median(maskedList);
846 }
847 else { // if element was not an outlier, pixel is fine.
848 destBuffer[a] = srcBuffer[a];
849 }
850 }
851 }
852 }
853 else { // not part of the VOI so just copy this into the destination
854 buffer.
855 destBuffer[a] = srcBuffer[a];
856 }
857 a ; // address the next data element from the bufferStartingPoint
858 }
859 }
860
861 // now set up for the repeat for multiple iterations.
862 // But only bother with copying over if there are more iterations.
863 if (pass < iterations - 1) {
864 tempBuffer = destBuffer; // swap dest & src buffers
865 destBuffer = srcBuffer;
866 srcBuffer = tempBuffer;
867 }
868 }
869 // destBuffer should now be copied over for the size of imageSliceLength.
870 // You may return.
871
872 }
873
874 /**
875 * Filter a 3D image with a 3D kernel. Allows median filtering to include the
876 * picture elements at greater depths than only the current slice.
877 * <p><em>Note that this volume filter will correctly filter color images on all
878 * bands (aRGB) because the neighbor list is correct (see getNeighborList()).
879 * This means, however, it will not selectivly filter any bands (one may not
880 * filter only the Red channel, for instance), and will also filter all alpha
881 * values as well. Of course, progress bar updates will not include any
882 * color information. For these reasons it a useable, but limited color
883 * filter.</em>
884 * @param srcBuffer Source image.
885 * @param destBuffer Destination image.
|- |
886 * @see volumeColorFilter
887 * @see getNeighborList
888 *
889 */
890 // some code has been left in to allow this method to properly filter
891 // color images, although the other method is included.
892
893 private void volumeFilter(float srcBuffer[], float destBuffer[]) {
894 int i, pass; // counting the current element
895 int row, // ease of reading to find the row, column and slice
896 column, // (all starting at 0) associated with the current element
897 slice; // [(0,0,0) starts at the closest upper-left corner]
898 int imageSliceLength = srcImage.getSliceSize() * valuesPerPixel;
899 int imageLength = imageSliceLength * numberOfSlices;
900 int kCenter = maskCenter;
901 int width = srcImage.getExtents()[0]; // width of slice in number of pixels
902 int height = srcImage.getExtents()[1]; // height of slice in number of pixels
903 int sliceWidth = width*valuesPerPixel; // width of slice in number of intensity
904 // values (as in colors per pixel (1 for
905 // mono, 4 for color))
906 float tempBuffer[];
907
908 float average; // arithmetic mean
909 float sigma; // standard deviation
910
911 float maskedList[]; // list of buffer-values that were showing inside the
912 // mask these bounds "frame" the interior of the slice which may be filtered
913 // (&adjusted); image outside the frame may not
914 int leftBound, rightBound, // bounds on the column
915 upperBound, lowerBound, // bounds on the row
916 aheadBound, behindBound; // bounds on the slice
917 // (a note on orientation: object front is facing in the same direction as
918 // viewer, thus ahead of viewer is into monitor, behind is out of monitor and
919 // a more positive number of slices is farther forward.)
920 upperBound = halfK;
921 lowerBound = height - halfK -1;
922 behindBound = halfK;
923 aheadBound = numberOfSlices - halfK - 1;
924 // we may say that each column is a pixel intensity: mono images have 1 per
925 // pixel, 4 in color;
926 // these calculations are done separately for color & mono images in
927 // sliceFilter().
928 leftBound = halfK * valuesPerPixel;
929 rightBound = sliceWidth - valuesPerPixel*halfK - 1; // in color: (4*width - 4*halfK
930 // - 1); mono: (width -
931 // halfK - 1)
932 int mod = (imageLength)/100; // mod is 1 percent of length of slice * the number
933 // of slices.
934
935 BitSet mask = srcImage.generateVOIMask();
936 for (pass = 0; pass < iterations && !threadStopped; pass ) {
937 if (pBarVisible == true) {
938 progressBar.setMessage("Filtering image (pass " String.valueOf(pass 1) " of "
939 iterations ") ...");
940 }
941
|- |
942 for ( i = 0; i < imageLength && !threadStopped; i ){
943 if (i%mod == 0 && pBarVisible == true) {
944 progressBar.setValue(Math.round
945 ( ( (float)( (pass*imageLength) i)/(iterations*(imageLength-1))*100)) );
946 }
947
948 if (entireImage == true || mask.get(i/valuesPerPixel) ) {
949 // Median stuff here
950 slice = i/imageSliceLength;
951 row = (i%imageSliceLength)/sliceWidth;
952 column = i%sliceWidth;
953
954 if ( (row < upperBound) || (row > lowerBound) ) {
955 destBuffer[i] = srcBuffer[i]; // row too far up or down--out of
956 // bounds
957 }
958 else if ((column < leftBound) || (column > rightBound)) {
959 destBuffer[i] = srcBuffer[i]; // column too far left or right--out
960 // of bounds
961 }
962 else if ((slice < behindBound) || (slice > aheadBound)) {
963 destBuffer[i] = srcBuffer[i]; // slice too far ahead or behind--out
964 // of bounds
965 }
966 else { // in bounds
967 maskedList = getNeighborList(i, srcBuffer, false);
968 // verify that this element is an outlier
969 if (stdDevLimit == 0.0) { // anything is an outlier
970 shellSort(maskedList);
971 destBuffer[i] = median(maskedList);
972 }
973 else { // look for outlierness
974 average = mean(maskedList);
975 sigma = standardDeviation(maskedList, average);
976 if ((maskedList[kCenter] > (average stdDevLimit*sigma)) ||
977 (maskedList[kCenter] < (average - stdDevLimit*sigma))) {
978 shellSort(maskedList);
979 destBuffer[i] = median(maskedList);
980 }
981 else { // if element was not an outlier, pixel is fine.
982 destBuffer[i] = srcBuffer[i];
983 }
984 }
985 }
986 }
987 else { // not part of the VOI so just copy this
988 // into the destination buffer.
989 destBuffer[i] = srcBuffer[i];
990 }
991 }
992 // now set up for the repeat for multiple iterations.
993 // But only bother with copying over if there are more iterations.
994 if (pass < iterations - 1) {
995 tempBuffer = destBuffer; // swap src & dest buffer
996 destBuffer = srcBuffer;
997 srcBuffer = tempBuffer;
998 }
|- |
999 }
1000 }
1001 /**
1002 * Filter a Color 3D image with a 3D kernel. Allows median filtering to
1003 * include the picture elements at greater depths than only the current
1004 * slice. This method allows selected band filtering, and does not filter
1005 * the alpha band.
1006 * @param srcBuffer Source image.
1007 * @param destBuffer Destination image.
1008 * @see volumeFilter
1009 *
1010 */
1011 private void volumeColorFilter(float srcBuffer[], float destBuffer[]) {
1012 int i, pass; // counting the current element
1013 int initialIndex; // reference to the color band being filtered/copied: aRBG:
1014 // 0, 1, 2, 3;
1015 // it is an offset to the identified pixel, or column, of
1016 // the slice
1017 int row, // ease of reading to find the row, column and slice
1018 column, // (all starting at 0) associated with the current element
1019 slice; // [(0,0,0) starts at the closest upper-left corner]
1020 int kCenter = maskCenter;
1021 int width = srcImage.getExtents()[0]; // width of slice in number of pixels
1022 int height = srcImage.getExtents()[1]; // height of slice in number of pixels
1023 int sliceWidth = width*valuesPerPixel; // width of slice in number of
1024 // intensity values (as in colors per
1025 // pixel (1 for mono, 4 for color))
1026 int sliceSize = width * height; // in pixels (or elements)
1027 int imageSliceLength = width * height * valuesPerPixel; // in values-pixels
1028 int imageSize = sliceSize * numberOfSlices; // in pixels (or elements)
1029 int imageLength = imageSliceLength * numberOfSlices; // in (values-pixels)
1030 float tempBuffer[];
1031
1032 float average; // arithmetic mean
1033 float sigma; // standard deviation
1034
1035 float maskedList[]; // list of buffer-values that were showing inside the
1036 // mask
1037 // these bounds "frame" the interior of the slice which may be
1038 // filtered (&adjusted); image outside the frame may not
1039 int leftBound, rightBound, // bounds on the column
1040 upperBound, lowerBound, // bounds on the row
1041 aheadBound, behindBound; // bounds on the slice
1042 // (a note on orientation: object front is facing in the same direction as
1043 // viewer, thus ahead of viewer is into monitor, behind is out of monitor and
1044 // a more positive number of slices is farther forward.)
1045 upperBound = halfK;
1046 lowerBound = height - halfK -1;
1047 behindBound = halfK;
1048 aheadBound = numberOfSlices - halfK - 1;
1049 // we may say that each column is a pixel intensity: mono images have 1 per
1050 // pixel, 4 in color; these calculations are done separately for color &
1051 // mono images in sliceFilter().
1052 leftBound = halfK * valuesPerPixel;
1053 rightBound = sliceWidth - valuesPerPixel*halfK - 1; // in color: (4*width -
1054 // 4*halfK - 1); mono:
1055 // (width - halfK - 1)
|- |
1056 int mod = (imageSize)/100; // mod is 1 percent of length of slice * the number
1057 // of slices.
1058
1059 BitSet mask = srcImage.generateVOIMask();
1060
1061 // copy all alpha values in the image
1062 setCopyColorText("alpha");
1063 for (i = 0; i < imageLength; i =4) {
1064 destBuffer[i] = srcBuffer[i]; // copy alpha;
1065 }
1066
1067 // choose i so the proper colors go alongside the initial index
1068 // so we get the right output statements in the progress bar
1069 // copy only needed RGB values
1070 initialIndex = 0; // start with alpha on each pass (routine moved so we don't
1071 // do it for each pass)
1072 while (initialIndex < 3 && !threadStopped) { // alpha:0, R:1, G:2, B:3. But
1073 // alpha must be copied
1074 initialIndex; // next initial index
1075
1076 if (!rChannel && initialIndex==1) {
1077 // when looking at the image reds but we're not filtering the red
1078 // channel copy all red values
1079 setCopyColorText("red");
1080 for (i = initialIndex; i < imageLength; i =4) {
1081 destBuffer[i] = srcBuffer[i];
1082 }
1083 }
1084 else if (!gChannel && initialIndex==2) { // when looking at the image greens
1085 // but we're not filtering the
1086 // greens channel copy all greens
1087 // values
1088 setCopyColorText("green");
1089 for (i = initialIndex; i < imageLength; i =4) {
1090 destBuffer[i] = srcBuffer[i];
1091 }
1092 }
1093 else if (!bChannel && initialIndex==3) {
1094 // when looking at the image blues but we're not filtering the
1095 // blues channel copy all blue values
1096 setCopyColorText("blue");
1097 for (i = initialIndex; i < imageLength; i =4) {
1098 destBuffer[i] = srcBuffer[i];
1099 }
1100 }
1101 else {
1102 for (pass = 0; pass < iterations && !threadStopped; pass ) {
1103 if (pBarVisible == true) {
1104 if (initialIndex == 1) {
1105 progressBar.setMessage("Filtering red channel (pass "
1106 String.valueOf(pass 1) " of " iterations ") ...");
1107 }
1108 else if (initialIndex == 2) {
1109 progressBar.setMessage("Filtering green channel (pass "
1110 String.valueOf(pass 1) " of " iterations ") ...");
1111 }
1112
|- |
1113 else if (initialIndex == 3) {
1114 progressBar.setMessage("Filtering blue channel (pass "
1115 String.valueOf(pass 1) " of " iterations ") ...");
1116 }
1117 }
1118 // if we needed to filter the image, we dropped through the
1119 // selection to filter the color given by ints initialIndex
1120 for ( i = initialIndex; i < imageLength && !threadStopped; i =4){
1121 if (i%mod == 0 && pBarVisible == true) {
1122 progressBar.setValue(Math.round
1123 ( ( (float)(iterations*(initialIndex - 1)*imageSize imageSize*pass
1124 i/4)/(3*iterations*(imageSize-1))*100)) );
1125 }
1126
1127 if (entireImage == true || mask.get(i/valuesPerPixel) ) {
1128 // Median stuff here
1129 slice = i/imageSliceLength;
1130 row = (i%imageSliceLength)/sliceWidth;
1131 column = i%sliceWidth;
1132
1133 if ( (row < upperBound) || (row > lowerBound) ) {
1134 destBuffer[i] = srcBuffer[i]; // row too far up or down--out of
1135 // bounds
1136 }
1137 else if ((column < leftBound) || (column > rightBound)) {
1138 destBuffer[i] = srcBuffer[i]; // column too far left or right--
1139 // out of bounds
1140 }
1141 else if ((slice < behindBound) || (slice > aheadBound)) {
1142 destBuffer[i] = srcBuffer[i]; // slice too far ahead or behind--
1143 // out of bounds
1144 }
1145 else { // in bounds
1146 maskedList = getNeighborList(i, srcBuffer, false);
1147 // verify that this element is an outlier
1148 if (stdDevLimit == 0.0) { // anything is an outlier
1149 shellSort(maskedList);
1150 destBuffer[i] = median(maskedList);
1151 }
1152 else { // look for outlierness
1153 average = mean(maskedList);
1154 sigma = standardDeviation(maskedList, average);
1155 if ((maskedList[kCenter] > (average stdDevLimit*sigma)) ||
1156 (maskedList[kCenter] < (average - stdDevLimit*sigma))) {
1157 shellSort(maskedList);
1158 destBuffer[i] = median(maskedList);
1159 }
1160 else { // if element was not an outlier, pixel is fine.
1161 destBuffer[i] = srcBuffer[i];
1162 }
1163 }
1164 }
1165 }
1166
|- |
1167 else { // not part of the VOI so just copy this into the
1168 // destination buffer.
1169 destBuffer[i] = srcBuffer[i];
1170 }
1171 }
1172 // now set up for the repeat for multiple iterations.
1173 // But only bother with copying over if there are more iterations.
1174 if (pass < iterations - 1) {
1175 tempBuffer = destBuffer; // swap src & dest buffer
1176 destBuffer = srcBuffer;
1177 srcBuffer = tempBuffer;
1178 }
1179 }
1180 if (iterations%2 == 0) { // if even number of iterations, then
1181 tempBuffer = destBuffer; // swap src & dest buffer is necessary
1182 destBuffer = srcBuffer; // to keep other colors not-yet-filtered
1183 // from
1184 srcBuffer = tempBuffer; // filtering from the wrong buffer,
1185 // overwriting the real src
1186 }
1187 }
1188 }
1189 }
1190
1191 /**
1192 * Forms kernel. Note that the <bold>kernel</bold> uses the 0th place, unlike the
1193 * kernelMask where counting starts at 1.
1194 *
1195 */
1196 private void makeKernel(){
1197 try {
1198 if (sliceFiltering)
1199 kernel = new byte[kernelSize*kernelSize];