Voyeurism Redux

For the midterm, I wanted to extend my Voyeurism project. This version of my program, titled “Voyeur,” connects to public (i.e. not password protected) IP cameras in 2 bars in Europe. The patrons of these bars are unaware that they are being broadcasted. While there is no expectation of real privacy when in a public space like a bar, there is something invasive about being watched by someone who is across the Atlantic Ocean. The green-rimmed boxes blur into obscurity any people and objects underneath them. I want to remind users that they are participating in an intrusion, and also allow them an opportunity to give privacy back to the patrons they are watching.

Applet code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
//Kim Ash
//Voyeur 2
//CompCams Spring 2012
import processing.core.PApplet;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import processing.core.PApplet;
import processing.core.PImage;
import javax.imageio.ImageIO;
 
public class Voyeur extends PApplet {
	//.28 Phys Comp (406)
	//.29 inactive - can go in ex-res when needed
	//.188 ("Is Our Machines Learning")
	//.189 On your desk...
 
	//Capture video; 
	//this is what you use for ordinary video cameras
	//requires pointing at the video.jar library from processing
 
	CaptureAxisCamera video;	 //This acts the same the regular but connects to axis net cam
	CaptureAxisCamera video2;
 
	BlurBox box1;
	BlurBox box2;
 
	static public void main(String _args[]) {
		PApplet.main(new String[] { "Voyeur" });
	}
 
	public void setup() {
 
		size(1290,550);
		video = new CaptureAxisCamera(this, "195.43.56.144",width,height,true);	//bar in Engelberg, Switzerland
		video2 = new CaptureAxisCamera(this, "oviso.axiscam.net",width,height,true);	//bar in Barcelona, Spain
		box1 = new BlurBox(500, height/2, 100, 200);
		box2 = new BlurBox(650, height/2, 200, 100);
		//video = new Capture(this, 640,480);
		//this is what you use for ordinary video cameras
	}
 
	public void draw() {
		if (video.available()) {
			video.read();
			image(video, 0, 0);
			//println(video.mjpgURL);
		}
 
		if (video2.available()) {
			video2.read();
			image(video2, 650, 15);
			//println(video3.mjpgURL);
		}
 
		box1.display();
	    box1.drag(mouseX, mouseY);
 
	    box2.display();
	    box2.drag(mouseX, mouseY);
 
		/*fill(255, 0, 0);
		textSize(20);
		text("Engelberg, Switzerland", 10, 270);
		text("Barcelona, Spain", 660, 510);*/
 
	}
 
public class BlurBox {
	int x, y, w, h;
	  boolean dragging = false; // Is the object being dragged?
	  int offsetX, offsetY; // Mouseclick offset
	  PImage blurred;
 
	  BlurBox (int x_, int y_, int w_, int h_) {
	    x = x_;
	    y = y_;
	    w = w_;
	    h = h_;
	    offsetX = 0;
	    offsetY = 0;
	    blurred = new PImage(w_, h_);
	  }
 
	  void display() {
	    // pushMatrix(); you shouldn't need this
	    if (dragging) stroke(255, 255, 0);
	    else stroke(0, 255, 0);
 
	    //fill(0, 0, 0, 150);
	    noFill();
	    //filter(BLUR, 6);
 
	    blurred = get(x, y, w, h);
	    blurred.filter(BLUR, 5);
	    image(blurred, x, y);
 
	    rect(x, y, w, h);
 
	    //  popMatrix(); you shouldn't need this either
	  }
 
 
	  // Is a point inside the rectangle (for click)?
	  boolean clicked(int mx, int my) {
	    if (mx > x && mx < x + w && my > y && my < y + h) {
	      dragging = true;
	      // If so, keep track of relative location of click to corner of rectangle
	      offsetX = x-mx;
	      offsetY = y-my;
	      return true;
	    }
	    else return false;
	  }
 
