From 53b947df484159f5934898ba6c0aa69a9c869007 Mon Sep 17 00:00:00 2001 From: Ido Hadanny Date: Thu, 22 Sep 2011 21:30:13 +0300 Subject: added stuff --- .../hackingroomba/roombacomm/FrameProcessor.java | 586 +++++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100644 roombacomm-client/src/com/hackingroomba/roombacomm/FrameProcessor.java (limited to 'roombacomm-client/src/com/hackingroomba/roombacomm/FrameProcessor.java') diff --git a/roombacomm-client/src/com/hackingroomba/roombacomm/FrameProcessor.java b/roombacomm-client/src/com/hackingroomba/roombacomm/FrameProcessor.java new file mode 100644 index 0000000..85d7b60 --- /dev/null +++ b/roombacomm-client/src/com/hackingroomba/roombacomm/FrameProcessor.java @@ -0,0 +1,586 @@ +package com.hackingroomba.roombacomm; +import java.io.*; +import java.net.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import javax.swing.*; +import java.lang.Thread; +import java.util.*; +import java.lang.Math; + + +public class FrameProcessor { + private static final long serialVersionUID = 1L; + private static final int lumBufHeight = 32; + // socket variables + int portNum = 5005; + Socket videoSocket; + BufferedInputStream in; + BufferedOutputStream out; + RoboRealmAPI rr; + + // video variables + byte[] readBuf; // where we read raw network data into + byte[] vidBuf; // raw pixel bytes + int[] vidDispBuf, sliceBufInt; + int[] lumBuf = new int[256*lumBufHeight]; + int[] qDisplayBuf, q; // the quantized array, qDisplayBuf is video data, q is 0 or 1 in each int + int[] ltBuf; // the graphic markers for current middle & bundaries of tracking + String server = ""; + int frameSize; + int imgWidth; + int imgHeight; + Container contentPane; + Image img, lumImg, quantizedImg, sliceImg, trackingImg; + JFrame frame; + Insets insets; + int qStartRow, qEndRow; + int thresholdOverride = 0; + int frameCount = 0; + + // line variables. Units are pixels distance from center of image. Negative value is left of center + class LineBoundary { + int start; + int middle; + int end; + }; + ArrayList lineList; + LineBoundary currentLine; + int first; + int[] smoothSlice; // a quantized slice across the image, averaged to remove noise + int minLineThickness, maxLineThickness; + + public FrameProcessor(String server,int portnum, int width, int height, int minLine, int maxline, int thresholdOv) + { + imgWidth = width; + imgHeight = height; + minLineThickness = minLine; + maxLineThickness = maxline; + lineList = new ArrayList(); + currentLine = new LineBoundary(); + first = 1; + smoothSlice = new int[width]; + ltBuf = new int[4*imgWidth]; + thresholdOverride = thresholdOv; + this.server = server; + this.portNum = portnum; + } + + public void makeImagePane() + { + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + } + + void createAndShowGUI() { + //Create and set up the window. + frame = new JFrame("Raw Image"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + contentPane = frame.getContentPane(); + contentPane.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 20)); + + //Display the window. + frame.pack(); + frame.setVisible(true); + insets = frame.getInsets(); + frame.setMinimumSize(new Dimension(400,350)); + + } + + public void displayFrame() + { + Graphics g = frame.getGraphics(); + + // display the raw image + img = frame.createImage(new MemoryImageSource(imgWidth,imgHeight,vidDispBuf, 0, imgWidth)); + g.drawImage(img, insets.left+2, insets.top+2, null); + + // display the slice + sliceImg = frame.createImage(new MemoryImageSource(imgWidth, qEndRow-qStartRow, sliceBufInt, 0, imgWidth)); + g.drawImage(sliceImg, insets.left, insets.top + 20 + imgHeight, null); + + // display the quantized image + quantizedImg = frame.createImage(new MemoryImageSource(imgWidth, qEndRow-qStartRow, qDisplayBuf, 0, imgWidth)); + g.drawImage(quantizedImg, insets.left, insets.top + 40 + imgHeight, null); + + // display the line tracking markers + trackingImg = frame.createImage(new MemoryImageSource(imgWidth, 4, ltBuf, 0, imgWidth)); + g.drawImage(trackingImg, insets.left, insets.top + 60 + imgHeight, null); + + //lumImg = frame.createImage(new MemoryImageSource(256,lumBufHeight,lumBuf, 0, 256)); + //g.drawImage(lumImg, insets.left, insets.top + 20 + imgHeight, null); + } + + public Boolean frame2Roborealm() + { + return rr.setImage(vidBuf, imgWidth, imgHeight); + } + + public String getShapeData() + { + String rrString = rr.getVariable("SHAPES"); + //System.out.println(rrString); + return rrString; + } + + public void connect(boolean connectRoborealm) + { + try { + videoSocket = new Socket(server, portNum); + in = new BufferedInputStream(videoSocket.getInputStream()); + out = new BufferedOutputStream(videoSocket.getOutputStream()); + } catch (UnknownHostException e) { + System.out.println("Unknown host: " + server + ":" + portNum); + System.exit(-1); + } catch(IOException e) { + System.out.println("I/O exception"); + e.printStackTrace(); + System.exit(-1); + } + System.out.println("connected to video"); + + // connect to RoboRealm if requested + if (connectRoborealm) { + rr = new RoboRealmAPI(); + if (!rr.connect("localhost")) + { + System.out.println("Could not connect to RoboRealm on localhost! Exiting..."); + System.exit(-1); + } + } + } + + public void disconnect() + { + try { + // do io streams need to be closed first? + if (in != null) in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + in = null; + + try { + if (videoSocket != null) videoSocket.close(); + } catch (Exception e) { + e.printStackTrace(); + } + videoSocket = null; + System.out.println("disconnected from Video"); + } + + /** + * Read a video frame from the network device + * @param width in pixels + * @param height in pixels + * @param captureType 0 = monochrome, 1 = rgb color + * @return number of pixels read or negative for error during read (e.g. size doesn't match frame size) + */ + + public int readFrame(int width, int height, int captureType) + { + int bytesPerPixel = 1; + int readLength = 0; + int rxImageSize; + int rgbShiftSize = 16; + int pixel = 255 << 24; + + if (captureType == 1) // if rgb color, 3 bytes/pixel, otherwise 1 for grayscale + bytesPerPixel = 3; + frameSize = width * height * bytesPerPixel; + + int maxReadSize = frameSize; + readBuf = new byte[frameSize]; // analysis form - temp buffer for raw received data + vidBuf = new byte[frameSize]; // raw image bytes + vidDispBuf = new int[frameSize]; // display version (alpha set, bytes replicated if needed) + int vidDispBufIx = 0; + int vidBufIx = 0; + + readBuf[0] = (byte)(200 + captureType); // send the "capture" command + byte[] t = new byte[4]; + + try { + out.write(readBuf, 0, 1); + out.flush(); + + readLength = in.read(t, 0, 4); // read imgWidth + if (readLength != 4) + return -4; + //System.out.println(t[0] + " " + t[1] + " " + t[2] + " " + t[3]); + imgWidth = ((t[2] << 8) & 0xff00) | t[3] & 0xff; // I think this way of getting byte to int is broken + if (imgWidth != width) + return -1; + + readLength = in.read(t, 0, 4); // read imgHeight + //System.out.println(t[0] + " " + t[1] + " " + t[2] + " " + t[3]); + if (readLength != 4) + return -5; + imgHeight = (int)(t[2] & 0xff) << 8 | t[3] & 0xff; + //System.out.println(t[0] + " " + t[1] + " " + t[2] + " " + t[3]); + if (imgHeight != height) + return -2; + + readLength = in.read(t, 0, 4); // read imgLength + if (readLength != 4) + return -6; + rxImageSize = ((t[1] << 16) & 0xff0000) | ((t[2] << 8) & 0xff00) | (int)t[3] & 0xff; + //System.out.println(t[0] + " " + t[1] + " " + t[2] + " " + t[3]); + if (rxImageSize != frameSize) + return -3; + + //System.out.println("Chumby reports image size " + imgWidth + "x" + imgHeight + " length " + rxImageSize + " for frameSize " + frameSize); + + + // ACHTUNG - readBuf gets overwritten at the beginning by multiple read buffers - use vidDispBuf or vidBuf for image + + for (int i=0; i<50; i++) { + readLength = in.read(readBuf, 0, maxReadSize); + maxReadSize -= readLength; + for (int j=0; j minLineThickness & create a LineBoundary for each + blackStart = blackEnd = 0; + for (int i=0; i minLineThickness) && ((blackEnd - blackStart) < maxLineThickness)) { + LineBoundary lb = new LineBoundary(); + lb.start = blackStart - (imgWidth/2); + lb.end = blackEnd - (imgWidth/2); + lb.middle = ((lb.start + lb.end)/2); + lineList.add(lb); + } // else ignore this as a false line (noise) - we're in white now + } + } else { // inWhite + if (smoothSlice[i] == 0) { + inBlack = true; // were in white, just transitioned to black (can happen on element 0) + blackStart = i; + } + } + } + + // print found lines +// System.out.print("Found " + lineList.size() + " lines: "); +// for (LineBoundary l : lineList) { +// System.out.print(l.start + " " + l.middle + " " + l.end + " "); +// } +// System.out.println(); + + return(0); + } + + /* + * Find the line we should be following. The very first time this runs, or if it loses the line & backs up + * it will pick the line closest to center. Thereafter it chooses the first found line who's center is within + * the boundaries of the last line it chose. If it can't find one, it returns an error. Therefore it will always take + * a left fork. It returns the middle value of the chosen line, or a large value if error. + */ + public int trackLine() + { + int m; + LineBoundary lTmp = new LineBoundary(); + // clear out current markers in the tracking display + m = currentLine.middle + imgWidth/2; + ltBuf[m + 3*imgWidth] = ltBuf[m + 2*imgWidth] = ltBuf[m + imgWidth] = ltBuf[m] = 0; + + if (lineList.size() == 0) { + if (currentLine.middle >= 0) { + System.out.println("Error: line disappeared to right, last seen at " + currentLine.middle); + return(100); + } else { + System.out.println("Error: line disappeared to left, last seen at " + currentLine.middle); + return (-100); + } + } + if (first == 1) { + lTmp.middle = 100; // any found line will be closer than this + for (LineBoundary lb : lineList) { + if (Math.abs(lb.middle) < Math.abs(lTmp.middle)) { + lTmp = lb; // save the new lineBoundary with the lowest absolute value of middle + } + } + currentLine = lTmp; + first = 0; + System.out.print("Picked line center at " + lTmp.middle); + return(lTmp.middle); + } else { + if (lineList.size() == 1) { + System.out.println("tracking line center at " + lineList.get(0).middle + " width: " + (lineList.get(0).end-lineList.get(0).start)); + currentLine = lineList.get(0); + return (lineList.get(0).middle); + } + for (LineBoundary lb : lineList) { + if ((lb.middle > currentLine.start-20) && (lb.middle < currentLine.end + 20)) { + System.out.println("tracking line center at " + lb.middle + " width: " + (lb.end-lb.start)); + currentLine = lb; + // write the image of the new currentLine middle + m = lb.middle+(imgWidth/2); + ltBuf[m] = 0xff<<24 | 0xff<<16; + ltBuf[m + 3*imgWidth] = ltBuf[m + 2*imgWidth] = ltBuf[m + imgWidth] = ltBuf[m]; + return (lb.middle); + } + } + } + System.out.println("Error: Lost the line I was tracking"); + first = 1; + return(2001); + } + public void testQuantization() + { + byte[] testArray1 = + {6, 6, 6, 10, + 6, 6, 6, 10, + 17, 17, 17, 17, + 17, 17, 17, 88}; + for (int i=0; i