Übung 6:

Einleitung: Nutze für die Aufgaben die neue Java bmp_io_ue6_vStud.java. Für die Übung benötigt ihr außerdem eure eigenen Bildaufnahmen (Detail und Fläche), und zwar die Graustufenversionen nach der Formel Y=0.3 x R + 0,6 x G + 0,1 x B.

Aufgabe 1: Mittelwertfilter (Tiefpass)

a. Erweitere bmp_io so, dass ein Filter mit einem Kernel von 3x3 Pixeln angewandt werden kann. Beim Mittelwertfilter wird ein Zielpixel aus dem Mittelwert aller Pixel im Kernel im Originalbild berechnet. Beschreibe die Wirkung des Filters auf deine Bilder!

b. Wie verfährt man bei der Berechnung des Filters mit den Randpixeln?

c. Erweitere bmp_io so, dass das Differenzbild zwischen dem gefilterten und dem Originalbild berechnet werden kann (analog zu Übung 2, Aufgabenpunkt 3.3)! Dieses muss offensichtlich die Information zeigen, die das Filter entfernt hat. Beachte dabei, dass du das Differenzbild möglicherweise im Kontrast verstärken musst (siehe Übung 4).

Lösung:

6.1.a

Sourcecode
private static void mittelwertfilter(String inFilename, String outputFileName) throws IOException {
			  BmpImage bmpImageOriginal = BmpReader.read_bmp(new FileInputStream(inFilename));
			  BmpImage bmpImageFiltered = BmpReader.read_bmp(new FileInputStream(inFilename));
			  OutputStream out = new FileOutputStream(outputFileName);

			  int height = bmpImageOriginal.image.getHeight();
			  int width = bmpImageOriginal.image.getWidth();

			  for (int y = 0; y < height; y++) {
			     for (int x = 0; x < width; x++) {
			        // Kernel[x][y]
			        int[][] kernel = new int[3][3];

			        for(int i = 0; i < 3; i++) { // x
			           for(int j = 0; j < 3; j++) { // y
			              int xKernel = x + (j-1);
			              int yKernel = y + (i-1);

			              if (pixelIsInPicture(xKernel, yKernel, width, height)) {
			                 kernel[i][j] = bmpImageOriginal.image.getRgbPixel(xKernel, yKernel).r;
			              } else {
			                 kernel[i][j] = 0;
			              }
			           }
			        }

			        int average = average(kernel);

			        PixelColor color = new PixelColor(average, average, average);
			        bmpImageFiltered.image.setRgbPixel(x, y, color);
			     }
			  }

			  try {
			     BmpWriter.write_bmp(out, bmpImageFiltered);
			  } finally {
			     out.close();
			  }
			}

		 	private static boolean pixelIsInPicture(int x, int y, int width, int height) {
				 return (x >= 0 && y >= 0 && x < width && y < height);
			}

			private static int average(int[][] kernel) {
				 double average = 0;
				 for(int x = 0; x < kernel.length; x++) { // x
						for(int y = 0; y < kernel.length; y++) { // y
							 average += kernel[x][y];
						}
				 }
				 return (int) (roundValue(average / (kernel.length * kernel.length), 0));
			}

			private static double roundValue(double value, int decimals) {
				 return Math.round(value * Math.pow(10, decimals))/ Math.pow(10, decimals);
			}
		
Bilder
Original Mittelwertfilter
Details_Atom-greyscale Details_Atom-mittelwertfilter
Flaechen_Atom-greyscale Flaechen_Atom-mittelwertfilter

Die Bilder werden durch den Filter unscharf.

6.1.b

Pixel die außerhalb des Bildes liegen bekommen für die Mittelwertberechnung den Wert 0.

6.1.c

Sourcecode
private static void differenzbild(String original, String filtered, String outputFileName) throws IOException {
			   BmpImage originalimage = BmpReader.read_bmp(new FileInputStream(original));
			   BmpImage filteredimage = BmpReader.read_bmp(new FileInputStream(filtered));
			   BmpImage difference = BmpReader.read_bmp(new FileInputStream(filtered));
			   OutputStream out = new FileOutputStream(outputFileName);

			   for (int y = 0; y < originalimage.image.getHeight(); y++) {
			      for (int x = 0; x < originalimage.image.getWidth(); x++) {
			         int originalValue = originalimage.image.getRgbPixel(x, y).r;
			         int filteredValue = filteredimage.image.getRgbPixel(x, y).r;

			         int differenceValue = Math.abs(originalValue - filteredValue);

			         PixelColor color = new PixelColor(differenceValue, differenceValue, differenceValue);
			         difference.image.setRgbPixel(x, y, color);
			      }
			   }

			   try {
			      BmpWriter.write_bmp(out, difference);
			   } finally {
			      out.close();
			   }
			}
		