	  // Is a point inside the rectangle (for rollover)
	  /*void rollover(int mx, int my) {
	   if (mx > x && mx < x + w && my > y && my < y + h) {
	   rollover = true;
	   } else {
	   rollover = false;
	   }
	   }*/
 
	  // Stop dragging
	  void stopDragging() {
	    dragging = false;
	  }
 
	  // Drag the rectangle
	  void drag(int mx, int my) {
	    if (dragging) {
	      x = mx + offsetX;
	      y = my + offsetY;
	    }
	  }
}
 
public void mousePressed() {
	  box1.clicked(mouseX,mouseY);
	  box2.clicked(mouseX,mouseY);
	}
 
public void mouseReleased() {
	  box1.stopDragging();
	  box2.stopDragging();
	}
/**
 * 
 * @author David E. Mireles, Ph.D. (adapted for processing by Dan O'Sullivan)
 */
public class CaptureAxisCamera extends PImage implements Runnable {
	public boolean useMJPGStream = false;
 
	public String ip = "";
	public String jpgURL = "http://128.122.151.200/axis-cgi/jpg/image.cgi?resolution=352x240";
 
	public String mjpgURL  = "http://128.122.151.189/axis-cgi/mjpg/video.cgi?resolution=352x240";
 
	DataInputStream dis;
 
    Image image;
 
    BufferedImage bimage;
 
	public Dimension imageSize = null;
 
	public boolean connected = false;
 
	private boolean initCompleted = false;
 
	HttpURLConnection huc = null;
 
	PApplet parent;
 
	boolean crop;
 
	boolean available;
 
	Method captureEventMethod;
 
	/** Creates a new instance of AxisCamera */
	public CaptureAxisCamera(PApplet _parent, String _ip,int _w, int _h, boolean _useMJPGStream) {
		ip = _ip;
		parent = _parent;
		useMJPGStream = _useMJPGStream;
		jpgURL = "http://"+ ip + "/axis-cgi/jpg/image.cgi?resolution="+ String.valueOf(_w)+ "x" +String.valueOf(_h);
 
		//jpgURL = "";
		mjpgURL  = "http://"+ ip +"/axis-cgi/mjpg/video.cgi?resolution="+ String.valueOf(_w)+ "x" +String.valueOf(_h);
 
		// initialize my PImage self
		super.init(_w, _h, RGB);
 
 
 
 
		try {
			captureEventMethod = parent.getClass().getMethod("captureEvent", new Class[] { CaptureAxisCamera.class });
		} catch (Exception e) {
			// no such method, or an error.. which is fine, just ignore
		}
 
 
 
		Thread myThread = new Thread(this);
		myThread.start();
 
		parent.registerDispose(this);
	}
 
	/**
	 * True if a frame is ready to be read.
	 * 
	 * // put this somewhere inside draw if (capture.available()) capture.read();
	 * 
	 * 
	 * 
	 * Alternatively, you can use captureEvent(Capture c) to notify you whenever available() is set to true. In which case, things might look like this:
	 * 
	 * 
	 * 
	 * public void captureEvent(Capture c) { c.read(); // do something exciting now that c has been updated }
	 * 
	 * 
	 */
	public boolean available() {
		return available;
	}
 
