Subversion Repositories svnkaklik

Rev

Blame | Last modification | View Log | Download

/*
    AVRcamVIEW: A PC application to test out the functionallity of the
     AVRcam real-time image processing engine.
    Copyright (C) 2004    Brent A. Taylor

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public
    License along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

   For more information on the AVRcamVIEW, please contact:

   taylorba@comcast.net

   or go to www.jrobot.net for more details regarding the system.
*/

package avr.swing;

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import javax.swing.*;

import avr.lang.*;

public class JCapturePanel extends JPanel {

   // constant variables for the interpolate state machine
   private static final int RED        = 0x01;
   private static final int BLUE       = 0x02;
   private static final int GREEN_EVEN = 0x04;
   private static final int GREEN_ODD  = 0x08;

   private BufferedImage bayerImage;
   private BufferedImage image;

   public JCapturePanel() {
      super(null);

      bayerImage = new BufferedImage(AVRSystem.IMAGE_WIDTH, AVRSystem.IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
      image = new BufferedImage(AVRSystem.IMAGE_WIDTH, AVRSystem.IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);

   }

   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      if(bayerImage != null) {

         Dimension size = getSize();
         Insets insets = getInsets();

         Image offscreenImage = this.createImage(size.width, size.height);

         Graphics2D g2d = (Graphics2D)offscreenImage.getGraphics();

         // scale the images so they fit side by side for either the full
         // width or full height of the window
         double xScale = size.width / (double)(insets.left + 5 + AVRSystem.IMAGE_WIDTH + 10 + AVRSystem.IMAGE_WIDTH + 5 + insets.right);
         double yScale = size.height / (double)(insets.top + 5 + AVRSystem.IMAGE_HEIGHT + 5 + insets.bottom);
         double scale = Math.min(xScale, yScale);

         g2d.scale(scale, scale);

         g2d.drawImage(bayerImage, insets.left + 5, insets.top + 5, null);
         g2d.drawImage(image, insets.left + 5 + AVRSystem.IMAGE_WIDTH + 10, insets.top + 5, null);

         g.drawImage(offscreenImage, 0, 0, null);

      }
   }

   public Dimension getMinimumSize() {
      return getPreferredSize();
   }

   public Dimension getPreferredSize() {
      Insets insets = getInsets();
      return new Dimension(insets.left + 5 + AVRSystem.IMAGE_WIDTH + 10 + AVRSystem.IMAGE_WIDTH + 5 + insets.right,
                           insets.top + 5 + AVRSystem.IMAGE_HEIGHT + 5 + insets.bottom);
   }

   public Dimension getMaximumSize() {
      return getPreferredSize();
   }

   public int getRGB(int x, int y) {
      return image.getRGB(x, y);
   }

   public void openBayer(File file) throws IOException {

      FileInputStream inStream = new FileInputStream(file);
      FileChannel inChannel = inStream.getChannel();

      ByteBuffer[] buffers = new ByteBuffer[bayerImage.getWidth()];

      for(int x = 0; x < buffers.length; x++) {
         buffers[x] = ByteBuffer.allocate(bayerImage.getHeight() * 4);
      }

      inChannel.read(buffers);

      inStream.close();
      inChannel.close();

      int[] pixels = new int[bayerImage.getHeight()];

      for(int x = 0; x < bayerImage.getWidth(); x++) {
         buffers[x].flip();
         buffers[x].asIntBuffer().get(pixels);
         bayerImage.setRGB(x, 0, 1, pixels.length, pixels, 0, 1);
      }

      interpolate();

   }

   public void saveBayer(File file) throws IOException {

      ByteBuffer[] buffers = new ByteBuffer[bayerImage.getWidth()];

      for(int x = 0; x < buffers.length; x++) {
         buffers[x] = ByteBuffer.allocate(bayerImage.getHeight() * 4);
         for(int y = 0; y < bayerImage.getHeight(); y++) {
            buffers[x].putInt(bayerImage.getRGB(x, y));
         }
         buffers[x].flip();
      }

      FileOutputStream outStream = new FileOutputStream(file);
      FileChannel outChannel = outStream.getChannel();

      outChannel.write(buffers);

      outStream.close();
      outChannel.close();

   }

