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);
}
}
}
}