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.

1031 lines
25 KiB

2 years ago
  1. //TO-DO
  2. // add a cvs recorder for blop positions
  3. //timer
  4. import gab.opencv.*;
  5. import java.awt.Rectangle;
  6. import processing.video.*;
  7. import controlP5.*;
  8. import oscP5.*;
  9. import netP5.*;
  10. final static int OSC_IN_PORT = 8444;
  11. OscP5 mOscP5;
  12. OpenCV opencv;
  13. Capture video;
  14. PImage src, preProcessedImage, processedImage, contoursImage;
  15. //record time-lapse
  16. boolean record = false;
  17. boolean invert = true;
  18. ArrayList<Contour> contours;
  19. // List of detected contours parsed as blobs (every frame)
  20. ArrayList<Contour> newBlobContours;
  21. // List of my blob objects (persistent)
  22. ArrayList<Blob> blobList;
  23. // Number of blobs detected over all time. Used to set IDs.
  24. int blobCount = 0;
  25. float scalefactor = 1.0, scaleX = 1.0, scaleY = 1.0 ;
  26. float contrast = 3.0;
  27. int brightness = 0;
  28. int threshold = 75;
  29. boolean useAdaptiveThreshold = false; // use basic thresholding
  30. boolean RecordTimelapse = false; // genera una imagen por segundo
  31. boolean screenmode = true;
  32. boolean blobSwitch = true;
  33. boolean bSwitch = true;
  34. boolean srcswitch = true;
  35. boolean helpflag = false;
  36. int thresholdBlockSize = 489;
  37. int thresholdConstant = 45;
  38. int blobSizeThreshold = 20;
  39. int blurSize = 4;
  40. IntList bAreas;
  41. IntList bX;
  42. IntList bY;
  43. int xID=0;
  44. int xArea=0;
  45. // Control vars
  46. ControlP5 cp5;
  47. int buttonColor;
  48. int buttonBgColor;
  49. long lastOscMillis;
  50. Textlabel myTitle;
  51. Textlabel controllers;
  52. boolean showcontrol = false;
  53. // Console vars
  54. String[] cons = {"1","2","3","4","5","6","7","8"};
  55. boolean console = false;
  56. int consindex = 0;
  57. // camera vars
  58. String[] cameras = Capture.list();
  59. int capW = 960, capH = 540;
  60. void setup() {
  61. // size(1160, 540);
  62. fullScreen();
  63. println("screen width: " + width + "screen height: " + height);
  64. surface.setResizable(true);
  65. noStroke();
  66. // clear console
  67. cons(1,"clear");
  68. // list cameras
  69. printCameraList();
  70. // frameRate(15);
  71. lastOscMillis = millis();
  72. mOscP5 = new OscP5(this, OSC_IN_PORT);
  73. // init video capture size and start video
  74. setCaptureSize(16); // argument is the number of the camera (see camera list)
  75. // init Contours
  76. contours = new ArrayList<Contour>();
  77. // Blobs list
  78. blobList = new ArrayList<Blob>();
  79. // Init Controls
  80. cp5 = new ControlP5(this);
  81. initControls();
  82. // Set thresholding
  83. toggleAdaptiveThreshold(useAdaptiveThreshold);
  84. // Reset Blob Timer
  85. btimer_reset();
  86. bAreas = new IntList();
  87. bX = new IntList();
  88. bY = new IntList();
  89. }
  90. ////////////////////////////////////
  91. ///////// DRAW LOOP ////////////////
  92. ////////////////////////////////////
  93. void draw() {
  94. background(0,0,0);
  95. // Read last captured frame
  96. if (video.available()) {
  97. video.read();
  98. }
  99. // Load the new frame of our camera in to OpenCV
  100. opencv.useColor();
  101. opencv.loadImage(video);
  102. // Flips the image horizontally
  103. opencv.flip(OpenCV.HORIZONTAL);
  104. src = opencv.getSnapshot();
  105. ///////////////////////////////
  106. // <1> PRE-PROCESS IMAGE
  107. // - Grey channel
  108. // - Brightness / Contrast
  109. ///////////////////////////////
  110. // Gray channel
  111. opencv.gray();
  112. //opencv.brightness(brightness);
  113. opencv.contrast(contrast);
  114. // Save snapshot for display
  115. preProcessedImage = opencv.getSnapshot();
  116. ///////////////////////////////
  117. // <2> PROCESS IMAGE
  118. // - Threshold
  119. // - Noise Supression
  120. ///////////////////////////////
  121. // Adaptive threshold - Good when non-uniform illumination
  122. if (useAdaptiveThreshold) {
  123. // Block size must be odd and greater than 3
  124. if (thresholdBlockSize%2 == 0) thresholdBlockSize++;
  125. if (thresholdBlockSize < 3) thresholdBlockSize = 3;
  126. opencv.adaptiveThreshold(thresholdBlockSize, thresholdConstant);
  127. // Basic threshold - range [0, 255]
  128. } else {
  129. opencv.threshold(threshold);
  130. }
  131. if(invert){
  132. // Invert (black bg, white blobs)
  133. opencv.invert();
  134. }
  135. // Reduce noise - Dilate and erode to close holes
  136. opencv.dilate();
  137. opencv.erode();
  138. // Blur
  139. opencv.blur(blurSize);
  140. // Save snapshot for display
  141. processedImage = opencv.getSnapshot();
  142. ///////////////////////////////
  143. // <3> FIND CONTOURS
  144. ///////////////////////////////
  145. detectBlobs();
  146. // Passing 'true' sorts them by descending area.
  147. //contours = opencv.findContours(true, true);
  148. // Save snapshot for display
  149. contoursImage = opencv.getSnapshot();
  150. if (screenmode){
  151. // Draw
  152. pushMatrix();
  153. // Leave space for ControlP5 sliders
  154. //translate(width-src.width, 0);
  155. translate(0, 0);
  156. // Display images
  157. displayImages();
  158. // Display contours in the lower right window
  159. pushMatrix();
  160. //scale(0.5 * scalefactor);
  161. scale(0.5 * scaleX,0.5 * scaleY);
  162. translate(src.width, src.height * 1);
  163. // Contours
  164. if (bSwitch){displayContours();}
  165. //displayContoursBoundingBoxes();
  166. // Blobs
  167. if (bSwitch){ displayBlobs();}
  168. popMatrix();
  169. popMatrix();
  170. } else{
  171. // Draw
  172. pushMatrix();
  173. // translate(width-src.width, 0);
  174. translate(0, 0);
  175. displayTrack();
  176. // Display contours in the lower right window
  177. pushMatrix();
  178. // scale(scalefactor);
  179. scale(scaleX, scaleY);
  180. // Contours
  181. if (bSwitch){displayContours();}
  182. //displayContoursBoundingBoxes();
  183. // Blobs
  184. if (bSwitch){displayBlobs(); }
  185. popMatrix();
  186. popMatrix();
  187. }// end if screenmode
  188. // SHOW CONTROLS
  189. if(showcontrol){
  190. // background controls
  191. fill(0, 80, 80, 200);
  192. noStroke();
  193. rect(0, 0, 180, 270);
  194. showControls();
  195. }else{hideControls();}
  196. // SHOW CONSOLE
  197. if(console){
  198. showConsole();
  199. }
  200. // SHOW HELP
  201. if(helpflag){
  202. showHelp();
  203. }
  204. // press R key for timelapse recording
  205. if (record == true) {
  206. saveFrame("timelapse-######.png");
  207. delay(100);
  208. }
  209. if (record == false) {
  210. record = false; // Stop recording to the file
  211. }
  212. // write osc
  213. if (millis()-lastOscMillis > 100) {
  214. for (Blob b : blobList) {
  215. b.sendOsc();
  216. }
  217. // lastOscMillis = millis();
  218. }
  219. // draw blob lines and reset blobs every 3 seconds
  220. if(btimer_passed(3)){
  221. resetBlobs();
  222. btimer_reset();
  223. }
  224. } // END DRAW LOOP
  225. ///////////////////////
  226. // Display Functions
  227. ///////////////////////
  228. void displayImages() {
  229. //
  230. pushMatrix();
  231. // scale(0.5);
  232. // scale(scalefactor / 2.);
  233. scale(0.5 * scaleX,0.5 * scaleY);
  234. image(src, 0, 0);
  235. image(preProcessedImage, src.width, 0);
  236. image(processedImage, 0, src.height);
  237. image(src, src.width, src.height);
  238. popMatrix();
  239. stroke(255);
  240. fill(255);
  241. textSize(12);
  242. text("Source", 10, 25);
  243. text("Pre-processed Image", src.width/2 * scalefactor + 10, 25);
  244. text("Processed Image", 10, src.height/2 * scalefactor + 25);
  245. text("Tracked Points", src.width/2 * scalefactor + 10, src.height/2 * scalefactor + 25);
  246. }
  247. ////////////////////////
  248. void displayTrack() {
  249. pushMatrix();
  250. //scale(1.);
  251. // scale(scalefactor);
  252. scale(scaleX,scaleY);
  253. if(srcswitch){image(src, 0, 0);}
  254. popMatrix();
  255. stroke(255);
  256. fill(255,0,0);
  257. textSize(24);
  258. if(srcswitch){text("Live Tracking", 10, 20);}
  259. }
  260. ///////////////////////
  261. void displayBlobs() {
  262. // if(blobSwitch){blobLines();}
  263. for (Blob b : blobList) {
  264. strokeWeight(1);
  265. b.display();
  266. }
  267. }
  268. ///////////////////////
  269. void displayContours() {
  270. // Contours
  271. for (int i=0; i<contours.size (); i++) {
  272. Contour contour = contours.get(i);
  273. noFill();
  274. stroke(0, 255, 0);
  275. strokeWeight(3);
  276. contour.draw();
  277. }
  278. }
  279. void displayContoursBoundingBoxes() {
  280. for (int i=0; i<contours.size (); i++) {
  281. Contour contour = contours.get(i);
  282. Rectangle r = contour.getBoundingBox();
  283. if (//(contour.area() > 0.9 * src.width * src.height) ||
  284. (r.width < blobSizeThreshold || r.height < blobSizeThreshold))
  285. continue;
  286. stroke(255, 0, 0);
  287. fill(255, 0, 0, 150);
  288. strokeWeight(2);
  289. rect(r.x, r.y, r.width, r.height);
  290. }
  291. }
  292. ////////////////////
  293. // Blob Detection
  294. ////////////////////
  295. void detectBlobs() {
  296. // Contours detected in this frame
  297. // Passing 'true' sorts them by descending area.
  298. contours = opencv.findContours(true, true);
  299. newBlobContours = getBlobsFromContours(contours);
  300. cons(1, "contours.size(): " + contours.size());
  301. cons(2, "newBlobContours.size(): " + newBlobContours.size());
  302. cons(3, "blobList.size(): " + blobList.size());
  303. // Check if the detected blobs already exist are new or some has disappeared.
  304. if (blobSwitch){
  305. // SCENARIO 1
  306. // blobList is empty
  307. if (blobList.isEmpty()) {
  308. // Just make a Blob object for every face Rectangle
  309. for (int i = 0; i < newBlobContours.size (); i++) {
  310. // println("+++ New blob detected with ID: " + blobCount);
  311. blobList.add(new Blob(this, blobCount, newBlobContours.get(i)));
  312. blobCount++;
  313. /*
  314. // for bloblines
  315. Rectangle r = newBlobContours.get(i).getBoundingBox();
  316. xArea=r.width * r.height;
  317. bAreas.append(xArea);
  318. int tempX = (int)r.getCenterX();
  319. bX.append(tempX);
  320. int tempY=(int)r.getCenterY();
  321. bY.append(tempX);
  322. */
  323. }
  324. // SCENARIO 2
  325. // We have fewer Blob objects than face Rectangles found from OpenCV in this frame
  326. } else if (blobList.size() <= newBlobContours.size()) {
  327. boolean[] used = new boolean[newBlobContours.size()];
  328. // Match existing Blob objects with a Rectangle
  329. for (Blob b : blobList) {
  330. // Find the new blob newBlobContours.get(index) that is closest to blob b
  331. // set used[index] to true so that it can't be used twice
  332. float record = 50000;
  333. int index = -1;
  334. for (int i = 0; i < newBlobContours.size (); i++) {
  335. float d = dist(newBlobContours.get(i).getBoundingBox().x, newBlobContours.get(i).getBoundingBox().y, b.getBoundingBox().x, b.getBoundingBox().y);
  336. //float d = dist(blobs[i].x, blobs[i].y, b.r.x, b.r.y);
  337. if (d < record && !used[i]) {
  338. record = d;
  339. index = i;
  340. }
  341. }
  342. // Update Blob object location
  343. used[index] = true;
  344. b.update(newBlobContours.get(index));
  345. }
  346. // Add any unused blobs
  347. for (int i = 0; i < newBlobContours.size (); i++) {
  348. if (!used[i]) {
  349. // println("+++ New blob detected with ID: " + blobCount);
  350. blobList.add(new Blob(this, blobCount, newBlobContours.get(i)));
  351. //blobList.add(new Blob(blobCount, blobs[i].x, blobs[i].y, blobs[i].width, blobs[i].height));
  352. blobCount++;
  353. }
  354. }
  355. // SCENARIO 3
  356. // We have more Blob objects than blob Rectangles found from OpenCV in this frame
  357. } else {
  358. // All Blob objects start out as available
  359. for (Blob b : blobList) {
  360. b.available = true;
  361. }
  362. // Match Rectangle with a Blob object
  363. for (int i = 0; i < newBlobContours.size (); i++) {
  364. // Find blob object closest to the newBlobContours.get(i) Contour
  365. // set available to false
  366. float record = 50000;
  367. int index = -1;
  368. for (int j = 0; j < blobList.size (); j++) {
  369. Blob b = blobList.get(j);
  370. float d = dist(newBlobContours.get(i).getBoundingBox().x, newBlobContours.get(i).getBoundingBox().y, b.getBoundingBox().x, b.getBoundingBox().y);
  371. //float d = dist(blobs[i].x, blobs[i].y, b.r.x, b.r.y);
  372. if (d < record && b.available) {
  373. record = d;
  374. index = j;
  375. }
  376. }
  377. // Update Blob object location
  378. Blob b = blobList.get(index);
  379. b.available = false;
  380. b.update(newBlobContours.get(i));
  381. /*
  382. // for bloblines
  383. Rectangle r = newBlobContours.get(i).getBoundingBox();
  384. xArea=r.width * r.height;
  385. bAreas.set(i,xArea);
  386. int tempX = (int)r.getCenterX();
  387. bX.set(i,tempX);
  388. int tempY=(int)r.getCenterY();
  389. bY.set(i,tempY);
  390. */
  391. }
  392. // Start to kill any left over Blob objects
  393. for (Blob b : blobList) {
  394. if (b.available) {
  395. b.countDown();
  396. if (b.dead()) {
  397. b.delete = true;
  398. }
  399. }
  400. }
  401. }
  402. // Delete any blob that should be deleted
  403. for (int i = blobList.size ()-1; i >= 0; i--) {
  404. Blob b = blobList.get(i);
  405. if (b.delete) {
  406. blobList.remove(i);
  407. }
  408. }
  409. }
  410. }
  411. ///////////////////////
  412. void resetBlobs(){
  413. blobSwitch = false;
  414. for (int i = blobList.size ()-1; i >= 0; i--) {
  415. blobList.remove(i);}
  416. blobCount=0;
  417. for (int i=0; i<blobList.size (); i++) {
  418. blobList.remove(i);
  419. }
  420. for (int i=0; i<contours.size (); i++) {
  421. contours.remove(i);}
  422. for (int i=0; i<newBlobContours.size (); i++) {
  423. newBlobContours.remove(i);}
  424. // delete all entries
  425. bAreas.clear();
  426. bX.clear();
  427. bY.clear();
  428. blobSwitch = true;
  429. }
  430. ////////////////////////////////////////////
  431. void blobLines(){
  432. /*
  433. cons(5, "bAreas:" + bAreas.size() + " bX size:" + bX.size() + " bY size:" + bY.size());
  434. // bAreas.sort();
  435. cons(6, " bX:" + bX);
  436. if(bAreas.size()>0){
  437. for(int i=1; i<bAreas.size();i++){
  438. //cons(8, " bX[0]:" + bX.get(0)+ " bY[0]:" + bY.get(0)+ " bX[1]:" + bX.get(1)+" bY[1]:" + bY.get(1));
  439. stroke(255,0,0);
  440. line(bX.get(i-1), bY.get(i-1), bX.get(i), bY.get(i));
  441. }
  442. }
  443. */
  444. }
  445. ///////////////////////
  446. ArrayList<Contour> getBlobsFromContours(ArrayList<Contour> newContours) {
  447. ArrayList<Contour> newBlobs = new ArrayList<Contour>();
  448. // Which of these contours are blobs?
  449. for (int i=0; i<newContours.size (); i++) {
  450. Contour contour = newContours.get(i);
  451. Rectangle r = contour.getBoundingBox();
  452. if (//(contour.area() > 0.9 * src.width * src.height) ||
  453. (r.width < blobSizeThreshold || r.height < blobSizeThreshold))
  454. continue;
  455. newBlobs.add(contour);
  456. }
  457. return newBlobs;
  458. }
  459. //////////////////////////
  460. // CONTROL P5 Functions
  461. //////////////////////////
  462. void initControls() {
  463. cp5.addScrollableList("cameraz")
  464. .setPosition(180, 0)
  465. .setSize(300, 300)
  466. .setBarHeight(20)
  467. .setItemHeight(20)
  468. .addItems(cameras)
  469. .setCaptionLabel("video input")
  470. // .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
  471. ;
  472. cp5.get(ScrollableList.class, "cameraz").setType(ControlP5.DROPDOWN);
  473. cp5.get(ScrollableList.class, "cameraz").close();
  474. cp5.get(ScrollableList.class, "cameraz").setColorBackground(#008080);
  475. CColor c = new CColor();
  476. c.setBackground(color(0,80,80));
  477. c.setAlpha(100);
  478. cp5.get(ScrollableList.class, "cameraz").setColor(c);
  479. PFont pfont = createFont("Arial",20,true); // use true/false for smooth/no-smooth
  480. ControlFont font = new ControlFont(pfont,12);
  481. //label
  482. myTitle = cp5.addTextlabel("label")
  483. .setText("M I K R O T R A C K E R")
  484. .setPosition(16, 40)
  485. .setColorValue(color(0,0,0))
  486. .setFont(font)
  487. //.setColorValue(0x000000ff)
  488. ;
  489. // Slider for contrast
  490. cp5.addSlider("contrast")
  491. .setLabel("contrast")
  492. .setPosition(10, 70)
  493. .setRange(0.0, 6.0)
  494. .setColorValue(color(255))
  495. .setColorActive(color(0,100,0))
  496. .setColorForeground(color(0,100,0))
  497. .setColorBackground(color(0, 0, 0))
  498. ;
  499. // Slider for threshold
  500. cp5.addSlider("threshold")
  501. .setLabel("threshold")
  502. .setPosition(10, 90)
  503. .setRange(0, 255)
  504. .setColorValue(color(255))
  505. .setColorActive(color(0,100,0))
  506. .setColorForeground(color(0,100,0))
  507. .setColorBackground(color(0, 0, 0))
  508. ;
  509. // Toggle to activae adaptive threshold
  510. cp5.addToggle("toggleAdaptiveThreshold")
  511. .setLabel("use adaptive threshold")
  512. .setSize(10, 10)
  513. .setPosition(10, 120)
  514. .setColorValue(color(255))
  515. .setColorActive(color(0,100,0))
  516. .setColorForeground(color(0,100,0))
  517. .setColorBackground(color(0, 0, 0))
  518. ;
  519. // Slider for adaptive threshold block size
  520. cp5.addSlider("thresholdBlockSize")
  521. .setLabel("a.t. block size")
  522. .setPosition(10, 150)
  523. .setRange(1, 700)
  524. .setColorValue(color(255))
  525. .setColorActive(color(0,100,0))
  526. .setColorForeground(color(0,100,0))
  527. .setColorBackground(color(0, 0, 0))
  528. ;
  529. // Slider for adaptive threshold constant
  530. cp5.addSlider("thresholdConstant")
  531. .setLabel("a.t. constant")
  532. .setPosition(10, 170)
  533. .setRange(-100, 100)
  534. .setColorValue(color(255))
  535. .setColorActive(color(0,100,0))
  536. .setColorForeground(color(0,100,0))
  537. .setColorBackground(color(0, 0, 0))
  538. ;
  539. // Slider for blur size
  540. cp5.addSlider("blurSize")
  541. .setLabel("blur size")
  542. .setPosition(10, 210)
  543. .setRange(1, 20)
  544. .setColorValue(color(255))
  545. .setColorActive(color(0,100,0))
  546. .setColorForeground(color(0,100,0))
  547. .setColorBackground(color(0, 0, 0))
  548. ;
  549. // Slider for minimum blob size
  550. cp5.addSlider("blobSizeThreshold")
  551. .setLabel("min blob size")
  552. .setPosition(10, 230)
  553. .setRange(0, 60)
  554. .setColorValue(color(255))
  555. .setColorActive(color(0,100,0))
  556. .setColorForeground(color(0,100,0))
  557. .setColorBackground(color(0, 0, 0))
  558. ;
  559. /*
  560. // Toggle to activae record CVS file
  561. cp5.addToggle("toggleRecordTimelapse")
  562. .setLabel("record timelapse")
  563. .setSize(10, 10)
  564. .setPosition(15, 380)
  565. .setColorValue(color(255))
  566. .setColorActive(color(0,100,0))
  567. .setColorForeground(color(0,100,0))
  568. .setColorBackground(color(0, 0, 0))
  569. ;
  570. // Slider for timelapse
  571. cp5.addSlider("timelapse")
  572. .setLabel("time-lapse")
  573. .setPosition(15, 410)
  574. .setRange(0.01, 60)
  575. .setColorValue(color(255))
  576. .setColorActive(color(0,100,0))
  577. .setColorForeground(color(0,100,0))
  578. .setColorBackground(color(0, 0, 0))
  579. ;
  580. */
  581. // Store the default background color, we gonna need it later
  582. buttonColor = cp5.getController("contrast").getColor().getForeground();
  583. buttonBgColor = cp5.getController("contrast").getColor().getBackground();
  584. }
  585. //////////////////////////
  586. void toggleAdaptiveThreshold(boolean theFlag) {
  587. useAdaptiveThreshold = theFlag;
  588. if (useAdaptiveThreshold) {
  589. // Lock basic threshold
  590. setLock(cp5.getController("threshold"), true);
  591. // Unlock adaptive threshold
  592. setLock(cp5.getController("thresholdBlockSize"), false);
  593. setLock(cp5.getController("thresholdConstant"), false);
  594. } else {
  595. // Unlock basic threshold
  596. setLock(cp5.getController("threshold"), false);
  597. // Lock adaptive threshold
  598. setLock(cp5.getController("thresholdBlockSize"), true);
  599. setLock(cp5.getController("thresholdConstant"), true);
  600. }
  601. }
  602. //////////////////////////
  603. void setLock(Controller theController, boolean theValue) {
  604. theController.setLock(theValue);
  605. if (theValue) {
  606. theController.setColorBackground(color(150, 150));
  607. theController.setColorForeground(color(100, 100));
  608. } else {
  609. theController.setColorBackground(color(buttonBgColor));
  610. theController.setColorForeground(color(buttonColor));
  611. }
  612. }
  613. //////////////////////////
  614. void hideControls(){
  615. cp5.getController("cameraz").hide();
  616. cp5.getController("contrast").hide();
  617. cp5.getController("label").hide();
  618. cp5.getController("threshold").hide();
  619. cp5.getController("toggleAdaptiveThreshold").hide();
  620. cp5.getController("thresholdBlockSize").hide();
  621. cp5.getController("thresholdConstant").hide();
  622. cp5.getController("blurSize").hide();
  623. cp5.getController("blobSizeThreshold").hide();
  624. // cp5.getController("toggleRecordTimelapse").hide();
  625. // cp5.getController("timelapse").hide();
  626. }
  627. //////////////////////////
  628. void showControls(){
  629. cp5.getController("cameraz").show();
  630. cp5.getController("contrast").show();
  631. cp5.getController("label").show();
  632. cp5.getController("threshold").show();
  633. cp5.getController("toggleAdaptiveThreshold").show();
  634. cp5.getController("thresholdBlockSize").show();
  635. cp5.getController("thresholdConstant").show();
  636. cp5.getController("blurSize").show();
  637. cp5.getController("blobSizeThreshold").show();
  638. // cp5.getController("toggleRecordTimelapse").show();
  639. // cp5.getController("timelapse").show();
  640. }
  641. //////////////////////////
  642. void cameraz(int n) {
  643. /* request the selected item based on index n */
  644. // println(n, cp5.get(ScrollableList.class, "cameraz").getItem(n));
  645. cons(5, cameras[n]);
  646. cp5.get(ScrollableList.class, "cameraz").close();
  647. video.stop();
  648. setCaptureSize(n);
  649. // video = new Capture(this, capW, capH, cameras[n]);
  650. // video.start();
  651. }
  652. //////////////////////////
  653. void toggleRecordTimelapse(boolean theFlag) {
  654. RecordTimelapse = theFlag;
  655. if (RecordTimelapse) {
  656. // Lock basic threshold
  657. record = true;
  658. setLock(cp5.getController("timelapse"), true);
  659. } else {
  660. record = false;
  661. }
  662. }
  663. void keyPressed() {
  664. if (key == '0' ) { // toggle src image
  665. srcswitch = !(srcswitch);
  666. }
  667. if (key == '1') { // show capture / blob screens
  668. screenmode = !(screenmode);
  669. }
  670. if (key == 'C' || key == 'c') { // toggle showcontrol
  671. showcontrol = !(showcontrol);
  672. }
  673. if (key == 'I' || key == 'i') { // invert
  674. invert = !(invert);
  675. }
  676. if (key == '~' ) { // toggle console
  677. console = !(console);
  678. }
  679. if (key == 'B' || key == 'b') { // reset blobs
  680. resetBlobs();
  681. }
  682. if (key == 'x') {
  683. bSwitch=!(bSwitch);
  684. }
  685. if (key == 's') {
  686. saveFrame("mikro-######.png");
  687. }
  688. if (key == 'H' || key == 'h') {
  689. helpflag = !helpflag;
  690. }
  691. /*
  692. if (key == 'R' || key == 'r') { // Press R start time-lapse
  693. record = true;
  694. }
  695. if (key == 'S' || key == 's') { // Press s stop time-lapse
  696. record = false;
  697. }
  698. */
  699. }
  700. /////// SHOW HELP MENU ///////
  701. void showHelp(){
  702. fill(0, 0, 0, 90);
  703. noStroke();
  704. int cleft = (width/2) - (width/4);
  705. int ctop = (height/2) - (height/4);
  706. rect(cleft,ctop, width/2, height/2);
  707. stroke(0,255,0);
  708. fill(0,255,0);
  709. textSize(24);
  710. text("key: h --> this help" , cleft+ 10, ctop + 30);
  711. text("key: c --> openCV controls" , cleft+ 10, ctop + 70);
  712. text("key: 1 --> Tracking full screen" , cleft+ 10, ctop + 110);
  713. text("key: 0 --> toggle source image (in full screen)" , cleft+ 10, ctop + 150);
  714. text("key: i --> invert fx image" , cleft+ 10, ctop + 190);
  715. text("key: s --> save frame" , cleft+ 10, ctop + 230);
  716. text("key: ~ --> message console" , cleft+ 10, ctop + 270);
  717. }
  718. /////////////////////////////////////////
  719. // 8 LINES - BOTTOM SCREEN - CONSOLE
  720. /////////////////////////////////////////
  721. void showConsole(){
  722. fill(40, 40, 0, 200);
  723. noStroke();
  724. int ctop=height-200; // height - height/4;
  725. rect(0,ctop, width, height);
  726. stroke(0,255,0);
  727. fill(0,255,0);
  728. textSize(14);
  729. int cs=cons.length - 1;
  730. text(cons[0] , 10, ctop + 20);
  731. text(cons[1] , 10, ctop + 40);
  732. text(cons[2] , 10, ctop + 60);
  733. text(cons[3] , 10, ctop + 80);
  734. text(cons[4] , 10, ctop + 100);
  735. text(cons[5] , 10, ctop + 120);
  736. text(cons[6] , 10, ctop + 140);
  737. text(cons[7] , 10, ctop + 160);
  738. }
  739. //////////////////////////////////////////
  740. void cons(int cline, String mystring){
  741. // consindex++;
  742. // consindex=consindex % 8;
  743. consindex = cline -1;
  744. cons[consindex]= "> " + mystring;
  745. // println(cons[consindex]);
  746. // clear
  747. if(cline==0 || mystring=="clear"){
  748. for(int i=0; i<8;i++){
  749. cons[i] = ">> ";
  750. }
  751. }
  752. }
  753. ////////////////////////
  754. void printCameraList(){
  755. // print cameras list
  756. if (cameras.length == 0) {
  757. println("There are no cameras available for capture.");
  758. exit();
  759. } else {
  760. println("Available cameras:");
  761. for (int i = 0; i < cameras.length; i++) {
  762. println("index: " + i + " " + cameras[i]);
  763. }
  764. }
  765. }
  766. ////////////////////////
  767. void setCaptureSize(int n){
  768. blobSwitch = false;
  769. String mystring = cameras[n];
  770. int mybegin = mystring.indexOf("size=") + 5;
  771. int myend = mystring.indexOf(",fps");
  772. // println("mybegin: " + mybegin + " myend: " + myend);
  773. String tempstring=mystring.substring(mybegin, myend);
  774. // println("tempstring: " + tempstring);
  775. int xbegin = tempstring.indexOf("x");
  776. // println("x: " + xbegin);
  777. String stX=tempstring.substring(0, xbegin);
  778. String stY=tempstring.substring(xbegin+1,tempstring.length());
  779. capW = int(stX);
  780. capH = int(stY);
  781. println("capW: " + capW + " capH: " + capH);
  782. cons(6,"capW: " + capW + " capH: " + capH);
  783. // capW = 960;
  784. // capH = 540;
  785. video = new Capture(this, capW, capH, cameras[n]);
  786. video.start();
  787. scalefactor= float(width) / float(video.width);
  788. scaleX= float(width) / float(video.width);
  789. scaleY= float(height) / float(video.height);
  790. cons(8,"screen width: " + width + " video.width: " + video.width + " screen height: " + height + " video.height: " + video.height);
  791. cons(7,"scaleX: " + scaleX + " scaleY: " + scaleY);
  792. opencv = new OpenCV(this, capW, capH);
  793. blobSwitch = true;
  794. }
  795. //////////////////////////////
  796. int btime = -1;
  797. void btimer_reset() {
  798. btime = millis();
  799. }
  800. boolean btimer_passed(int seconds) {
  801. return ( millis() - btime > 1000 * seconds );
  802. }
  803. //////////////////////////////