1
+ /*
2
+ xtra_syphon
3
+ Images from any syphon source on the scope!
4
+ mouseX - threshold
5
+ mouseY - threshold distance
6
+
7
+ » Requires OpenCV for Processing + Syphon libraries
8
+
9
+ cc teddavis.org + jankenpopp.com 2017
10
+ */
11
+
12
+ // PREFS
13
+ int threshold = 138 ;
14
+ float thresholdDist = 43 ;
15
+ int cutoff = 91 ; // limit min size contour
16
+
17
+ // import and create instance of XYscope
18
+ import xyscope.* ;
19
+ XYscope xy;
20
+
21
+ // minim is required to generate audio
22
+ import ddf.minim.* ;
23
+
24
+ // syphon is required for passing imagery
25
+ import codeanticode.syphon.* ;
26
+ SyphonClient client;
27
+ PImage imgs; // syphon client
28
+ PImage imgo; // syphon resize
29
+ PImage imgf; // syphon threshold
30
+
31
+ // libs required for point sorting (efficient drawing)
32
+ import java.util.Collections ;
33
+ import java.util.Comparator ;
34
+
35
+ // opencv
36
+ import gab.opencv.* ;
37
+ import java.awt.* ;
38
+ OpenCV opencv;
39
+ ArrayList<Contour > contours;
40
+
41
+ void setup () {
42
+ size (512 , 512 , P3D );
43
+
44
+ // initialize XYscope with default/custom sound out
45
+ xy = new XYscope (this , " " );
46
+
47
+ // initialize syphon client
48
+ client = new SyphonClient (this );
49
+
50
+ // initialize OpenCV (used to convert syphon to single line)
51
+ opencv = new OpenCV (this , width , height );
52
+ }
53
+
54
+ void draw () {
55
+ background (0 );
56
+
57
+ // only up date when sypon sends new image
58
+ if (client. newFrame()) {
59
+ imgs = client. getImage(imgs);
60
+ }
61
+ if (imgs != null ) {
62
+ imgf = imgs. get();
63
+ if (imgf. width > imgf. height ) {
64
+ imgf. resize(width , 0 );
65
+ } else {
66
+ imgf. resize(0 , height );
67
+ }
68
+ imgo = imgf. get();
69
+ // clear waves like refreshing background
70
+ xy. clearWaves();
71
+
72
+ // adjust threshold of image for selective lines
73
+ if (mousePressed ) {
74
+ threshold = floor (map (mouseX , 0 , width , 0 , 255 ));
75
+ thresholdDist = map (mouseY , 0 , height , 0 , 255 - threshold);
76
+
77
+ // replace variable defaults at top if you find better ones
78
+ println (" threshold: " + threshold + " / thresholdDist: " + thresholdDist);
79
+ }
80
+
81
+ // convert syphon to high contrast threshold
82
+ for (int i= 0 ; i< imgf. width * imgf. height ; i++ ) {
83
+ if (brightness (imgf. pixels [i]) > threshold && brightness (imgf. pixels [i]) < threshold+ thresholdDist) {
84
+ imgf. pixels [i] = color (200 ); // White
85
+ } else {
86
+ imgf. pixels [i] = color (0 ); // Black
87
+ }
88
+ }
89
+
90
+ // process threshold to single line
91
+ opencv. loadImage(imgf);
92
+ opencv. dilate();
93
+ opencv. erode();
94
+
95
+ // display syphon original, threshold, opencv images – w/ keys 1, 2, 3
96
+ if (keyPressed ) {
97
+ if (key == ' 1' )
98
+ image (imgo, 0 , 0 );
99
+ if (key == ' 2' )
100
+ image (imgf, 0 , 0 );
101
+ if (key == ' 3' ) {
102
+ PImage otemp = opencv. getSnapshot();
103
+ image (otemp, 0 , 0 );
104
+ }
105
+ }
106
+
107
+ contours = opencv. findContours(true , false );
108
+
109
+ // sort group of lines for effeciant drawing
110
+ Collections . sort(contours, new MyComparator ());
111
+
112
+ // draw shapes on scope
113
+ for (Contour contour : contours) {
114
+ if (contours. size() > 0 ) {
115
+ contour. setPolygonApproximationFactor(1 );
116
+ if (contour. numPoints() > cutoff) {
117
+ xy. beginShape();
118
+ for (PVector point : contour. getPolygonApproximation(). getPoints()) {
119
+ xy. vertex(point. x, point. y);
120
+ }
121
+ xy. endShape();
122
+ }
123
+ }
124
+ }
125
+
126
+ // build audio from shapes
127
+ xy. buildWaves();
128
+ }
129
+ // draw XY analytics
130
+ xy. drawXY();
131
+ }
132
+
133
+ // used for sorting points
134
+ class MyComparator implements Comparator<Contour > {
135
+ @Override
136
+ public int compare (Contour o1 , Contour o2 ) {
137
+ if (o1. numPoints() > o2. numPoints()) {
138
+ return - 1 ;
139
+ } else if (o1. numPoints() < o2. numPoints()) {
140
+ return 1 ;
141
+ }
142
+ return 0 ;
143
+ }
144
+ }
0 commit comments