TeZ LIFE/FORMS workshop info + code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
9.8 KiB

2 years ago
  1. /*
  2. This code is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published
  4. by the Free Software Foundation, either version 3 of the License,
  5. or (at your option) any later version.
  6. This code is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  9. General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this code. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. /* Code logic in short:
  14. The code reads the webcam image
  15. Detects contours
  16. Filter contours based on size
  17. Checks whether contour is new or a movement of an existing contour based on a threshold
  18. Reoccuring contours are saved as blobs
  19. The first blob is assigned as being pacman, you can also click on another blob to switch pacman
  20. A matrix of dots is drawn
  21. In case pacman is near a dot, it gets destroy and score + 1
  22. */
  23. /* Most important values for tracking:
  24. contourTreshold
  25. sizeTreshold
  26. /*
  27. /* Load libraries */
  28. import gab.opencv.*; // Load library https://github.com/atduskgreg/opencv-processing
  29. import processing.video.*; // Load video camera library
  30. /* Declare variables */
  31. Capture video; // Camera stream
  32. OpenCV opencv; // OpenCV
  33. PImage now, diff; // PImage variables to store the current image and the difference between two images
  34. PGraphics drawing; // PGraphics buffer
  35. ArrayList<Contour> contours; // ArrayList to hold all detected contours
  36. ArrayList<Blob> blobs = new ArrayList <Blob>(); // ArrayList to hold all blobs
  37. PFont font; // A new font object
  38. int ContourThreshold = 20; // Contour detection sensitivity of the script
  39. int SizeThreshold = 100; // Contour size threshold
  40. int MovementMargin = 40; // Max difference in coordinates
  41. int segmentSize = 5; // orig 5;
  42. int segmentThreshold = segmentSize * segmentSize / 3;
  43. /* Slider Bar */
  44. HScrollbar hs1, hs2;
  45. Boolean scroll_lock = false;
  46. /* Setup function */
  47. void setup() {
  48. size(640, 960); // Create canvas window
  49. // Select camera: print all available cameras in a list
  50. String[] cameras = Capture.list();
  51. if (cameras.length == 0) {
  52. println("There are no cameras available for capture.");
  53. exit();
  54. } else {
  55. println("Available cameras:");
  56. for (int i = 0; i < cameras.length; i++) {
  57. println(i, cameras[i]);
  58. }
  59. }
  60. // select the number of the webcam camera from the list
  61. // video = new Capture(this, 640, 480, cameras[12], 30); // Define video size, with webcam plugged in
  62. video = new Capture(this, 640, 480, cameras[16], 30);
  63. opencv = new OpenCV(this, 640, 480); // Define opencv size
  64. video.start(); // Start capturing video
  65. font = loadFont("Serif-48.vlw"); // Load the font file into memory
  66. textFont(font, 12); // Set font size
  67. strokeWeight(3); // Set stroke size
  68. noStroke();
  69. hs1 = new HScrollbar(0, height/2-8, width, 16, 16);
  70. hs2 = new HScrollbar(0, height/2+8, width, 16, 16);
  71. }
  72. /* Draw function */
  73. void draw() {
  74. // start buffer
  75. drawing = createGraphics(640, 480);
  76. drawing.beginDraw();
  77. drawing.noStroke();
  78. int[] segments = new int[int(640/segmentSize)*int((480)/segmentSize)]; // Set number segments
  79. opencv.loadImage(video); // Capture video from camera in OpenCV
  80. image(video, 0, 0); // Draw camera image to screen
  81. opencv.gray(); // Convert into gray scale
  82. //opencv.contrast(2); // Increase contrast
  83. opencv.invert(); // Invert b/w
  84. //opencv.blur(3); // Reduce camera noise
  85. opencv.threshold(ContourThreshold); // Convert to Black and White
  86. //opencv.flip(OpenCV.VERTICAL); // Flip image vertical
  87. now = opencv.getOutput(); // Store image in PImage
  88. image(now, 0, 480); // Show video (black and white)
  89. // Analyze image
  90. int segmentCounter = 0;
  91. for( int x = 1; x < 640; x = x + segmentSize) {
  92. for ( int y = 1; y < 480; y = y + segmentSize) {
  93. int segmentBrightness = 0;
  94. for ( int i = 0; i < segmentSize; i++) {
  95. for ( int j = 0; j < segmentSize; j++) {
  96. if (brightness(now.pixels[x+i+(y*width)+j]) > 127) {
  97. segmentBrightness++;
  98. }
  99. }
  100. }
  101. if(segmentBrightness > segmentThreshold) { // segment is bright
  102. segments[segmentCounter] = 1;
  103. drawing.fill(255,255,255);
  104. drawing.rect(x-1,y-1,12,12);
  105. }
  106. segmentCounter++;
  107. }
  108. }
  109. drawing.endDraw();
  110. // Draw the offscreen buffer to the screen with image()
  111. image(drawing, 0, 0);
  112. //opencv.loadImage(drawing);
  113. // Analyze video
  114. contours = opencv.findContours(); // Find contours
  115. int evalc = 0; // Count number of evaluated contours
  116. for (Contour contour : contours) { // Loop through all contours
  117. int sumx = 0; // Sum of all x coordinates
  118. int sections = 0; // # of sections
  119. int sumy = 0; // Sum of all y coordinates
  120. int area = 0; // Area of polygon
  121. ArrayList<Integer> Xcoors = new ArrayList<Integer>(); // List of all X coordinates
  122. ArrayList<Integer> Ycoors = new ArrayList<Integer>(); // List of all Y coordinates
  123. for (PVector point : contour.getPolygonApproximation().getPoints()) { // Loop through all vertex X Y coordinates of polygon
  124. sumx = sumx + int(point.x); // Sum up all X coordinates, needed for calculating the middle
  125. sumy = sumy + int(point.y); // Sum up all Y coordinates, needed for calculating the middle
  126. Xcoors.add(int(point.x)); // Store all X coordinates, needed for calculating the area
  127. Ycoors.add(int(point.y)); // Store all Y coordinates, needed for calculating the area
  128. sections++; // Count the number of sections
  129. }
  130. // Calculate the area of the polygon
  131. int j = 0;
  132. for (int i = 0; i < sections; i++) {
  133. area = area + (Xcoors.get(j)+Xcoors.get(i)) * (Ycoors.get(j)-Ycoors.get(i));
  134. j = i;
  135. }
  136. area = area / 2;
  137. if(area > SizeThreshold && area < 100000) { // Check whether area is above threshold and not as big as the video itself
  138. evalc++; // Up 1 for the evaluated contours counter
  139. noFill(); // Disable filled shapes
  140. stroke(0, 255, 0); // Set stroke color to green
  141. contour.draw(); // Draw the contour
  142. fill(255, 0, 0); // Set color to red
  143. text((sumx/sections) + ", " + (sumy/sections), (sumx/sections), (sumy/sections)); // Print the coordinates on screen
  144. if(blobs.size() > 0) { // Check whether this is the first blob or not
  145. boolean withinmargin = false; // Flag whether it is close to a previous blob
  146. int withinmarginID = 0; // Remember which one that was
  147. for( int i = 0; i < blobs.size(); i++) { // Loop through all blobs
  148. Blob _blob = (Blob) blobs.get(i); // Make a temp copy
  149. int lastX = _blob.blobX.get(_blob.blobX.size()-1); // most recent X coordinate
  150. int lastY = _blob.blobY.get(_blob.blobY.size()-1); // most recent Y coordinate
  151. // Check whether the contour is within movement margin, otherwise it's a new blob
  152. if(lastX < (sumx/sections + MovementMargin)){
  153. if(lastX > (sumx/sections - MovementMargin)) {
  154. if(lastY < (sumy/sections + MovementMargin)) {
  155. if(lastY > (sumy/sections - MovementMargin)) {
  156. withinmargin = true;
  157. withinmarginID = i;
  158. // println("hit X old: " + lastX + "; new:" + sumx/c + "; Y old: " + lastY + "; Y new: " +sumy/c);
  159. }
  160. }
  161. }
  162. }
  163. _blob = null; // Reset temp copy
  164. }
  165. if(withinmargin) { // Within margin? True: add coordinates to ArrayList
  166. Blob _blob = (Blob) blobs.get(withinmarginID); // Make temp copy of blob
  167. _blob.addXYSA(sumx/sections, sumy/sections, sections, area); // Add the information to the ArrayLists of the blob object
  168. blobs.set(withinmarginID, _blob); // Store the blob
  169. } else { // else: it's a new blob
  170. blobs.add(new Blob(sumx/sections, sumy/sections, sections, area, false)); // Add new blob to the blobs ArrayList
  171. }
  172. } else { // Add first blob, which becomes PacMan
  173. blobs.add(new Blob(sumx/sections, sumy/sections, sections, area, true)); // Store blob and flag as PacMan
  174. }
  175. }
  176. }
  177. // Print some useful monitoring info to the console
  178. println("Found " + contours.size() + " Contours; area > "+SizeThreshold+" px " + evalc + "; Total "+ blobs.size() + " blobs" + " mouseX: " + mouseX);
  179. ContourThreshold = int(hs1.getPos()); // get scrollbar position
  180. fill(0,0,255); // Set color to blue
  181. textSize(20); // Increase text size
  182. text("CountourThreshold: " + ContourThreshold, 20, 40);
  183. int multiplySizeTreshold = 2; // variable for multiplying the Sizetreshold
  184. SizeThreshold = int(hs2.getPos()) * multiplySizeTreshold; // NEW: multiply w/ 100 to get a bigger max SizeTreshold
  185. // SizeThreshold = int(hs2.getPos());
  186. text("SizeThreshold: " + SizeThreshold * 10, 30, 60);
  187. scroll_lock = hs1.update(scroll_lock);
  188. scroll_lock = hs2.update(scroll_lock);
  189. hs1.display();
  190. hs2.display();
  191. // Wait a little before the next round to save processing power and memory
  192. delay(40);
  193. }
  194. /* Capture function */
  195. void captureEvent(Capture c) {
  196. c.read();
  197. }