{"id":136,"date":"2007-11-25T12:13:45","date_gmt":"2007-11-25T11:13:45","guid":{"rendered":"http:\/\/blog.sahits.ch\/?p=136"},"modified":"2008-12-17T16:43:13","modified_gmt":"2008-12-17T15:43:13","slug":"bildverarbeitung-in-java","status":"publish","type":"post","link":"http:\/\/sahits.ch\/blog\/blog\/2007\/11\/25\/bildverarbeitung-in-java\/","title":{"rendered":"Bildverarbeitung in Java"},"content":{"rendered":"<p>Java ist keine Programmiersprache in der sich Bilder einfach manipulieren lassen. Dass es trotzdem geht und was n\u00f6tig ist, soll dieser Artikel aufzeigen.<!--more--><br \/>\nZuerst muss man sich auch hier zuerst dar\u00fcber Klar werden, was man will. Ich habe gefunden, dass es drei Ans\u00e4tze gibt von denen ich zwei auf meine Problematik anwenden kann. Ausgangslage ist hierbei immer ein Bild mit einer fixen Dimension, das durch zus\u00e4tzliche graphische Elemente aufgepeppt werden soll:<\/p>\n<ol>\n<li>Die zus\u00e4tzlichen graphischen Elemente sind einfache Formen (Linien, Ellipsen, Rechtecke, Texte, &#8230;)<\/li>\n<li>Das resultierende Bild wird mit einem anderen Bild gleicher Dimension erg\u00e4nzt.<\/li>\n<li>Das resultierende Bild wird mit Elementen aus einem anderen Bild erg\u00e4nzt<\/li>\n<\/ol>\n<p>Nun kommt die berechtigte Frage auf, was denn der Unterschied zwischen den beiden letzten Praktiken ist. Bei der ersten wird ein Bild mit einem anderen durch eine <a href=\"http:\/\/java.sun.com\/j2se\/1.4.2\/docs\/api\/java\/awt\/AlphaComposite.html\" target=\"_blanck\">affine Transformation<\/a> \u00fcberlagert. Dies eignet sich jedoch nur wenn entweder alles von Bild A in B angezeigt werden soll, umgekehrt oder das eine Bild Transparent sein soll. Mit dieser M\u00f6glichkeit ist es nicht m\u00f6glich beispielsweise ein in Bild B definiertes Polygon in A darzustellen, so dass die Fl\u00e4che von A, die in Bild B nicht vom Polygon \u00fcberdeckt ist, dargestellt wird. Man spricht hierbei von Blending image welches in dem <a href=\"http:\/\/javajeff.mb.ca\/articles\/bi\/article.html\" target=\"_blanck\">gleichnamigen Artikel<\/a> gut beschrieben wird. Diese Technik kann beispielsweise f\u00fcr Diashows oder f\u00fcr ein <a href=\"http:\/\/forum.java.sun.com\/thread.jspa?threadID=620850&#038;messageID=3499086\" target=\"_blanck\">Wasserzeichen<\/a> verwendet werden.<br \/>\nDas erste Verfahren eignet sich besonders, wenn einfache Strukturen das Bild erg\u00e4nzen:<br \/>\n<code><br \/>\n\t\tFile f = new File(image2enhance);<br \/>\n\t\timage =ImageIO.read(f);<br \/>\n\t\tGraphics graphics = image.getGraphics();<br \/>\n\t\tgraphics.setColor(Color.black);<br \/>\n\t\tPoint start = new Point(0,25);<br \/>\n\t\tPoint end = new Point(25,50);<br \/>\n\t\tgraphics.drawLine(start.x, start.y, end.x, end.y);<br \/>\n\t\tString fileName = \"someSillyFileName.png\";<br \/>\n\t\tImageIO.write(image, \"PNG\", new File(fileName));<br \/>\n<\/code><br \/>\nIm Artikel <a href=\"http:\/\/schmidt.devlib.org\/java\/highlight.html\" target=\"_blanck\">Highlight<\/a> ist dieser Mechanismus beschrieben.<br \/>\nErst die dritte Methode l\u00e4sst mehr Flexibilit\u00e4t zu. Der Einfachheit halber besitzt das Bild B, das den Artefakt enth\u00e4lt, der in Bild A hinzugef\u00fcgt werden soll, dieselbe Dimensionen wie Bild A. Der Artefakt kann dann in Bild B entsprechend Positioniert werden. Als Hintergrundfarbe wird eine eindeutige Farbe gew\u00e4hlt, die im Artefakt nicht verwendet wird. Nun wird f\u00fcr jedes Pixel in Bild B \u00fcberpr\u00fcft, ob es sich um die Hintergrundfarbe handelt oder der Pixel zum Artefakt geh\u00f6rt. In letzterem Fall wird der Pixel in Bild A eingetragen. Auf diese Weise k\u00f6nnen auch komplexere Bedingungen erf\u00fcllt werden, z.B. Zeichne den Pixel nur wenn der entsprechende Pixel in Bild A eine bestimmte Farbe (nicht) hat.<br \/>\n<code><br \/>\nprivate BufferedImage image=null;<br \/>\npublic void createEnhancedImage(){<br \/>\n\ttry {<br \/>\n\t\ttry {<br \/>\n\t\t\timage =ImageIO.read(new File(\"backgroundFile.png\"));<br \/>\n\t\t} catch (IOException e) {<br \/>\n\t\t\te.printStackTrace();<br \/>\n\t\t}<br \/>\n\t\tBufferedImage bi = ImageIO.read(new File(\"baseFile.png\"));<br \/>\n\t\thandlepixels(bi, 0, 0, 50, 50);<br \/>\n\t\tImageIO.write(image, \"PNG\", new File(\"newFileName.png\"));<br \/>\n\t} catch (IOException e) {<br \/>\n\t\te.printStackTrace();<br \/>\n\t}<br \/>\n}<br \/>\n private void handlepixels(Image img, int x, int y, int w, int h) {<br \/>\n        int[] pixels = new int[w * h];<br \/>\n        PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);<br \/>\n        try {<br \/>\n            pg.grabPixels();<br \/>\n        } catch (InterruptedException e) {<br \/>\n            System.err.println(\"interrupted waiting for pixels!\");<br \/>\n            return;<br \/>\n        }<br \/>\n        if ((pg.getStatus() & ImageObserver.ABORT) != 0) {<br \/>\n            System.err.println(\"image fetch aborted or errored\");<br \/>\n            return;<br \/>\n        }<br \/>\n        for (int j = 0; j < h; j++) {\n            for (int i = 0; i < w; i++) {\n                handlesinglepixel(x+i, y+j, pixels[j * w + i]);\n            }\n        }\n  }\nprivate void handlesinglepixel(int x, int y, int pixel) {\n\/\/        int alpha = (pixel >> 24) & 0xff;<br \/>\n        int red   = (pixel >> 16) & 0xff;<br \/>\n        int green = (pixel >>  8) & 0xff;<br \/>\n        int blue  = (pixel      ) & 0xff;<br \/>\n        Color col = new Color(red,green,blue);<br \/>\n\tif (col.getBlue()==0 && col.getGreen()==0 && col.getRead()==0){<br \/>\n\t} else {<br \/>\n\t\t\/\/ color is not black<br \/>\n\t\t\/\/ replace the pixel (x,y) in background with a pixel of color col<br \/>\n\t\tdrawPixel(x, y, col);<br \/>\n\t}<br \/>\n}<br \/>\n private void drawPixel(int x, int y, Color col){<br \/>\n\t Graphics graphics = image.getGraphics();<br \/>\n\t graphics.setColor(col);<br \/>\n\t graphics.drawLine(x, y, x, y);<br \/>\n }<\/p>\n<p><\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Java ist keine Programmiersprache in der sich Bilder einfach manipulieren lassen. Dass es trotzdem geht und was n\u00f6tig ist, soll dieser Artikel aufzeigen.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,6],"tags":[65,66,64,99,67,63,301,25],"class_list":["post-136","post","type-post","status-publish","format-standard","hentry","category-java","category-programmieren","tag-add","tag-bearbeiten","tag-bild","tag-de","tag-hinzufuegen","tag-image","tag-java","tag-tutorial"],"_links":{"self":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts\/136","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/comments?post=136"}],"version-history":[{"count":3,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts\/136\/revisions"}],"predecessor-version":[{"id":307,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/posts\/136\/revisions\/307"}],"wp:attachment":[{"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/media?parent=136"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/categories?post=136"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/sahits.ch\/blog\/wp-json\/wp\/v2\/tags?post=136"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}