import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Date; import javax.swing.JFrame; import sun.net.TelnetInputStream; import sun.net.TelnetOutputStream; import sun.net.ftp.FtpClient; import vxp.PixelSource; import vxp.QTLivePixelSource; import vxp.VideoListener; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGEncodeParam; import com.sun.image.codec.jpeg.JPEGImageEncoder; /** * @author DanO *This is a sample class that students can extend to create interesting web cams *1/28/06 Tried to fix the array out of bounds error on the mac with a fix in the constructor */ public class WebCam extends JFrame implements WindowListener, VideoListener, KeyListener, MouseListener { /**This is reference to a PixelSource object from vxp.jar*/ PixelSource ps; /**This is handy for testing performance*/ long elapsedTime; /**Width and Height are set in one place. * Using 320,240 instead of 640,480 will make all your programming and transers faster * When you want to get fancy bump it up */ int kWidth = 320; int kHeight = 240; /**BufferedImage is now the the basic image format within java. Learn it, love it*/ BufferedImage liveImage = new BufferedImage(kWidth,kHeight,BufferedImage.TYPE_INT_ARGB); BufferedImage freezeFrame = new BufferedImage(kWidth,kHeight,BufferedImage.TYPE_INT_ARGB); /** For frame differencing we will need an array to store the pixels from some previous frame. * This may be a frame from the very start of the program when the cameras view was clear (background removal) * or it may be from the previous froma (movement detection). */ int[] backgroundReference = new int[kWidth * kHeight]; /** This is the constructor */ WebCam() { initVideo(); // This may fix that mac "arrray out of bounds error freezeFrame = new BufferedImage(ps.vidWidth,kHeight,BufferedImage.TYPE_INT_ARGB); //set the window stuff setSize(kWidth*2, kHeight); setTitle("WebCam"); setVisible(true); //arrange to get callbacks for events from these Listeners. //I had to previously promise to implement and then implement the methods that these listeners call addWindowListener(this); addMouseListener(this); addKeyListener(this); } /** This cranks up the video by creating a pixelSource object. * It also subscribes to the video listener, of course I would have to have previously promised to implement a VideoListener and then implement "newFrame" * You might consider overriding this if you want a different kind of video object * or don't want to subscribe to the notification service. */ public void initVideo(){ ps = new QTLivePixelSource(kWidth, kHeight, 300); ps.addVideoListener(this); } /** The is the entry point for your program * You will definitely want to override this and then get out of it as * soon as possible */ public static void main(String[] Args) { JFrame myWorld = new WebCam(); } /** You always need to clean up */ public void cleanUp() { ps.killSession(); System.out.println("Killed Video Source"); } /** This is the method that pixel source uses to tell you that a * new frame is ready. You have to have this if you want to implement a VideoListener */ public void newFrame() { long startTime = System.currentTimeMillis(); ps.grabFrame(); liveImage = ps.getImage(); repaint(); elapsedTime = System.currentTimeMillis() - startTime; } /** This overrides the update method of JFrame which gets called on repaint. The * reason I don't like JFrames is because it clears the screen (which I don't need) * and creates flicker doing it. I redo the method with a paint but no clear */ public void update(Graphics g){ paint(g); } /**This gets called everytime you repaint the screen. You would * want to override this if you want anything but side by side pictures */ public void paint(Graphics g) { g.drawImage(liveImage ,0,0,null); g.drawImage(freezeFrame, kWidth, 0, null); } /**This is a convenience because hate typing "System.out.println" * In this way you can rewrite java to your tastes. */ public void put(String s) { System.out.println(s); } /**This is a method that you promised to have as a WindowListener. */ public void windowClosing(WindowEvent e) { cleanUp(); //this stuff kills the window System.out.println("Kill Application"); setVisible(false); dispose(); System.exit(0); } /**Grabs a frame and then puts it into a bufferedImage. */ public void grabPicture(BufferedImage _ff){ ps.grabFrame(); ps.getImage(_ff); } /**This stores the current frame for future reference. */ public void grabReference() { // you have clone which makes a full copy of the old frame //otherwise you would just make a reference to the array that keeps changing with each new frame backgroundReference = (int[]) ps.getPixelArray().clone(); } /**This is a method that you promised to have as a KeyListener. * For homework you might try to replace the last part with different input than a keystroke */ public void keyReleased(KeyEvent e) { if (e.getKeyChar() == 's') { ps.videoSettings(); } else if (e.getKeyChar() == 't') { put("Timer" + elapsedTime); } else { put("Grabit "); //maybe you could have sound or change or something do this instead of key stroke //grab picture //put it to a file //put the file on the server grabPicture(freezeFrame); makeJPegFile(freezeFrame, "C:\\", "tempoloni.jpg", 0.5f); postFileToITP("C:\\", "tempoloni.jpg", "/home/dbo3/public_html/VideoSensing/test/", "WC" + getTimeString() + ".jpg" ); } } /**Turn a bufferedImage into a jpeg. */ public void makeJPegFile(BufferedImage bi, String pathname, String filename, float quality) { try { // convert it to an image without an alpha channel for the Jpeg BufferedImage biOut = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics biOutG = biOut.getGraphics(); biOutG.drawImage(bi, 0, 0, null); File outputFile = new File(pathname + filename); FileOutputStream fos = new FileOutputStream(outputFile); BufferedOutputStream bufOut = new BufferedOutputStream(fos); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bufOut); JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(biOut); param.setQuality(quality, false); encoder.setJPEGEncodeParam(param); encoder.encode(biOut); System.out.println(" jpeg " + pathname + filename); bufOut.close(); } catch (FileNotFoundException e) { System.out.println("file not found" + pathname + filename); } catch (IOException e) { System.out.println("io execption" + pathname + filename); } } public float getAmountOfChange(int _threshold) { int[] rgb; int[] brgb; ps.grabFrame(); // grab a frame int[] newPixels = ps.getPixelArray(); int totalChanged = 0; for (int row = 0; row < kHeight; row++) { // REPEAT FOR EACH ROW OF // PIXELS for (int column = 0; column < ps.vidWidth; column++) { rgb = ps.getPixel(column, row); brgb = ps.getPixel(backgroundReference, column, row); if ((Math.abs(brgb[1] - rgb[1])) > _threshold){; totalChanged++; } } } // END FOR EACH ROW OF PIXELS grabReference(); return ((float) totalChanged) / ((float) (kWidth * kHeight)); } /**Homework someone should write this by modifying the above*/ public ArrayList getChangeRects(int _threshold) { ArrayList changes = new ArrayList(); //someone should write this method return changes; } /**This does not work with secure ftp but if you have a regular ftp server it will*/ public void ftp_utility(String localPath, String localFilename, String serverLogin, String serverPassword, String serverAddress, String serverPath, String serverFilename) { FtpClient fcMyFtp = new FtpClient(); try { int ch; fcMyFtp.openServer(serverAddress); fcMyFtp.login(serverLogin, serverPassword); TelnetInputStream tisList = fcMyFtp.list(); while ((ch = tisList.read()) != -1) ; fcMyFtp.cd(serverPath); fcMyFtp.binary(); FileInputStream fis = new FileInputStream(localPath + localFilename); TelnetOutputStream tos = fcMyFtp.put(serverFilename); byte buffer[] = new byte[1000]; int len; while ((len = fis.read(buffer)) != -1) { tos.write(buffer, 0, len); } fis.close(); tos.close(); } catch (IOException e) { e.printStackTrace(); } } /**For giving your picture and arbitraty title*/ public String getTimeString() { Date now = new Date(); String date = String.valueOf(now.getYear() + "-" + String.valueOf(now.getMonth() + 1) + "-" + String.valueOf(now.getDate())); long millis = now.getTime(); String time = String.valueOf(millis); return date + time; } /**This connects with a php script (see below) that takes in a picture and * puts it somewhere on itp.nyu.edu. You can supply your directory * for example /home/netid/public_html/bla but you have to change the permissions of your bla folder to be world writable. * This is dubious so I might shut it down after this week. */ public void postFileToITP(String _localPath, String _localFilename, String _pathname, String _filename) { DataOutputStream dataOut; String urlString = "http://itp.nyu.edu/~dbo3/VideoSensing/files/WebCam/UpLoad.php"; URLConnection urlConn; URL url; try { url = new URL(urlString); urlConn = url.openConnection(); urlConn.setDoInput(true); urlConn.setDoOutput(true); urlConn.setUseCaches(false); urlConn.setRequestProperty("Content-Type", "multipart/form-data, boundary=AaB03x"); dataOut = new DataOutputStream(urlConn.getOutputStream()); dataOut.writeBytes("--AaB03x\r\n"); dataOut.writeBytes("Content-Disposition: form-data; name=\"image_file\"; filename=\"" + URLEncoder.encode(_pathname + _filename) + "\"\r\n"); dataOut.writeBytes("Content-Type: image/jpeg\r\n"); dataOut.writeBytes("\r\n"); FileInputStream fis = new FileInputStream(_localPath + _localFilename); System.out.println("output from " + _localPath + _localFilename + " to " + _pathname + _filename); byte buffer[] = new byte[1000]; int len; while ((len = fis.read(buffer)) != -1) { dataOut.write(buffer, 0, len); } fis.close(); dataOut.close(); dataOut.writeBytes("\r\n--AaB03x--\r\n"); dataOut.flush(); dataOut.close(); System.out.println("waiting for server"); InputStream in = urlConn.getInputStream(); int input = 0; String inputSt = ""; while (input != -1) { input = in.read(); inputSt = inputSt + ((char) input); } System.out.println("from Server" + inputSt); } catch (MalformedURLException me) { System.err.println("MalformedURLException: " + me); } catch (IOException ioe) { System.err.println("IOException: " + ioe.getMessage()); } } /*This method is talkiing to the following php on the server * \n"; } } ?> */ public void windowDeactivated(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowOpened(WindowEvent e) { } public void keyPressed(KeyEvent e) { } public void keyTyped(KeyEvent e) { } public void windowActivated(WindowEvent e) { } public void windowClosed(WindowEvent e) { } public void mouseClicked(MouseEvent e) { // TODO Auto-generated method stub } public void mouseEntered(MouseEvent e) { // TODO Auto-generated method stub } public void mouseExited(MouseEvent e) { // TODO Auto-generated method stub } public void mousePressed(MouseEvent e) { // TODO Auto-generated method stub } public void mouseReleased(MouseEvent e) { // TODO Auto-generated method stub } }