   public void setRow(int row, ByteBuffer data, boolean finished) {

      int[] pixels = new int[AVRSystem.IMAGE_WIDTH * 2];

      int x = 0;

      while(data.hasRemaining()) {

         byte pixel = data.get();

         if((x & 1) == 0) {

            // green
            pixels[x] = (pixel & 0xF0) << 8;

            // blue
            pixels[AVRSystem.IMAGE_WIDTH + x] = (pixel & 0x0F) << 4;

         } else {

            // green
            pixels[AVRSystem.IMAGE_WIDTH + x] = ((pixel & 0x0F) << 4) << 8;

            // red
            pixels[x] = (pixel & 0xF0) << 16;

         }

         x++;

      }

      bayerImage.setRGB(0, row * 2, AVRSystem.IMAGE_WIDTH, 2, pixels, 0, AVRSystem.IMAGE_WIDTH);

      if(finished) {
         interpolate();
      }

      repaint();

   }

   /* ********************************************************
    * The bayerImage is in the bayer format shown below.
    *
    *      |   |   |   |   |   |   |   |   |   | . | 1 | 1 |
    *      |   |   |   |   |   |   |   |   |   | . | 7 | 7 |
    *      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | . | 4 | 5 |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *    0 | G | R | G | R | G | R | G | R | G | . | G | R |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *    1 | B | G | B | G | B | G | B | G | B | . | B | G |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *    2 | G | R | G | R | G | R | G | R | G | . | G | R |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *    3 | B | G | B | G | B | G | B | G | B | . | B | G |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *    4 | G | R | G | R | G | R | G | R | G | . | G | R |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *    5 | B | G | B | G | B | G | B | G | B | . | B | G |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *    .   .   .   .   .   .   .   .   .   .   .   .   .
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *  142 | G | R | G | R | G | R | G | R | G | . | G | R |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *  143 | B | G | B | G | B | G | B | G | B | . | B | G |
    * -----+---+---+---+---+---+---+---+---+---+ . +---+---+
    *
    * The corners are calculated, then the edges, then the center.
    *
    */