Bilder
Differenz Kontrastverstärkt
Details_Atom-differenz Details_Atom-differenz-kontrastverstaerkt
Flaechen_Atom-differenz Flaechen_Atom-differenz-kontrastverstaerkt

Aufgabe 2: Gradientenfilter

a. Wende nun den folgenden 3*3 Kernel auf deine Bilder an! Beachte dabei, dass bei der direkten Anwendung der Vorschrift Werte > 255 entstehen können. Durch welchen Wert muss also die Intensität des Zielpixels geteilt werden, damit man wieder in den erlaubten Bereich 0...255 kommt? Beschreibe die Wirkung des Filters auf deine Bilder!

phototask
b. Berechne wiederum das Differenzbild zwischen dem gefilterten und dem Originalbild! Beachte dabei ebenfalls, dass du das Differenzbild möglicherweise im Kontrast verstärken musst.

Lösung:

6.2

Sourcecode
private static void gradientenfilter(String inFilename, String outputFileName) throws IOException {
		       BmpImage bmpImageOriginal = BmpReader.read_bmp(new FileInputStream(inFilename));
		       BmpImage bmpImageFiltered = BmpReader.read_bmp(new FileInputStream(inFilename));
		       OutputStream out = new FileOutputStream(outputFileName);

		       int height = bmpImageOriginal.image.getHeight();
		       int width = bmpImageOriginal.image.getWidth();

		       // Iterate over every pixel in picture
		       for (int y = 0; y < height; y++) {
		          for (int x = 0; x < width; x++) {
		             // Kernel[x][y]
		             int[][] pixelkernel = new int[3][3];
		             int[][] filterkernel = {{0, -2, 0},{-2, 12 ,-2},{0, -2, 0}};

		             // Build Kernel for pixel
		             for(int i = 0; i < 3; i++) { // x
		                for(int j = 0; j < 3; j++) { // y
		                   int xKernel = x + (j-1);
		                   int yKernel = y + (i-1);

		                   if (pixelIsInPicture(xKernel, yKernel, width, height)) {
		                      pixelkernel[i][j] = bmpImageOriginal.image.getRgbPixel(xKernel, yKernel).r;
		                   } else {
		                      pixelkernel[i][j] = 0;
		                   }
		                }
		             }

		             pixelkernel = matrizenmultiplikation(pixelkernel, filterkernel);
		             int sum = sumOfAllMatrixValues(pixelkernel)/4;

		             if(sum < 0) sum = 0;
		             else if (sum > 255) sum = 255;

		             PixelColor color = new PixelColor(sum, sum, sum);
		             bmpImageFiltered.image.setRgbPixel(x, y, color);
		          }
		       }

		       try {
		          BmpWriter.write_bmp(out, bmpImageFiltered);
		       } finally {
		          out.close();
		       }
		    }

		    private static int sumOfAllMatrixValues(int[][] matrix) {
		       int sum = 0;

		       for (int row = 0; row < 3; row++){
		          for(int column = 0; column < 3; column++){
		             sum += matrix[column][row];
		          }
		       }

		       return sum;
		    }

				private static int[][] matrizenmultiplikation(int[][] matrix_A, int[][] matrix_B) {
					 int[][] matrix_C = new int[3][3];

					 for (int row = 0; row < 3; row++){
							for(int column = 0; column < 3; column++){
								 matrix_C[column][row] = (matrix_A[column][row]*matrix_B[column][row]);
							}
					 }

					 return matrix_C;
				}
			
Bilder
Gradientenfilter Differenz
Details_Atom-gradientenfilter Details_Atom-differenz-gradientenfilter
Flaechen_Atom-gradientenfilter Flaechen_Atom-differenz-gradientenfilter

Es muss durch vier geteilt werden (Werte der Matrix aufaddieren).

Die Bilder werden durch den Filter deutlich schärfer und kontrastreicher

Aufgabe 3: Medianfilter

Das Medianfilter reiht alle Pixelintensitäten im Filterkernel der Größe nach auf und gibt den Intensitätswert aus, der an der mittleren Position steht. Es wird oft zur Beseitigung von Kratzern oder punktförmigen Bildfehlern verwendet. Füge zunächst mit Paint deinem Flächenbild zehn „Fehler“ hinzu, wie es in dem folgenden Beispiel zu sehen ist. Benutze dazu einen weißen Stift mit der Strichstärke 2 Pixel. Programmiere das Medianfilter für deine 3x3-Pixelmatrix und berechne das Ergebnisbild.

Lösung:

6.3