	public void read() {
		// try {
		// synchronized (capture) {
		if (image != null){
		loadPixels();
		synchronized (pixels) {
			// System.out.println("read1");
			if (crop) {
				// System.out.println("read2a");
				// f#$)(#$ing quicktime / jni is so g-d slow, calling copyToArray
				// for the invidual rows is literally 100x slower. instead, first
				// copy the entire buffer to a separate array (i didn't need that
				// memory anyway), and do an arraycopy for each row.
				/*
				 * if (data == null) { data = new int[dataWidth * dataHeight]; } raw.copyToArray(0, data, 0, dataWidth * dataHeight); int sourceOffset = cropX + cropY * dataWidth; int destOffset = 0; for (int y = 0; y < cropH; y++) { System.arraycopy(data, sourceOffset, pixels, destOffset, cropW); sourceOffset += dataWidth; destOffset += width; }
				 */
			} else { // no crop, just copy directly
				// System.out.println("read2b");
				// theData = (byte[]) imageBuffer.getData();
 
				PixelGrabber pg = new PixelGrabber(image,0,0,width,height,pixels,0,width);
 
				   try {
					      pg.grabPixels();
					    } catch (InterruptedException e) { }
				// raw.copyToArray(0, pixels, 0, width * height);
			// }
			// System.out.println("read3");
					    }
			available = false;
			// mark this image as modified so that PGraphicsJava2D and
			// PGraphicsOpenGL will properly re-blit and draw this guy
			updatePixels();
			// System.out.println("read4");
		}
		}
	}
	public void connect() {
		try {
			URL u = new URL(useMJPGStream ? mjpgURL : jpgURL);
			huc = (HttpURLConnection) u.openConnection();
			// System.out.println(huc.getContentType());
			InputStream is = huc.getInputStream();
			connected = true;
			BufferedInputStream bis = new BufferedInputStream(is);
			dis = new DataInputStream(bis);
			if (!initCompleted) initDisplay();
		} catch (IOException e) { // in case no connection exists wait and try again, instead of printing the error
			try {
				huc.disconnect();
				Thread.sleep(60);
			} catch (InterruptedException ie) {
				huc.disconnect();
				connect();
			}
			connect();
		} catch (Exception e) {
			;
		}
	}
 
	public void initDisplay() { // setup the display
		if (useMJPGStream)
			readMJPGStream();
		else {
			readJPG();
			disconnect();
		}
		initCompleted = true;
	}
 
	public void disconnect() {
		try {
			if (connected) {
				dis.close();
				connected = false;
			}
		} catch (Exception e) {
			;
		}
	}
 
 
	public void readStream() { // the basic method to continuously read the stream
		try {
			if (useMJPGStream) {
				while (true) {
					readMJPGStream();
 
				}
			} else {
				while (true) {
					connect();
					readJPG();
 
					disconnect();
 
				}
			}
 
		} catch (Exception e) {
			;
		}
	}
 
	public void readMJPGStream() { // preprocess the mjpg stream to remove the mjpg encapsulation
		readLine(3, dis); // discard the first 3 lines
		readJPG();
		readLine(2, dis); // discard the last two lines
	}
	public BufferedImage getImage(){
		available = false;
		return bimage;
	}
	public void readJPG() { // read the embedded jpeg image
		try {			
			bimage = ImageIO.read(dis);
			image = bimage;
			available = true;
			if (captureEventMethod != null) {
				try {
					captureEventMethod.invoke(parent, new Object[] { this });
				} catch (Exception e) {
					System.err.println("Disabling captureEvent()  because of an error.");
					e.printStackTrace();
					captureEventMethod = null;
				}
			}
 
		} catch (Exception e) {
			e.printStackTrace();
			disconnect();
		}
	}
	/**
	 * Called by PApplet to shut down video so that QuickTime can be used later by another applet.
	 */
	public void dispose() {
		disconnect();
 
	}
	public void readLine(int n, DataInputStream dis) { // used to strip out the header lines
		for (int i = 0; i < n; i++) {
			readLine(dis);
		}
	}
 
	public void readLine(DataInputStream dis) {
		try {
			boolean end = false;
			String lineEnd = "n"; // assumes that the end of the line is marked with this
			byte[] lineEndBytes = lineEnd.getBytes();
			byte[] byteBuf = new byte[lineEndBytes.length];
 
			while (!end) {
				dis.read(byteBuf, 0, lineEndBytes.length);
				String t = new String(byteBuf);
				// System.out.print(t); //uncomment if you want to see what the lines actually look like
				if (t.equals(lineEnd)) end = true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
 
	}
 
	public void run() {
		connect();
		readStream();
	}
}
}