   private void interpolate() {

      int red = 0;
      int green = 0;
      int blue = 0;

      int currColor = GREEN_ODD;
      int nextColor = RED;

      int width = AVRSystem.IMAGE_WIDTH;
      int height = AVRSystem.IMAGE_HEIGHT;

      // *** do the corners of the image ***
      // upper left corner
      red   = bayerImage.getRGB(1, 0);
      green = bayerImage.getRGB(0, 0);
      blue  = bayerImage.getRGB(0, 1);
      image.setRGB(0, 0, red | green | blue);

      // upper right corner
      red   = bayerImage.getRGB(width - 1, 0);
      green = (bayerImage.getRGB(width - 2, 0) + bayerImage.getRGB(width - 1, 1)) / 2;
      blue  = bayerImage.getRGB(width - 2, 1);
      image.setRGB(width - 1, 0, red | green | blue);

      // lower left corner
      red   = bayerImage.getRGB(1, height - 2);
      green = (bayerImage.getRGB(0, height - 2) + bayerImage.getRGB(1, height - 1)) / 2;
      blue  = bayerImage.getRGB(0, height - 1);
      image.setRGB(0, height - 1, red | green | blue);

      // lower right corner
      red   = bayerImage.getRGB(width - 1, height - 2);
      green = bayerImage.getRGB(width - 1, height - 1);
      blue  = bayerImage.getRGB(width - 2, height - 1);
      image.setRGB(width - 1, height - 1, red | green | blue);

      // *** do the north edge
      currColor = RED;
      for(int x = 1, y = 0; x < width - 1; x++) {
         switch(currColor) {
            case RED:
               red   = bayerImage.getRGB(x, y);
               green = (bayerImage.getRGB(x + 1, y) + bayerImage.getRGB(x, y + 1) + bayerImage.getRGB(x - 1, y)) / 3;
               blue  = (bayerImage.getRGB(x + 1, y + 1) + bayerImage.getRGB(x - 1, y + 1)) / 2;
               nextColor = GREEN_EVEN;
               break;
            case GREEN_EVEN:
               red   = (bayerImage.getRGB(x - 1, y) + bayerImage.getRGB(x + 1, y)) / 2;
               green = bayerImage.getRGB(x, y);
               blue  = bayerImage.getRGB(x, y + 1);
               nextColor = RED;
               break;
            default:
               AVRSystem.LOG.warning("Invalid color for row start: " + currColor);
         }
         currColor = nextColor;
         image.setRGB(x, y, red | green | blue);
      }

      // *** do the west edge
      currColor = BLUE;
      for(int y = 1, x = 0; y < height - 1; y++) {
         switch(currColor) {
            case BLUE:
               red   = (bayerImage.getRGB(x + 1, y + 1) + bayerImage.getRGB(x + 1, y - 1)) / 2;
               green = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x + 1, y) + bayerImage.getRGB(x, y + 1)) / 3;
               blue  = bayerImage.getRGB(x, y);
               nextColor = GREEN_EVEN;
               break;
            case GREEN_EVEN:
               red   = bayerImage.getRGB(x + 1, y);
               green = bayerImage.getRGB(x, y);
               blue  = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x, y + 1)) / 2;
               nextColor = BLUE;
               break;
         }
         currColor = nextColor;
         image.setRGB(x, y, red | green | blue);
      }

      // *** do the east edge
      currColor = GREEN_ODD;
      for(int y = 1, x = width - 1; y < height - 1; y++) {
         switch(currColor) {
            case RED:
               blue  = (bayerImage.getRGB(x - 1, y + 1) + bayerImage.getRGB(x - 1, y - 1)) / 2;
               green = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x - 1, y) + bayerImage.getRGB(x, y + 1)) / 3;
               red   = bayerImage.getRGB(x, y);
               nextColor = GREEN_EVEN;
               break;
            case GREEN_ODD:
               blue  = bayerImage.getRGB(x - 1, y);
               green = bayerImage.getRGB(x, y);
               red   = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x, y + 1)) / 2;
               nextColor = BLUE;
               break;
         }
         currColor = nextColor;
         image.setRGB(x, y, red | green | blue);
      }

      // *** do the south edge
      currColor = GREEN_ODD;
      for(int x = 1, y = height - 1; x < width - 1; x++) {
         switch(currColor) {
            case GREEN_ODD:
               red   = bayerImage.getRGB(x, y - 1);
               green = bayerImage.getRGB(x, y);
               blue  = (bayerImage.getRGB(x - 1, y) + bayerImage.getRGB(x + 1, y)) / 2;
               nextColor = BLUE;
               break;
            case BLUE:
               red   = (bayerImage.getRGB(x - 1, y - 1) + bayerImage.getRGB(x + 1, y - 1)) / 2;
               green = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x + 1, y) + bayerImage.getRGB(x - 1, y)) / 3;
               blue  = bayerImage.getRGB(x, y);
               nextColor = GREEN_ODD;
               break;
            default:
               AVRSystem.LOG.warning("Invalid color for row start: " + currColor);
         }
         currColor = nextColor;
         image.setRGB(x, y, red | green | blue);
      }

      // *** do the center box ***
      currColor = RED;
      for(int y = 1; y < height - 1; y++) {
         // change the starting color for the row
         switch(currColor) {
            case RED:
               currColor = GREEN_ODD;
               break;
            case GREEN_ODD:
               currColor = RED;
               break;
            default:
               AVRSystem.LOG.warning("Invalid color for row start: " + currColor);

         }
         for(int x = 1; x < width - 1; x++) {

            switch(currColor) {
               case RED:
                  red   = bayerImage.getRGB(x, y);

                  green = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x + 1, y) +
                           bayerImage.getRGB(x, y + 1) + bayerImage.getRGB(x - 1, y)) / 4;

                  blue  = (bayerImage.getRGB(x - 1, y - 1) + bayerImage.getRGB(x + 1, y + 1) +
                           bayerImage.getRGB(x + 1, y - 1) + bayerImage.getRGB(x - 1, y + 1)) / 4;
                  nextColor = GREEN_EVEN;
                  break;
               case GREEN_EVEN:
                  red   = (bayerImage.getRGB(x - 1, y) + bayerImage.getRGB(x + 1, y)) / 2;
                  green = bayerImage.getRGB(x, y);
                  blue  = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x, y + 1)) / 2;
                  nextColor = RED;
                  break;
               case GREEN_ODD:
                  red   = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x, y + 1)) / 2;
                  green = bayerImage.getRGB(x, y);
                  blue  = (bayerImage.getRGB(x - 1, y) + bayerImage.getRGB(x + 1, y)) / 2;
                  nextColor = BLUE;
                  break;
               case BLUE:
                  red   = (bayerImage.getRGB(x - 1, y - 1) + bayerImage.getRGB(x + 1, y + 1) +
                           bayerImage.getRGB(x + 1, y - 1) + bayerImage.getRGB(x - 1, y + 1)) / 4;

                  green = (bayerImage.getRGB(x, y - 1) + bayerImage.getRGB(x + 1, y) +
                           bayerImage.getRGB(x, y + 1) + bayerImage.getRGB(x - 1, y)) / 4;

                  blue  = bayerImage.getRGB(x, y);
                  nextColor = GREEN_ODD;
                  break;
               default:
                  AVRSystem.LOG.warning("Invalid color: " + currColor);
            }

            currColor = nextColor;

            image.setRGB(x, y, red | green | blue);
         }
      }

   }

}