Sourcecode
private static void medianfilter(String inFilename, String outputFileName) throws IOException {
      BmpImage bmpImageOriginal = BmpReader.read_bmp(new FileInputStream(inFilename));
      BmpImage bmpImageFiltered = BmpReader.read_bmp(new FileInputStream(inFilename));
      OutputStream out = new FileOutputStream(outputFileName);

      int height = bmpImageOriginal.image.getHeight();
      int width = bmpImageOriginal.image.getWidth();

      // Iterate over every pixel in picture
      for (int y = 0; y < height; y++) {
         for (int x = 0; x < width; x++) {
            // Kernel[x][y]
            int[][] pixelkernel = buildPixelkernel(bmpImageOriginal, y, x);

            int[] pixelvalues = makeOneDimensionalArrayOutOfTwoDimensionalArray(pixelkernel);
            int median = medianOfUnevenArray(pixelvalues);

            PixelColor color = new PixelColor(median, median, median);
            bmpImageFiltered.image.setRgbPixel(x, y, color);
         }
      }

      try {
         BmpWriter.write_bmp(out, bmpImageFiltered);
      } finally {
         out.close();
      }
   }

   private static int[][] buildPixelkernel(BmpImage image, int y, int x) {
      int height = image.image.getHeight();
      int width = image.image.getWidth();
      int[][] pixelkernel = new int[3][3];

      // Build Kernel for pixel
      for(int i = 0; i < 3; i++) { // x
         for(int j = 0; j < 3; j++) { // y
            int xKernel = x + (j-1);
            int yKernel = y + (i-1);

            if (pixelIsInPicture(xKernel, yKernel, width, height)) {
               pixelkernel[i][j] = image.image.getRgbPixel(xKernel, yKernel).r;
            } else {
               pixelkernel[i][j] = 0;
            }
         }
      }
      return pixelkernel;
   }
Bilder
Beschädigtes Original Medianfilter
Details_Atom-greyscale-damaged Details_Atom-medianfilter
Flaechen_Atom-greyscale-damaged Flaechen_Atom-medianfilter

Aufgabe 4: Sobel-Filter

Das Sobel-Filter dient der Detektion von Kanten im Bild. Programmiere ein Sobel-Filter für die x- und ein Sobel-Filter für die y-Richtung und wende sie auf deine Bilder an! Die Matrizen für das Sobel- Filter finden sich im pdf zur Bildfilterung.

Lösung:

6.4

Sourcecode
   private static void sobelfilterHorizontal(String inFilename, String outputFileName) throws IOException {
      BmpImage bmpImageOriginal = BmpReader.read_bmp(new FileInputStream(inFilename));
      BmpImage bmpImageFiltered = BmpReader.read_bmp(new FileInputStream(inFilename));
      OutputStream out = new FileOutputStream(outputFileName);

      int height = bmpImageOriginal.image.getHeight();
      int width = bmpImageOriginal.image.getWidth();

      // Iterate over every pixel in picture
      for (int y = 0; y < height; y++) {
         for (int x = 0; x < width; x++) {
            // Kernel[x][y]
            int[][] pixelkernel = buildPixelkernel(bmpImageOriginal, y, x);
            int[][] filterkernel = {{1, 2, 1},{0, 0 ,0},{-1, -2, -1}};

            pixelkernel = matrizenmultiplikation(pixelkernel, filterkernel);
            int sum = sumOfAllMatrixValues(pixelkernel);

            if(sum < 0) sum = 0;
            else if (sum > 255) sum = 255;

            PixelColor color = new PixelColor(sum, sum, sum);
            bmpImageFiltered.image.setRgbPixel(x, y, color);
         }
      }

      try {
         BmpWriter.write_bmp(out, bmpImageFiltered);
      } finally {
         out.close();
      }
   }

   private static void sobelfilterVertical(String inFilename, String outputFileName) throws IOException {
      BmpImage bmpImageOriginal = BmpReader.read_bmp(new FileInputStream(inFilename));
      BmpImage bmpImageFiltered = BmpReader.read_bmp(new FileInputStream(inFilename));
      OutputStream out = new FileOutputStream(outputFileName);

      int height = bmpImageOriginal.image.getHeight();
      int width = bmpImageOriginal.image.getWidth();

      // Iterate over every pixel in picture
      for (int y = 0; y < height; y++) {
         for (int x = 0; x < width; x++) {
            // Kernel[x][y]
            int[][] pixelkernel = buildPixelkernel(bmpImageOriginal, y, x);
            int[][] filterkernel = {{1, 0, -1},{2, 0 ,-2},{1, 0, -1}};

            pixelkernel = matrizenmultiplikation(pixelkernel, filterkernel);
            int sum = sumOfAllMatrixValues(pixelkernel);

            if(sum < 0) sum = 0;
            else if (sum > 255) sum = 255;

            PixelColor color = new PixelColor(sum, sum, sum);
            bmpImageFiltered.image.setRgbPixel(x, y, color);
         }
      }

      try {
         BmpWriter.write_bmp(out, bmpImageFiltered);
      } finally {
         out.close();
      }
   }
Bilder
Horizontal Vertikal
Details_Atom-sobelfilter-horizontal Details_Atom-sobelfilter-vertical
Flaechen_Atom-sobelfilter-horizontal Flaechen_Atom-sobelfilter-vertical