Calibrate works?
@ -2,12 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="6e752a8c-6cb9-4ef9-9031-0329ce15fcb4" name="Default" comment="">
|
<list default="true" id="6e752a8c-6cb9-4ef9-9031-0329ce15fcb4" name="Default" comment="">
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/compiler.xml" afterPath="$PROJECT_DIR$/.idea/compiler.xml" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/Camera.java" afterPath="$PROJECT_DIR$/src/Camera.java" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/EuglenaApplet.java" afterPath="$PROJECT_DIR$/src/EuglenaApplet.java" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/LEDControl.java" afterPath="$PROJECT_DIR$/src/LEDControl.java" />
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/LEDControl.java" afterPath="$PROJECT_DIR$/src/LEDControl.java" />
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/ProjectorApplet.java" afterPath="$PROJECT_DIR$/src/ProjectorApplet.java" />
|
|
||||||
</list>
|
</list>
|
||||||
<ignored path="processing-intellij.iws" />
|
<ignored path="processing-intellij.iws" />
|
||||||
<ignored path=".idea/workspace.xml" />
|
<ignored path=".idea/workspace.xml" />
|
||||||
@ -31,8 +26,8 @@
|
|||||||
<file leaf-file-name="euglena_basic_stimuli.java" pinned="false" current-in-tab="true">
|
<file leaf-file-name="euglena_basic_stimuli.java" pinned="false" current-in-tab="true">
|
||||||
<entry file="file://$PROJECT_DIR$/src/euglena_basic_stimuli.java">
|
<entry file="file://$PROJECT_DIR$/src/euglena_basic_stimuli.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="759">
|
<state relative-caret-position="489">
|
||||||
<caret line="85" column="29" selection-start-line="85" selection-start-column="29" selection-end-line="85" selection-end-column="29" />
|
<caret line="325" column="0" selection-start-line="325" selection-start-column="0" selection-end-line="325" selection-end-column="0" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#0#16478#0" expanded="true" />
|
<element signature="e#0#16478#0" expanded="true" />
|
||||||
<element signature="imports" expanded="true" />
|
<element signature="imports" expanded="true" />
|
||||||
@ -55,8 +50,8 @@
|
|||||||
<file leaf-file-name="EuglenaApplet.java" pinned="false" current-in-tab="false">
|
<file leaf-file-name="EuglenaApplet.java" pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/src/EuglenaApplet.java">
|
<entry file="file://$PROJECT_DIR$/src/EuglenaApplet.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="540">
|
<state relative-caret-position="504">
|
||||||
<caret line="41" column="13" selection-start-line="41" selection-start-column="13" selection-end-line="41" selection-end-column="13" />
|
<caret line="39" column="5" selection-start-line="39" selection-start-column="5" selection-end-line="39" selection-end-column="5" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#349#350#0" expanded="true" />
|
<element signature="e#349#350#0" expanded="true" />
|
||||||
<element signature="e#394#395#0" expanded="true" />
|
<element signature="e#394#395#0" expanded="true" />
|
||||||
@ -70,8 +65,8 @@
|
|||||||
<file leaf-file-name="ProjectorApplet.java" pinned="false" current-in-tab="false">
|
<file leaf-file-name="ProjectorApplet.java" pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/src/ProjectorApplet.java">
|
<entry file="file://$PROJECT_DIR$/src/ProjectorApplet.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="630">
|
<state relative-caret-position="594">
|
||||||
<caret line="35" column="0" selection-start-line="35" selection-start-column="0" selection-end-line="35" selection-end-column="0" />
|
<caret line="33" column="18" selection-start-line="33" selection-start-column="8" selection-end-line="33" selection-end-column="18" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#394#395#0" expanded="true" />
|
<element signature="e#394#395#0" expanded="true" />
|
||||||
<element signature="e#453#454#0" expanded="true" />
|
<element signature="e#453#454#0" expanded="true" />
|
||||||
@ -91,18 +86,18 @@
|
|||||||
<file leaf-file-name="LEDControl.java" pinned="false" current-in-tab="false">
|
<file leaf-file-name="LEDControl.java" pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/src/LEDControl.java">
|
<entry file="file://$PROJECT_DIR$/src/LEDControl.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="576">
|
<state relative-caret-position="378">
|
||||||
<caret line="35" column="33" selection-start-line="35" selection-start-column="24" selection-end-line="35" selection-end-column="33" />
|
<caret line="22" column="0" selection-start-line="22" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
|
||||||
<folding />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
</file>
|
</file>
|
||||||
<file leaf-file-name="Camera.java" pinned="false" current-in-tab="true">
|
<file leaf-file-name="Camera.java" pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/src/Camera.java">
|
<entry file="file://$PROJECT_DIR$/src/Camera.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="144">
|
<state relative-caret-position="396">
|
||||||
<caret line="8" column="6" selection-start-line="8" selection-start-column="6" selection-end-line="8" selection-end-column="6" />
|
<caret line="22" column="49" selection-start-line="22" selection-start-column="49" selection-end-line="22" selection-end-column="49" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="imports" expanded="true" />
|
<element signature="imports" expanded="true" />
|
||||||
<element signature="e#1015#1016#0" expanded="true" />
|
<element signature="e#1015#1016#0" expanded="true" />
|
||||||
@ -115,8 +110,8 @@
|
|||||||
<file leaf-file-name="Menu.java" pinned="false" current-in-tab="false">
|
<file leaf-file-name="Menu.java" pinned="false" current-in-tab="false">
|
||||||
<entry file="file://$PROJECT_DIR$/src/Menu.java">
|
<entry file="file://$PROJECT_DIR$/src/Menu.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="198">
|
<state relative-caret-position="342">
|
||||||
<caret line="20" column="63" selection-start-line="20" selection-start-column="63" selection-end-line="20" selection-end-column="63" />
|
<caret line="188" column="2" selection-start-line="188" selection-start-column="2" selection-end-line="188" selection-end-column="2" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="imports" expanded="true" />
|
<element signature="imports" expanded="true" />
|
||||||
</folding>
|
</folding>
|
||||||
@ -124,13 +119,13 @@
|
|||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
</file>
|
</file>
|
||||||
<file leaf-file-name="Calibrator.java" pinned="false" current-in-tab="false">
|
<file leaf-file-name="Calibrator.java" pinned="false" current-in-tab="true">
|
||||||
<entry file="file://$PROJECT_DIR$/src/Calibrator.java">
|
<entry file="file://$PROJECT_DIR$/src/Calibrator.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="318">
|
<state relative-caret-position="18">
|
||||||
<caret line="38" column="0" selection-start-line="38" selection-start-column="0" selection-end-line="38" selection-end-column="0" />
|
<caret line="28" column="20" selection-start-line="28" selection-start-column="20" selection-end-line="28" selection-end-column="20" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#0#3795#0" expanded="true" />
|
<element signature="e#0#3796#0" expanded="true" />
|
||||||
</folding>
|
</folding>
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
@ -167,10 +162,10 @@
|
|||||||
<option value="$PROJECT_DIR$/src/EllipseClass.java" />
|
<option value="$PROJECT_DIR$/src/EllipseClass.java" />
|
||||||
<option value="$PROJECT_DIR$/src/RectangleClass.java" />
|
<option value="$PROJECT_DIR$/src/RectangleClass.java" />
|
||||||
<option value="$PROJECT_DIR$/src/EuglenaApplet.java" />
|
<option value="$PROJECT_DIR$/src/EuglenaApplet.java" />
|
||||||
<option value="$PROJECT_DIR$/src/Calibrator.java" />
|
|
||||||
<option value="$PROJECT_DIR$/src/LEDControl.java" />
|
|
||||||
<option value="$PROJECT_DIR$/lib/core.jar!/processing/core/PApplet.class" />
|
<option value="$PROJECT_DIR$/lib/core.jar!/processing/core/PApplet.class" />
|
||||||
<option value="$PROJECT_DIR$/src/ProjectorApplet.java" />
|
<option value="$PROJECT_DIR$/src/ProjectorApplet.java" />
|
||||||
|
<option value="$PROJECT_DIR$/src/LEDControl.java" />
|
||||||
|
<option value="$PROJECT_DIR$/src/Calibrator.java" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
@ -610,17 +605,6 @@
|
|||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/src/euglena_basic_stimuli.java">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="759">
|
|
||||||
<caret line="85" column="29" selection-start-line="85" selection-start-column="29" selection-end-line="85" selection-end-column="29" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#16478#0" expanded="true" />
|
|
||||||
<element signature="imports" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="jar://$PROJECT_DIR$/lib/core.jar!/processing/core/PApplet.class">
|
<entry file="jar://$PROJECT_DIR$/lib/core.jar!/processing/core/PApplet.class">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="94216">
|
<state relative-caret-position="94216">
|
||||||
@ -629,30 +613,10 @@
|
|||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/src/Calibrator.java">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="318">
|
|
||||||
<caret line="38" column="0" selection-start-line="38" selection-start-column="0" selection-end-line="38" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#3795#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/Menu.java">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="198">
|
|
||||||
<caret line="20" column="63" selection-start-line="20" selection-start-column="63" selection-end-line="20" selection-end-column="63" />
|
|
||||||
<folding>
|
|
||||||
<element signature="imports" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/EuglenaApplet.java">
|
<entry file="file://$PROJECT_DIR$/src/EuglenaApplet.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="540">
|
<state relative-caret-position="504">
|
||||||
<caret line="41" column="13" selection-start-line="41" selection-start-column="13" selection-end-line="41" selection-end-column="13" />
|
<caret line="39" column="5" selection-start-line="39" selection-start-column="5" selection-end-line="39" selection-end-column="5" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#349#350#0" expanded="true" />
|
<element signature="e#349#350#0" expanded="true" />
|
||||||
<element signature="e#394#395#0" expanded="true" />
|
<element signature="e#394#395#0" expanded="true" />
|
||||||
@ -664,8 +628,8 @@
|
|||||||
</entry>
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/src/ProjectorApplet.java">
|
<entry file="file://$PROJECT_DIR$/src/ProjectorApplet.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="630">
|
<state relative-caret-position="594">
|
||||||
<caret line="35" column="0" selection-start-line="35" selection-start-column="0" selection-end-line="35" selection-end-column="0" />
|
<caret line="33" column="18" selection-start-line="33" selection-start-column="8" selection-end-line="33" selection-end-column="18" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="e#394#395#0" expanded="true" />
|
<element signature="e#394#395#0" expanded="true" />
|
||||||
<element signature="e#453#454#0" expanded="true" />
|
<element signature="e#453#454#0" expanded="true" />
|
||||||
@ -681,18 +645,39 @@
|
|||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/euglena_basic_stimuli.java">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="489">
|
||||||
|
<caret line="325" column="0" selection-start-line="325" selection-start-column="0" selection-end-line="325" selection-end-column="0" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#16478#0" expanded="true" />
|
||||||
|
<element signature="imports" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/src/LEDControl.java">
|
<entry file="file://$PROJECT_DIR$/src/LEDControl.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="576">
|
<state relative-caret-position="378">
|
||||||
<caret line="35" column="33" selection-start-line="35" selection-start-column="24" selection-end-line="35" selection-end-column="33" />
|
<caret line="22" column="0" selection-start-line="22" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
|
||||||
<folding />
|
<folding />
|
||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/Menu.java">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="342">
|
||||||
|
<caret line="188" column="2" selection-start-line="188" selection-start-column="2" selection-end-line="188" selection-end-column="2" />
|
||||||
|
<folding>
|
||||||
|
<element signature="imports" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
<entry file="file://$PROJECT_DIR$/src/Camera.java">
|
<entry file="file://$PROJECT_DIR$/src/Camera.java">
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
<state relative-caret-position="144">
|
<state relative-caret-position="396">
|
||||||
<caret line="8" column="6" selection-start-line="8" selection-start-column="6" selection-end-line="8" selection-end-column="6" />
|
<caret line="22" column="49" selection-start-line="22" selection-start-column="49" selection-end-line="22" selection-end-column="49" />
|
||||||
<folding>
|
<folding>
|
||||||
<element signature="imports" expanded="true" />
|
<element signature="imports" expanded="true" />
|
||||||
<element signature="e#1015#1016#0" expanded="true" />
|
<element signature="e#1015#1016#0" expanded="true" />
|
||||||
@ -701,6 +686,16 @@
|
|||||||
</state>
|
</state>
|
||||||
</provider>
|
</provider>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/Calibrator.java">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="18">
|
||||||
|
<caret line="28" column="20" selection-start-line="28" selection-start-column="20" selection-end-line="28" selection-end-column="20" />
|
||||||
|
<folding>
|
||||||
|
<element signature="e#0#3796#0" expanded="true" />
|
||||||
|
</folding>
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
</component>
|
</component>
|
||||||
<component name="masterDetails">
|
<component name="masterDetails">
|
||||||
<states>
|
<states>
|
||||||
|
BIN
lib/arduino.jar
Normal file
BIN
lib/controlP5.jar
Normal file
7
lib/opencv_processing/data/README
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
the data folder:
|
||||||
|
If your library is using files like images, sound files,
|
||||||
|
any data file, etc., put them into the data folder.
|
||||||
|
When coding your library you can use processing's internal loading
|
||||||
|
functions like loadImage(), loadStrings(), etc. to load files
|
||||||
|
located inside the data folder into your library.
|
||||||
|
|
@ -0,0 +1,37 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
import processing.video.*;
|
||||||
|
|
||||||
|
Movie video;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(720, 480);
|
||||||
|
video = new Movie(this, "street.mov");
|
||||||
|
opencv = new OpenCV(this, 720, 480);
|
||||||
|
|
||||||
|
opencv.startBackgroundSubtraction(5, 3, 0.5);
|
||||||
|
|
||||||
|
video.loop();
|
||||||
|
video.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(video, 0, 0);
|
||||||
|
opencv.loadImage(video);
|
||||||
|
|
||||||
|
opencv.updateBackground();
|
||||||
|
|
||||||
|
opencv.dilate();
|
||||||
|
opencv.erode();
|
||||||
|
|
||||||
|
noFill();
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
strokeWeight(3);
|
||||||
|
for (Contour contour : opencv.findContours()) {
|
||||||
|
contour.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void movieEvent(Movie m) {
|
||||||
|
m.read();
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
PImage src = loadImage("robot_light.jpg");
|
||||||
|
src.resize(800, 0);
|
||||||
|
size(src.width, src.height);
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(opencv.getOutput(), 0, 0);
|
||||||
|
PVector loc = opencv.max();
|
||||||
|
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
strokeWeight(4);
|
||||||
|
noFill();
|
||||||
|
ellipse(loc.x, loc.y, 10, 10);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/BrightestPoint/robot_light.jpg
Normal file
After Width: | Height: | Size: 205 KiB |
@ -0,0 +1,17 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
PImage img;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
img = loadImage("test.jpg");
|
||||||
|
size(img.width, img.height);
|
||||||
|
opencv = new OpenCV(this, img);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(){
|
||||||
|
opencv.loadImage(img);
|
||||||
|
opencv.brightness((int)map(mouseX, 0, width, -255, 255));
|
||||||
|
image(opencv.getOutput(),0,0);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/BrightnessContrast/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
@ -0,0 +1,25 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
PImage src;
|
||||||
|
ArrayList<PVector> cornerPoints;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
src = loadImage("checkerboard.jpg");
|
||||||
|
src.resize(500, 0);
|
||||||
|
size(src.width, src.height);
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
opencv.gray();
|
||||||
|
|
||||||
|
cornerPoints = opencv.findChessboardCorners(9,6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image( opencv.getOutput(), 0, 0);
|
||||||
|
fill(255,0,0);
|
||||||
|
noStroke();
|
||||||
|
for(PVector p : cornerPoints){
|
||||||
|
ellipse(p.x, p.y, 5, 5);
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 115 KiB |
@ -0,0 +1,46 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage src, r, g, b, h, s, v;
|
||||||
|
|
||||||
|
int imgH, imgW;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
src = loadImage("green_object.png");
|
||||||
|
src.resize(800,0);
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
size(int(opencv.width*1.5), int(opencv.height * 1.5));
|
||||||
|
|
||||||
|
imgH = src.height/2;
|
||||||
|
imgW = src.width/2;
|
||||||
|
|
||||||
|
r = opencv.getSnapshot(opencv.getR());
|
||||||
|
g = opencv.getSnapshot(opencv.getG());
|
||||||
|
b = opencv.getSnapshot(opencv.getB());
|
||||||
|
|
||||||
|
opencv.useColor(HSB);
|
||||||
|
|
||||||
|
h = opencv.getSnapshot(opencv.getH());
|
||||||
|
s = opencv.getSnapshot(opencv.getS());
|
||||||
|
v = opencv.getSnapshot(opencv.getV());
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
background(0);
|
||||||
|
noTint();
|
||||||
|
image(src, imgW,0, imgW, imgH);
|
||||||
|
|
||||||
|
tint(255,0,0);
|
||||||
|
image(r, 0, imgH, imgW, imgH);
|
||||||
|
|
||||||
|
tint(0,255,0);
|
||||||
|
image(g, imgW, imgH, imgW, imgH);
|
||||||
|
|
||||||
|
tint(0,0,255);
|
||||||
|
image(b, 2*imgW, imgH, imgW, imgH);
|
||||||
|
|
||||||
|
noTint();
|
||||||
|
image(h, 0, 2*imgH, imgW, imgH);
|
||||||
|
image(s, imgW, 2*imgH, imgW, imgH);
|
||||||
|
image(v, 2*imgW, 2*imgH, imgW, imgH);
|
||||||
|
}
|
BIN
lib/opencv_processing/examples/ColorChannels/green_object.png
Normal file
After Width: | Height: | Size: 3.2 MiB |
@ -0,0 +1,58 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.calib3d.StereoBM;
|
||||||
|
import org.opencv.core.CvType;
|
||||||
|
import org.opencv.calib3d.StereoSGBM;
|
||||||
|
|
||||||
|
OpenCV ocvL, ocvR;
|
||||||
|
PImage imgL, imgR, depth1, depth2;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
imgL = loadImage("scene_l.jpg");
|
||||||
|
imgR = loadImage("scene_r.jpg");
|
||||||
|
ocvL = new OpenCV(this, imgL);
|
||||||
|
|
||||||
|
ocvR = new OpenCV(this, imgR);
|
||||||
|
|
||||||
|
size(ocvL.width * 2, ocvL.height*2);
|
||||||
|
|
||||||
|
ocvL.gray();
|
||||||
|
ocvR.gray();
|
||||||
|
Mat left = ocvL.getGray();
|
||||||
|
Mat right = ocvR.getGray();
|
||||||
|
|
||||||
|
Mat disparity = OpenCV.imitate(left);
|
||||||
|
|
||||||
|
StereoSGBM stereo = new StereoSGBM(0, 32, 3, 128, 256, 20, 16, 1, 100, 20, true);
|
||||||
|
stereo.compute(left, right, disparity );
|
||||||
|
|
||||||
|
Mat depthMat = OpenCV.imitate(left);
|
||||||
|
disparity.convertTo(depthMat, depthMat.type());
|
||||||
|
|
||||||
|
depth1 = createImage(depthMat.width(), depthMat.height(), RGB);
|
||||||
|
ocvL.toPImage(depthMat, depth1);
|
||||||
|
|
||||||
|
StereoBM stereo2 = new StereoBM();
|
||||||
|
stereo2.compute(left, right, disparity );
|
||||||
|
disparity.convertTo(depthMat, depthMat.type());
|
||||||
|
|
||||||
|
|
||||||
|
depth2 = createImage(depthMat.width(), depthMat.height(), RGB);
|
||||||
|
ocvL.toPImage(depthMat, depth2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(imgL, 0, 0);
|
||||||
|
image(imgR, imgL.width, 0);
|
||||||
|
|
||||||
|
image(depth1, 0, imgL.height);
|
||||||
|
image(depth2, imgL.width, imgL.height);
|
||||||
|
|
||||||
|
fill(255, 0, 0);
|
||||||
|
text("left", 10, 20);
|
||||||
|
text("right", 10 + imgL.width, 20);
|
||||||
|
text("stereo SGBM", 10, imgL.height + 20);
|
||||||
|
text("stereo BM", 10 + imgL.width, imgL.height+ 20);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/DepthFromStereo/scene_l.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
lib/opencv_processing/examples/DepthFromStereo/scene_r.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
@ -0,0 +1,51 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
PImage src, dilated, eroded, both;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
src = loadImage("pen_sketch.jpg");
|
||||||
|
src.resize(src.width/2, 0);
|
||||||
|
size(src.width*2, src.height*2);
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
|
||||||
|
// Dilate and Erode both need a binary image
|
||||||
|
// So, we'll make it gray and threshold it.
|
||||||
|
opencv.gray();
|
||||||
|
opencv.threshold(100);
|
||||||
|
// We'll also invert so that erosion eats away the lines
|
||||||
|
// and dilation expands them (rather than vice-versa)
|
||||||
|
opencv.invert();
|
||||||
|
// save a snapshot to use in both operations
|
||||||
|
src = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// erode and save snapshot for display
|
||||||
|
opencv.erode();
|
||||||
|
eroded = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// reload un-eroded image and dilate it
|
||||||
|
opencv.loadImage(src);
|
||||||
|
opencv.dilate();
|
||||||
|
// save dilated version for display
|
||||||
|
dilated = opencv.getSnapshot();
|
||||||
|
// now erode on top of dilated version to close holes
|
||||||
|
opencv.erode();
|
||||||
|
both = opencv.getSnapshot();
|
||||||
|
|
||||||
|
noLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(src, 0, 0);
|
||||||
|
image(eroded, src.width, 0);
|
||||||
|
image(dilated, 0, src.height);
|
||||||
|
image(both, src.width, src.height);
|
||||||
|
|
||||||
|
fill(0, 255, 0);
|
||||||
|
text("original", 20, 20);
|
||||||
|
text("erode", src.width + 20, 20);
|
||||||
|
text("dilate", 20, src.height+20);
|
||||||
|
text("dilate then erode\n(close holes)", src.width+20, src.height+20);
|
||||||
|
}
|
||||||
|
|
After Width: | Height: | Size: 191 KiB |
BIN
lib/opencv_processing/examples/DilationAndErosion/pen_sketch.jpg
Normal file
After Width: | Height: | Size: 62 KiB |
@ -0,0 +1,25 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
Rectangle[] faces;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
opencv = new OpenCV(this, "test.jpg");
|
||||||
|
size(opencv.width, opencv.height);
|
||||||
|
|
||||||
|
opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
|
||||||
|
faces = opencv.detect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(opencv.getInput(), 0, 0);
|
||||||
|
|
||||||
|
noFill();
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
strokeWeight(3);
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/FaceDetection/data/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
lib/opencv_processing/examples/FaceDetection/data/test.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
lib/opencv_processing/examples/FaceDetection/data/testImage.png
Normal file
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 4.5 KiB |
40
lib/opencv_processing/examples/FilterImages/FilterImages.pde
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage img, thresh, blur, adaptive;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
img = loadImage("test.jpg");
|
||||||
|
size(img.width, img.height);
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, img);
|
||||||
|
PImage gray = opencv.getSnapshot();
|
||||||
|
|
||||||
|
opencv.threshold(80);
|
||||||
|
thresh = opencv.getSnapshot();
|
||||||
|
|
||||||
|
opencv.loadImage(gray);
|
||||||
|
opencv.blur(12);
|
||||||
|
blur = opencv.getSnapshot();
|
||||||
|
|
||||||
|
opencv.loadImage(gray);
|
||||||
|
opencv.adaptiveThreshold(591, 1);
|
||||||
|
adaptive = opencv.getSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
image(img, 0, 0);
|
||||||
|
image(thresh, img.width, 0);
|
||||||
|
image(blur, 0, img.height);
|
||||||
|
image(adaptive, img.width, img.height);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
fill(0);
|
||||||
|
text("source", img.width/2 - 100, 20 );
|
||||||
|
text("threshold", img.width - 100, 20 );
|
||||||
|
text("blur", img.width/2 - 100, img.height/2 + 20 );
|
||||||
|
text("adaptive threshold", img.width - 150, img.height/2 + 20 );
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/FilterImages/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
42
lib/opencv_processing/examples/FindContours/FindContours.pde
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
PImage src, dst;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
ArrayList<Contour> contours;
|
||||||
|
ArrayList<Contour> polygons;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
src = loadImage("test.jpg");
|
||||||
|
size(src.width, src.height/2);
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
|
||||||
|
opencv.gray();
|
||||||
|
opencv.threshold(70);
|
||||||
|
dst = opencv.getOutput();
|
||||||
|
|
||||||
|
contours = opencv.findContours();
|
||||||
|
println("found " + contours.size() + " contours");
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
scale(0.5);
|
||||||
|
image(src, 0, 0);
|
||||||
|
image(dst, src.width, 0);
|
||||||
|
|
||||||
|
noFill();
|
||||||
|
strokeWeight(3);
|
||||||
|
|
||||||
|
for (Contour contour : contours) {
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
contour.draw();
|
||||||
|
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
beginShape();
|
||||||
|
for (PVector point : contour.getPolygonApproximation().getPoints()) {
|
||||||
|
vertex(point.x, point.y);
|
||||||
|
}
|
||||||
|
endShape();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/FindContours/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
38
lib/opencv_processing/examples/FindEdges/FindEdges.pde
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage src, canny, scharr, sobel;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
src = loadImage("test.jpg");
|
||||||
|
size(src.width, src.height);
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
opencv.findCannyEdges(20,75);
|
||||||
|
canny = opencv.getSnapshot();
|
||||||
|
|
||||||
|
opencv.loadImage(src);
|
||||||
|
opencv.findScharrEdges(OpenCV.HORIZONTAL);
|
||||||
|
scharr = opencv.getSnapshot();
|
||||||
|
|
||||||
|
opencv.loadImage(src);
|
||||||
|
opencv.findSobelEdges(1,0);
|
||||||
|
sobel = opencv.getSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
image(src, 0, 0);
|
||||||
|
image(canny, src.width, 0);
|
||||||
|
image(scharr, 0, src.height);
|
||||||
|
image(sobel, src.width, src.height);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
text("Source", 10, 25);
|
||||||
|
text("Canny", src.width/2 + 10, 25);
|
||||||
|
text("Scharr", 10, src.height/2 + 25);
|
||||||
|
text("Sobel", src.width/2 + 10, src.height/2 + 25);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/FindEdges/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
@ -0,0 +1,47 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
Histogram grayHist, rHist, gHist, bHist;
|
||||||
|
|
||||||
|
PImage img;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(640, 400);
|
||||||
|
img = loadImage("test.jpg");
|
||||||
|
opencv = new OpenCV(this, img);
|
||||||
|
|
||||||
|
grayHist = opencv.findHistogram(opencv.getGray(), 256);
|
||||||
|
rHist = opencv.findHistogram(opencv.getR(), 256);
|
||||||
|
gHist = opencv.findHistogram(opencv.getG(), 256);
|
||||||
|
bHist = opencv.findHistogram(opencv.getB(), 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
background(0);
|
||||||
|
image(img, 10, 0, 300, 200);
|
||||||
|
|
||||||
|
stroke(125); noFill();
|
||||||
|
rect(320, 10, 310, 180);
|
||||||
|
|
||||||
|
fill(125); noStroke();
|
||||||
|
grayHist.draw(320, 10, 310, 180);
|
||||||
|
|
||||||
|
stroke(255, 0, 0); noFill();
|
||||||
|
rect(10, height - 190, 200, 180);
|
||||||
|
|
||||||
|
fill(255, 0, 0); noStroke();
|
||||||
|
rHist.draw(10, height - 190, 200, 180);
|
||||||
|
|
||||||
|
stroke(0, 255, 0); noFill();
|
||||||
|
rect(220, height - 190, 200, 180);
|
||||||
|
|
||||||
|
fill(0, 255, 0); noStroke();
|
||||||
|
gHist.draw(220, height - 190, 200, 180);
|
||||||
|
|
||||||
|
stroke(0, 0, 255); noFill();
|
||||||
|
rect(430, height - 190, 200, 180);
|
||||||
|
|
||||||
|
fill(0, 0, 255); noStroke();
|
||||||
|
bHist.draw(430, height - 190, 200, 180);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/FindHistogram/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* HSVColorTracking
|
||||||
|
* Greg Borenstein
|
||||||
|
* https://github.com/atduskgreg/opencv-processing-book/blob/master/code/hsv_color_tracking/HSVColorTracking/HSVColorTracking.pde
|
||||||
|
*
|
||||||
|
* Modified by Jordi Tost @jorditost (color selection)
|
||||||
|
*
|
||||||
|
* University of Applied Sciences Potsdam, 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
import gab.opencv.*;
|
||||||
|
import processing.video.*;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
|
||||||
|
Capture video;
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage src, colorFilteredImage;
|
||||||
|
ArrayList<Contour> contours;
|
||||||
|
|
||||||
|
// <1> Set the range of Hue values for our filter
|
||||||
|
int rangeLow = 20;
|
||||||
|
int rangeHigh = 35;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
video = new Capture(this, 640, 480);
|
||||||
|
video.start();
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, video.width, video.height);
|
||||||
|
contours = new ArrayList<Contour>();
|
||||||
|
|
||||||
|
size(2*opencv.width, opencv.height, P2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
|
||||||
|
// Read last captured frame
|
||||||
|
if (video.available()) {
|
||||||
|
video.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <2> Load the new frame of our movie in to OpenCV
|
||||||
|
opencv.loadImage(video);
|
||||||
|
|
||||||
|
// Tell OpenCV to use color information
|
||||||
|
opencv.useColor();
|
||||||
|
src = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// <3> Tell OpenCV to work in HSV color space.
|
||||||
|
opencv.useColor(HSB);
|
||||||
|
|
||||||
|
// <4> Copy the Hue channel of our image into
|
||||||
|
// the gray channel, which we process.
|
||||||
|
opencv.setGray(opencv.getH().clone());
|
||||||
|
|
||||||
|
// <5> Filter the image based on the range of
|
||||||
|
// hue values that match the object we want to track.
|
||||||
|
opencv.inRange(rangeLow, rangeHigh);
|
||||||
|
|
||||||
|
// <6> Get the processed image for reference.
|
||||||
|
colorFilteredImage = opencv.getSnapshot();
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// We could process our image here!
|
||||||
|
// See ImageFiltering.pde
|
||||||
|
///////////////////////////////////////////
|
||||||
|
|
||||||
|
// <7> Find contours in our range image.
|
||||||
|
// Passing 'true' sorts them by descending area.
|
||||||
|
contours = opencv.findContours(true, true);
|
||||||
|
|
||||||
|
// <8> Display background images
|
||||||
|
image(src, 0, 0);
|
||||||
|
image(colorFilteredImage, src.width, 0);
|
||||||
|
|
||||||
|
// <9> Check to make sure we've found any contours
|
||||||
|
if (contours.size() > 0) {
|
||||||
|
// <9> Get the first contour, which will be the largest one
|
||||||
|
Contour biggestContour = contours.get(0);
|
||||||
|
|
||||||
|
// <10> Find the bounding box of the largest contour,
|
||||||
|
// and hence our object.
|
||||||
|
Rectangle r = biggestContour.getBoundingBox();
|
||||||
|
|
||||||
|
// <11> Draw the bounding box of our object
|
||||||
|
noFill();
|
||||||
|
strokeWeight(2);
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
rect(r.x, r.y, r.width, r.height);
|
||||||
|
|
||||||
|
// <12> Draw a dot in the middle of the bounding box, on the object.
|
||||||
|
noStroke();
|
||||||
|
fill(255, 0, 0);
|
||||||
|
ellipse(r.x + r.width/2, r.y + r.height/2, 30, 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousePressed() {
|
||||||
|
|
||||||
|
color c = get(mouseX, mouseY);
|
||||||
|
println("r: " + red(c) + " g: " + green(c) + " b: " + blue(c));
|
||||||
|
|
||||||
|
int hue = int(map(hue(c), 0, 255, 0, 180));
|
||||||
|
println("hue to detect: " + hue);
|
||||||
|
|
||||||
|
rangeLow = hue - 5;
|
||||||
|
rangeHigh = hue + 5;
|
||||||
|
}
|
After Width: | Height: | Size: 596 KiB |
@ -0,0 +1,61 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
import org.opencv.core.Core;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.Size;
|
||||||
|
import org.opencv.core.Point;
|
||||||
|
import org.opencv.core.Scalar;
|
||||||
|
import org.opencv.core.CvType;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage src,dst, hist, histMask;
|
||||||
|
|
||||||
|
Mat skinHistogram;
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
src = loadImage("test.jpg");
|
||||||
|
src.resize(src.width/2, 0);
|
||||||
|
size(src.width*2 + 256, src.height);
|
||||||
|
// third argument is: useColor
|
||||||
|
opencv = new OpenCV(this, src, true);
|
||||||
|
|
||||||
|
skinHistogram = Mat.zeros(256, 256, CvType.CV_8UC1);
|
||||||
|
Core.ellipse(skinHistogram, new Point(113.0, 155.6), new Size(40.0, 25.2), 43.0, 0.0, 360.0, new Scalar(255, 255, 255), Core.FILLED);
|
||||||
|
|
||||||
|
histMask = createImage(256,256, ARGB);
|
||||||
|
opencv.toPImage(skinHistogram, histMask);
|
||||||
|
hist = loadImage("cb-cr.png");
|
||||||
|
hist.blend(histMask, 0,0,256,256,0,0,256,256, ADD);
|
||||||
|
|
||||||
|
dst = opencv.getOutput();
|
||||||
|
dst.loadPixels();
|
||||||
|
|
||||||
|
for(int i = 0; i < dst.pixels.length; i++){
|
||||||
|
|
||||||
|
Mat input = new Mat(new Size(1, 1), CvType.CV_8UC3);
|
||||||
|
input.setTo(colorToScalar(dst.pixels[i]));
|
||||||
|
Mat output = opencv.imitate(input);
|
||||||
|
Imgproc.cvtColor(input, output, Imgproc.COLOR_BGR2YCrCb );
|
||||||
|
double[] inputComponents = output.get(0,0);
|
||||||
|
if(skinHistogram.get((int)inputComponents[1], (int)inputComponents[2])[0] > 0){
|
||||||
|
dst.pixels[i] = color(255);
|
||||||
|
} else {
|
||||||
|
dst.pixels[i] = color(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.updatePixels();
|
||||||
|
}
|
||||||
|
|
||||||
|
// in BGR
|
||||||
|
Scalar colorToScalar(color c){
|
||||||
|
return new Scalar(blue(c), green(c), red(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void draw(){
|
||||||
|
image(src,0,0);
|
||||||
|
image(dst, src.width, 0);
|
||||||
|
image(hist, src.width*2, 0);
|
||||||
|
}
|
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 100 KiB |
@ -0,0 +1,38 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
ArrayList<Line> lines;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
PImage src = loadImage("film_scan.jpg");
|
||||||
|
src.resize(0, 800);
|
||||||
|
size(src.width, src.height);
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
opencv.findCannyEdges(20, 75);
|
||||||
|
|
||||||
|
// Find lines with Hough line detection
|
||||||
|
// Arguments are: threshold, minLengthLength, maxLineGap
|
||||||
|
lines = opencv.findLines(100, 30, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(opencv.getOutput(), 0, 0);
|
||||||
|
strokeWeight(3);
|
||||||
|
|
||||||
|
for (Line line : lines) {
|
||||||
|
// lines include angle in radians, measured in double precision
|
||||||
|
// so we can select out vertical and horizontal lines
|
||||||
|
// They also include "start" and "end" PVectors with the position
|
||||||
|
if (line.angle >= radians(0) && line.angle < radians(1)) {
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
line(line.start.x, line.start.y, line.end.x, line.end.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.angle > radians(89) && line.angle < radians(91)) {
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
line(line.start.x, line.start.y, line.end.x, line.end.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/HoughLineDetection/film_scan.jpg
Normal file
After Width: | Height: | Size: 1.9 MiB |
@ -0,0 +1,64 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
PImage img;
|
||||||
|
OpenCV opencv;
|
||||||
|
Histogram histogram;
|
||||||
|
|
||||||
|
int lowerb = 50;
|
||||||
|
int upperb = 100;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
img = loadImage("colored_balls.jpg");
|
||||||
|
opencv = new OpenCV(this, img);
|
||||||
|
size(opencv.width, opencv.height);
|
||||||
|
opencv.useColor(HSB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
opencv.loadImage(img);
|
||||||
|
|
||||||
|
image(img, 0, 0);
|
||||||
|
|
||||||
|
opencv.setGray(opencv.getH().clone());
|
||||||
|
opencv.inRange(lowerb, upperb);
|
||||||
|
histogram = opencv.findHistogram(opencv.getH(), 255);
|
||||||
|
|
||||||
|
image(opencv.getOutput(), 3*width/4, 3*height/4, width/4,height/4);
|
||||||
|
|
||||||
|
noStroke(); fill(0);
|
||||||
|
histogram.draw(10, height - 230, 400, 200);
|
||||||
|
noFill(); stroke(0);
|
||||||
|
line(10, height-30, 410, height-30);
|
||||||
|
|
||||||
|
text("Hue", 10, height - (textAscent() + textDescent()));
|
||||||
|
|
||||||
|
float lb = map(lowerb, 0, 255, 0, 400);
|
||||||
|
float ub = map(upperb, 0, 255, 0, 400);
|
||||||
|
|
||||||
|
stroke(255, 0, 0); fill(255, 0, 0);
|
||||||
|
strokeWeight(2);
|
||||||
|
line(lb + 10, height-30, ub +10, height-30);
|
||||||
|
ellipse(lb+10, height-30, 3, 3 );
|
||||||
|
text(lowerb, lb-10, height-15);
|
||||||
|
ellipse(ub+10, height-30, 3, 3 );
|
||||||
|
text(upperb, ub+10, height-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseMoved() {
|
||||||
|
if (keyPressed) {
|
||||||
|
upperb += mouseX - pmouseX;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (upperb < 255 || (mouseX - pmouseX) < 0) {
|
||||||
|
lowerb += mouseX - pmouseX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowerb > 0 || (mouseX - pmouseX) > 0) {
|
||||||
|
upperb += mouseX - pmouseX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upperb = constrain(upperb, lowerb, 255);
|
||||||
|
lowerb = constrain(lowerb, 0, upperb-1);
|
||||||
|
}
|
||||||
|
|
After Width: | Height: | Size: 268 KiB |
BIN
lib/opencv_processing/examples/HueRangeSelection/rainbow.jpg
Normal file
After Width: | Height: | Size: 168 KiB |
38
lib/opencv_processing/examples/ImageDiff/ImageDiff.pde
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage before, after, grayDiff;
|
||||||
|
//PImage colorDiff;
|
||||||
|
void setup() {
|
||||||
|
before = loadImage("before.jpg");
|
||||||
|
after = loadImage("after.jpg");
|
||||||
|
size(before.width, before.height);
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, before);
|
||||||
|
opencv.diff(after);
|
||||||
|
grayDiff = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// opencv.useColor();
|
||||||
|
// opencv.loadImage(after);
|
||||||
|
// opencv.diff(after);
|
||||||
|
// colorDiff = opencv.getSnapshot();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
image(before, 0, 0);
|
||||||
|
image(after, before.width, 0);
|
||||||
|
// image(colorDiff, 0, before.height);
|
||||||
|
image(grayDiff, before.width, before.height);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
fill(255);
|
||||||
|
text("before", 10, 20);
|
||||||
|
text("after", before.width/2 +10, 20);
|
||||||
|
text("gray diff", before.width/2 + 10, before.height/2+ 20);
|
||||||
|
|
||||||
|
// text("color diff", 10, before.height/2+ 20);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/ImageDiff/after.jpg
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
lib/opencv_processing/examples/ImageDiff/before.jpg
Normal file
After Width: | Height: | Size: 132 KiB |
297
lib/opencv_processing/examples/ImageFiltering/ImageFiltering.pde
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
/**
|
||||||
|
* Image Filtering
|
||||||
|
* This sketch performs some image filtering (threshold, blur) and contour detection
|
||||||
|
*
|
||||||
|
* @author: Jordi Tost (@jorditost)
|
||||||
|
* @url: https://github.com/jorditost/ImageFiltering/tree/master/ImageFiltering
|
||||||
|
*
|
||||||
|
* University of Applied Sciences Potsdam, 2014
|
||||||
|
*
|
||||||
|
* It requires the ControlP5 Processing library:
|
||||||
|
* http://www.sojamo.de/libraries/controlP5/
|
||||||
|
*/
|
||||||
|
|
||||||
|
import gab.opencv.*;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import processing.video.*;
|
||||||
|
import controlP5.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
Capture video;
|
||||||
|
PImage src, preProcessedImage, processedImage, contoursImage;
|
||||||
|
ArrayList<Contour> contours;
|
||||||
|
|
||||||
|
float contrast = 1.35;
|
||||||
|
int brightness = 0;
|
||||||
|
int threshold = 75;
|
||||||
|
boolean useAdaptiveThreshold = false; // use basic thresholding
|
||||||
|
int thresholdBlockSize = 489;
|
||||||
|
int thresholdConstant = 45;
|
||||||
|
int blobSizeThreshold = 20;
|
||||||
|
int blurSize = 4;
|
||||||
|
|
||||||
|
// Control vars
|
||||||
|
ControlP5 cp5;
|
||||||
|
int buttonColor;
|
||||||
|
int buttonBgColor;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
frameRate(15);
|
||||||
|
|
||||||
|
video = new Capture(this, 640, 480);
|
||||||
|
video.start();
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, 640, 480);
|
||||||
|
contours = new ArrayList<Contour>();
|
||||||
|
|
||||||
|
size(opencv.width + 200, opencv.height, P2D);
|
||||||
|
|
||||||
|
// Init Controls
|
||||||
|
cp5 = new ControlP5(this);
|
||||||
|
initControls();
|
||||||
|
|
||||||
|
// Set thresholding
|
||||||
|
toggleAdaptiveThreshold(useAdaptiveThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
|
||||||
|
// Read last captured frame
|
||||||
|
if (video.available()) {
|
||||||
|
video.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the new frame of our camera in to OpenCV
|
||||||
|
opencv.loadImage(video);
|
||||||
|
src = opencv.getSnapshot();
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// <1> PRE-PROCESS IMAGE
|
||||||
|
// - Grey channel
|
||||||
|
// - Brightness / Contrast
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
// Gray channel
|
||||||
|
opencv.gray();
|
||||||
|
|
||||||
|
//opencv.brightness(brightness);
|
||||||
|
opencv.contrast(contrast);
|
||||||
|
|
||||||
|
// Save snapshot for display
|
||||||
|
preProcessedImage = opencv.getSnapshot();
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// <2> PROCESS IMAGE
|
||||||
|
// - Threshold
|
||||||
|
// - Noise Supression
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
// Adaptive threshold - Good when non-uniform illumination
|
||||||
|
if (useAdaptiveThreshold) {
|
||||||
|
|
||||||
|
// Block size must be odd and greater than 3
|
||||||
|
if (thresholdBlockSize%2 == 0) thresholdBlockSize++;
|
||||||
|
if (thresholdBlockSize < 3) thresholdBlockSize = 3;
|
||||||
|
|
||||||
|
opencv.adaptiveThreshold(thresholdBlockSize, thresholdConstant);
|
||||||
|
|
||||||
|
// Basic threshold - range [0, 255]
|
||||||
|
} else {
|
||||||
|
opencv.threshold(threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert (black bg, white blobs)
|
||||||
|
opencv.invert();
|
||||||
|
|
||||||
|
// Reduce noise - Dilate and erode to close holes
|
||||||
|
opencv.dilate();
|
||||||
|
opencv.erode();
|
||||||
|
|
||||||
|
// Blur
|
||||||
|
opencv.blur(blurSize);
|
||||||
|
|
||||||
|
// Save snapshot for display
|
||||||
|
processedImage = opencv.getSnapshot();
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// <3> FIND CONTOURS
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
// Passing 'true' sorts them by descending area.
|
||||||
|
contours = opencv.findContours(true, true);
|
||||||
|
|
||||||
|
// Save snapshot for display
|
||||||
|
contoursImage = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
pushMatrix();
|
||||||
|
|
||||||
|
// Leave space for ControlP5 sliders
|
||||||
|
translate(width-src.width, 0);
|
||||||
|
|
||||||
|
// Display images
|
||||||
|
displayImages();
|
||||||
|
|
||||||
|
// Display contours in the lower right window
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
translate(src.width, src.height);
|
||||||
|
|
||||||
|
displayContours();
|
||||||
|
displayContoursBoundingBoxes();
|
||||||
|
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// Display Methods
|
||||||
|
/////////////////////
|
||||||
|
|
||||||
|
void displayImages() {
|
||||||
|
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
image(src, 0, 0);
|
||||||
|
image(preProcessedImage, src.width, 0);
|
||||||
|
image(processedImage, 0, src.height);
|
||||||
|
image(src, src.width, src.height);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
stroke(255);
|
||||||
|
fill(255);
|
||||||
|
text("Source", 10, 25);
|
||||||
|
text("Pre-processed Image", src.width/2 + 10, 25);
|
||||||
|
text("Processed Image", 10, src.height/2 + 25);
|
||||||
|
text("Tracked Points", src.width/2 + 10, src.height/2 + 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayContours() {
|
||||||
|
|
||||||
|
for (int i=0; i<contours.size(); i++) {
|
||||||
|
|
||||||
|
Contour contour = contours.get(i);
|
||||||
|
|
||||||
|
noFill();
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
strokeWeight(3);
|
||||||
|
contour.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayContoursBoundingBoxes() {
|
||||||
|
|
||||||
|
for (int i=0; i<contours.size(); i++) {
|
||||||
|
|
||||||
|
Contour contour = contours.get(i);
|
||||||
|
Rectangle r = contour.getBoundingBox();
|
||||||
|
|
||||||
|
if (//(contour.area() > 0.9 * src.width * src.height) ||
|
||||||
|
(r.width < blobSizeThreshold || r.height < blobSizeThreshold))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
fill(255, 0, 0, 150);
|
||||||
|
strokeWeight(2);
|
||||||
|
rect(r.x, r.y, r.width, r.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// CONTROL P5 Functions
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
void initControls() {
|
||||||
|
// Slider for contrast
|
||||||
|
cp5.addSlider("contrast")
|
||||||
|
.setLabel("contrast")
|
||||||
|
.setPosition(20,50)
|
||||||
|
.setRange(0.0,6.0)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for threshold
|
||||||
|
cp5.addSlider("threshold")
|
||||||
|
.setLabel("threshold")
|
||||||
|
.setPosition(20,110)
|
||||||
|
.setRange(0,255)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Toggle to activae adaptive threshold
|
||||||
|
cp5.addToggle("toggleAdaptiveThreshold")
|
||||||
|
.setLabel("use adaptive threshold")
|
||||||
|
.setSize(10,10)
|
||||||
|
.setPosition(20,144)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for adaptive threshold block size
|
||||||
|
cp5.addSlider("thresholdBlockSize")
|
||||||
|
.setLabel("a.t. block size")
|
||||||
|
.setPosition(20,180)
|
||||||
|
.setRange(1,700)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for adaptive threshold constant
|
||||||
|
cp5.addSlider("thresholdConstant")
|
||||||
|
.setLabel("a.t. constant")
|
||||||
|
.setPosition(20,200)
|
||||||
|
.setRange(-100,100)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for blur size
|
||||||
|
cp5.addSlider("blurSize")
|
||||||
|
.setLabel("blur size")
|
||||||
|
.setPosition(20,260)
|
||||||
|
.setRange(1,20)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for minimum blob size
|
||||||
|
cp5.addSlider("blobSizeThreshold")
|
||||||
|
.setLabel("min blob size")
|
||||||
|
.setPosition(20,290)
|
||||||
|
.setRange(0,60)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Store the default background color, we gonna need it later
|
||||||
|
buttonColor = cp5.getController("contrast").getColor().getForeground();
|
||||||
|
buttonBgColor = cp5.getController("contrast").getColor().getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleAdaptiveThreshold(boolean theFlag) {
|
||||||
|
|
||||||
|
useAdaptiveThreshold = theFlag;
|
||||||
|
|
||||||
|
if (useAdaptiveThreshold) {
|
||||||
|
|
||||||
|
// Lock basic threshold
|
||||||
|
setLock(cp5.getController("threshold"), true);
|
||||||
|
|
||||||
|
// Unlock adaptive threshold
|
||||||
|
setLock(cp5.getController("thresholdBlockSize"), false);
|
||||||
|
setLock(cp5.getController("thresholdConstant"), false);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Unlock basic threshold
|
||||||
|
setLock(cp5.getController("threshold"), false);
|
||||||
|
|
||||||
|
// Lock adaptive threshold
|
||||||
|
setLock(cp5.getController("thresholdBlockSize"), true);
|
||||||
|
setLock(cp5.getController("thresholdConstant"), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLock(Controller theController, boolean theValue) {
|
||||||
|
|
||||||
|
theController.setLock(theValue);
|
||||||
|
|
||||||
|
if (theValue) {
|
||||||
|
theController.setColorBackground(color(150,150));
|
||||||
|
theController.setColorForeground(color(100,100));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
theController.setColorBackground(color(buttonBgColor));
|
||||||
|
theController.setColorForeground(color(buttonColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
After Width: | Height: | Size: 268 KiB |
After Width: | Height: | Size: 221 KiB |
@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* Blob Class
|
||||||
|
*
|
||||||
|
* Based on this example by Daniel Shiffman:
|
||||||
|
* http://shiffman.net/2011/04/26/opencv-matching-faces-over-time/
|
||||||
|
*
|
||||||
|
* @author: Jordi Tost (@jorditost)
|
||||||
|
*
|
||||||
|
* University of Applied Sciences Potsdam, 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Blob {
|
||||||
|
|
||||||
|
private PApplet parent;
|
||||||
|
|
||||||
|
// Contour
|
||||||
|
public Contour contour;
|
||||||
|
|
||||||
|
// Am I available to be matched?
|
||||||
|
public boolean available;
|
||||||
|
|
||||||
|
// Should I be deleted?
|
||||||
|
public boolean delete;
|
||||||
|
|
||||||
|
// How long should I live if I have disappeared?
|
||||||
|
private int initTimer = 5; //127;
|
||||||
|
public int timer;
|
||||||
|
|
||||||
|
// Unique ID for each blob
|
||||||
|
int id;
|
||||||
|
|
||||||
|
// Make me
|
||||||
|
Blob(PApplet parent, int id, Contour c) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.id = id;
|
||||||
|
this.contour = new Contour(parent, c.pointMat);
|
||||||
|
|
||||||
|
available = true;
|
||||||
|
delete = false;
|
||||||
|
|
||||||
|
timer = initTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show me
|
||||||
|
void display() {
|
||||||
|
Rectangle r = contour.getBoundingBox();
|
||||||
|
|
||||||
|
float opacity = map(timer, 0, initTimer, 0, 127);
|
||||||
|
fill(0,0,255,opacity);
|
||||||
|
stroke(0,0,255);
|
||||||
|
rect(r.x, r.y, r.width, r.height);
|
||||||
|
fill(255,2*opacity);
|
||||||
|
textSize(26);
|
||||||
|
text(""+id, r.x+10, r.y+30);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give me a new contour for this blob (shape, points, location, size)
|
||||||
|
// Oooh, it would be nice to lerp here!
|
||||||
|
void update(Contour newC) {
|
||||||
|
|
||||||
|
contour = new Contour(parent, newC.pointMat);
|
||||||
|
|
||||||
|
// Is there a way to update the contour's points without creating a new one?
|
||||||
|
/*ArrayList<PVector> newPoints = newC.getPoints();
|
||||||
|
Point[] inputPoints = new Point[newPoints.size()];
|
||||||
|
|
||||||
|
for(int i = 0; i < newPoints.size(); i++){
|
||||||
|
inputPoints[i] = new Point(newPoints.get(i).x, newPoints.get(i).y);
|
||||||
|
}
|
||||||
|
contour.loadPoints(inputPoints);*/
|
||||||
|
|
||||||
|
timer = initTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count me down, I am gone
|
||||||
|
void countDown() {
|
||||||
|
timer--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I am deed, delete me
|
||||||
|
boolean dead() {
|
||||||
|
if (timer < 0) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getBoundingBox() {
|
||||||
|
return contour.getBoundingBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,455 @@
|
|||||||
|
/**
|
||||||
|
* Image Filtering
|
||||||
|
* This sketch will help us to adjust the filter values to optimize blob detection
|
||||||
|
*
|
||||||
|
* Persistence algorithm by Daniel Shifmann:
|
||||||
|
* http://shiffman.net/2011/04/26/opencv-matching-faces-over-time/
|
||||||
|
*
|
||||||
|
* @author: Jordi Tost (@jorditost)
|
||||||
|
* @url: https://github.com/jorditost/ImageFiltering/tree/master/ImageFilteringWithBlobPersistence
|
||||||
|
*
|
||||||
|
* University of Applied Sciences Potsdam, 2014
|
||||||
|
*
|
||||||
|
* It requires the ControlP5 Processing library:
|
||||||
|
* http://www.sojamo.de/libraries/controlP5/
|
||||||
|
*/
|
||||||
|
|
||||||
|
import gab.opencv.*;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import processing.video.*;
|
||||||
|
import controlP5.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
Capture video;
|
||||||
|
PImage src, preProcessedImage, processedImage, contoursImage;
|
||||||
|
|
||||||
|
ArrayList<Contour> contours;
|
||||||
|
|
||||||
|
// List of detected contours parsed as blobs (every frame)
|
||||||
|
ArrayList<Contour> newBlobContours;
|
||||||
|
|
||||||
|
// List of my blob objects (persistent)
|
||||||
|
ArrayList<Blob> blobList;
|
||||||
|
|
||||||
|
|
||||||
|
// Number of blobs detected over all time. Used to set IDs.
|
||||||
|
int blobCount = 0;
|
||||||
|
|
||||||
|
float contrast = 1.35;
|
||||||
|
int brightness = 0;
|
||||||
|
int threshold = 75;
|
||||||
|
boolean useAdaptiveThreshold = false; // use basic thresholding
|
||||||
|
int thresholdBlockSize = 489;
|
||||||
|
int thresholdConstant = 45;
|
||||||
|
int blobSizeThreshold = 20;
|
||||||
|
int blurSize = 4;
|
||||||
|
|
||||||
|
// Control vars
|
||||||
|
ControlP5 cp5;
|
||||||
|
int buttonColor;
|
||||||
|
int buttonBgColor;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
frameRate(15);
|
||||||
|
|
||||||
|
video = new Capture(this, 640, 480);
|
||||||
|
//video = new Capture(this, 640, 480, "USB2.0 PC CAMERA");
|
||||||
|
video.start();
|
||||||
|
|
||||||
|
opencv = new OpenCV(this, 640, 480);
|
||||||
|
contours = new ArrayList<Contour>();
|
||||||
|
|
||||||
|
// Blobs list
|
||||||
|
blobList = new ArrayList<Blob>();
|
||||||
|
|
||||||
|
size(opencv.width + 200, opencv.height, P2D);
|
||||||
|
|
||||||
|
// Init Controls
|
||||||
|
cp5 = new ControlP5(this);
|
||||||
|
initControls();
|
||||||
|
|
||||||
|
// Set thresholding
|
||||||
|
toggleAdaptiveThreshold(useAdaptiveThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
|
||||||
|
// Read last captured frame
|
||||||
|
if (video.available()) {
|
||||||
|
video.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the new frame of our camera in to OpenCV
|
||||||
|
opencv.loadImage(video);
|
||||||
|
src = opencv.getSnapshot();
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// <1> PRE-PROCESS IMAGE
|
||||||
|
// - Grey channel
|
||||||
|
// - Brightness / Contrast
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
// Gray channel
|
||||||
|
opencv.gray();
|
||||||
|
|
||||||
|
//opencv.brightness(brightness);
|
||||||
|
opencv.contrast(contrast);
|
||||||
|
|
||||||
|
// Save snapshot for display
|
||||||
|
preProcessedImage = opencv.getSnapshot();
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// <2> PROCESS IMAGE
|
||||||
|
// - Threshold
|
||||||
|
// - Noise Supression
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
// Adaptive threshold - Good when non-uniform illumination
|
||||||
|
if (useAdaptiveThreshold) {
|
||||||
|
|
||||||
|
// Block size must be odd and greater than 3
|
||||||
|
if (thresholdBlockSize%2 == 0) thresholdBlockSize++;
|
||||||
|
if (thresholdBlockSize < 3) thresholdBlockSize = 3;
|
||||||
|
|
||||||
|
opencv.adaptiveThreshold(thresholdBlockSize, thresholdConstant);
|
||||||
|
|
||||||
|
// Basic threshold - range [0, 255]
|
||||||
|
} else {
|
||||||
|
opencv.threshold(threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert (black bg, white blobs)
|
||||||
|
opencv.invert();
|
||||||
|
|
||||||
|
// Reduce noise - Dilate and erode to close holes
|
||||||
|
opencv.dilate();
|
||||||
|
opencv.erode();
|
||||||
|
|
||||||
|
// Blur
|
||||||
|
opencv.blur(blurSize);
|
||||||
|
|
||||||
|
// Save snapshot for display
|
||||||
|
processedImage = opencv.getSnapshot();
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
// <3> FIND CONTOURS
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
detectBlobs();
|
||||||
|
// Passing 'true' sorts them by descending area.
|
||||||
|
//contours = opencv.findContours(true, true);
|
||||||
|
|
||||||
|
// Save snapshot for display
|
||||||
|
contoursImage = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
pushMatrix();
|
||||||
|
|
||||||
|
// Leave space for ControlP5 sliders
|
||||||
|
translate(width-src.width, 0);
|
||||||
|
|
||||||
|
// Display images
|
||||||
|
displayImages();
|
||||||
|
|
||||||
|
// Display contours in the lower right window
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
translate(src.width, src.height);
|
||||||
|
|
||||||
|
// Contours
|
||||||
|
//displayContours();
|
||||||
|
//displayContoursBoundingBoxes();
|
||||||
|
|
||||||
|
// Blobs
|
||||||
|
displayBlobs();
|
||||||
|
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Display Functions
|
||||||
|
///////////////////////
|
||||||
|
|
||||||
|
void displayImages() {
|
||||||
|
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
image(src, 0, 0);
|
||||||
|
image(preProcessedImage, src.width, 0);
|
||||||
|
image(processedImage, 0, src.height);
|
||||||
|
image(src, src.width, src.height);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
stroke(255);
|
||||||
|
fill(255);
|
||||||
|
textSize(12);
|
||||||
|
text("Source", 10, 25);
|
||||||
|
text("Pre-processed Image", src.width/2 + 10, 25);
|
||||||
|
text("Processed Image", 10, src.height/2 + 25);
|
||||||
|
text("Tracked Points", src.width/2 + 10, src.height/2 + 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayBlobs() {
|
||||||
|
|
||||||
|
for (Blob b : blobList) {
|
||||||
|
strokeWeight(1);
|
||||||
|
b.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayContours() {
|
||||||
|
|
||||||
|
// Contours
|
||||||
|
for (int i=0; i<contours.size(); i++) {
|
||||||
|
|
||||||
|
Contour contour = contours.get(i);
|
||||||
|
|
||||||
|
noFill();
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
strokeWeight(3);
|
||||||
|
contour.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayContoursBoundingBoxes() {
|
||||||
|
|
||||||
|
for (int i=0; i<contours.size(); i++) {
|
||||||
|
|
||||||
|
Contour contour = contours.get(i);
|
||||||
|
Rectangle r = contour.getBoundingBox();
|
||||||
|
|
||||||
|
if (//(contour.area() > 0.9 * src.width * src.height) ||
|
||||||
|
(r.width < blobSizeThreshold || r.height < blobSizeThreshold))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
fill(255, 0, 0, 150);
|
||||||
|
strokeWeight(2);
|
||||||
|
rect(r.x, r.y, r.width, r.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// Blob Detection
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
void detectBlobs() {
|
||||||
|
|
||||||
|
// Contours detected in this frame
|
||||||
|
// Passing 'true' sorts them by descending area.
|
||||||
|
contours = opencv.findContours(true, true);
|
||||||
|
|
||||||
|
newBlobContours = getBlobsFromContours(contours);
|
||||||
|
|
||||||
|
//println(contours.length);
|
||||||
|
|
||||||
|
// Check if the detected blobs already exist are new or some has disappeared.
|
||||||
|
|
||||||
|
// SCENARIO 1
|
||||||
|
// blobList is empty
|
||||||
|
if (blobList.isEmpty()) {
|
||||||
|
// Just make a Blob object for every face Rectangle
|
||||||
|
for (int i = 0; i < newBlobContours.size(); i++) {
|
||||||
|
println("+++ New blob detected with ID: " + blobCount);
|
||||||
|
blobList.add(new Blob(this, blobCount, newBlobContours.get(i)));
|
||||||
|
blobCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCENARIO 2
|
||||||
|
// We have fewer Blob objects than face Rectangles found from OpenCV in this frame
|
||||||
|
} else if (blobList.size() <= newBlobContours.size()) {
|
||||||
|
boolean[] used = new boolean[newBlobContours.size()];
|
||||||
|
// Match existing Blob objects with a Rectangle
|
||||||
|
for (Blob b : blobList) {
|
||||||
|
// Find the new blob newBlobContours.get(index) that is closest to blob b
|
||||||
|
// set used[index] to true so that it can't be used twice
|
||||||
|
float record = 50000;
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < newBlobContours.size(); i++) {
|
||||||
|
float d = dist(newBlobContours.get(i).getBoundingBox().x, newBlobContours.get(i).getBoundingBox().y, b.getBoundingBox().x, b.getBoundingBox().y);
|
||||||
|
//float d = dist(blobs[i].x, blobs[i].y, b.r.x, b.r.y);
|
||||||
|
if (d < record && !used[i]) {
|
||||||
|
record = d;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update Blob object location
|
||||||
|
used[index] = true;
|
||||||
|
b.update(newBlobContours.get(index));
|
||||||
|
}
|
||||||
|
// Add any unused blobs
|
||||||
|
for (int i = 0; i < newBlobContours.size(); i++) {
|
||||||
|
if (!used[i]) {
|
||||||
|
println("+++ New blob detected with ID: " + blobCount);
|
||||||
|
blobList.add(new Blob(this, blobCount, newBlobContours.get(i)));
|
||||||
|
//blobList.add(new Blob(blobCount, blobs[i].x, blobs[i].y, blobs[i].width, blobs[i].height));
|
||||||
|
blobCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCENARIO 3
|
||||||
|
// We have more Blob objects than blob Rectangles found from OpenCV in this frame
|
||||||
|
} else {
|
||||||
|
// All Blob objects start out as available
|
||||||
|
for (Blob b : blobList) {
|
||||||
|
b.available = true;
|
||||||
|
}
|
||||||
|
// Match Rectangle with a Blob object
|
||||||
|
for (int i = 0; i < newBlobContours.size(); i++) {
|
||||||
|
// Find blob object closest to the newBlobContours.get(i) Contour
|
||||||
|
// set available to false
|
||||||
|
float record = 50000;
|
||||||
|
int index = -1;
|
||||||
|
for (int j = 0; j < blobList.size(); j++) {
|
||||||
|
Blob b = blobList.get(j);
|
||||||
|
float d = dist(newBlobContours.get(i).getBoundingBox().x, newBlobContours.get(i).getBoundingBox().y, b.getBoundingBox().x, b.getBoundingBox().y);
|
||||||
|
//float d = dist(blobs[i].x, blobs[i].y, b.r.x, b.r.y);
|
||||||
|
if (d < record && b.available) {
|
||||||
|
record = d;
|
||||||
|
index = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update Blob object location
|
||||||
|
Blob b = blobList.get(index);
|
||||||
|
b.available = false;
|
||||||
|
b.update(newBlobContours.get(i));
|
||||||
|
}
|
||||||
|
// Start to kill any left over Blob objects
|
||||||
|
for (Blob b : blobList) {
|
||||||
|
if (b.available) {
|
||||||
|
b.countDown();
|
||||||
|
if (b.dead()) {
|
||||||
|
b.delete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete any blob that should be deleted
|
||||||
|
for (int i = blobList.size()-1; i >= 0; i--) {
|
||||||
|
Blob b = blobList.get(i);
|
||||||
|
if (b.delete) {
|
||||||
|
blobList.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Contour> getBlobsFromContours(ArrayList<Contour> newContours) {
|
||||||
|
|
||||||
|
ArrayList<Contour> newBlobs = new ArrayList<Contour>();
|
||||||
|
|
||||||
|
// Which of these contours are blobs?
|
||||||
|
for (int i=0; i<newContours.size(); i++) {
|
||||||
|
|
||||||
|
Contour contour = newContours.get(i);
|
||||||
|
Rectangle r = contour.getBoundingBox();
|
||||||
|
|
||||||
|
if (//(contour.area() > 0.9 * src.width * src.height) ||
|
||||||
|
(r.width < blobSizeThreshold || r.height < blobSizeThreshold))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
newBlobs.add(contour);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBlobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// CONTROL P5 Functions
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
void initControls() {
|
||||||
|
// Slider for contrast
|
||||||
|
cp5.addSlider("contrast")
|
||||||
|
.setLabel("contrast")
|
||||||
|
.setPosition(20,50)
|
||||||
|
.setRange(0.0,6.0)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for threshold
|
||||||
|
cp5.addSlider("threshold")
|
||||||
|
.setLabel("threshold")
|
||||||
|
.setPosition(20,110)
|
||||||
|
.setRange(0,255)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Toggle to activae adaptive threshold
|
||||||
|
cp5.addToggle("toggleAdaptiveThreshold")
|
||||||
|
.setLabel("use adaptive threshold")
|
||||||
|
.setSize(10,10)
|
||||||
|
.setPosition(20,144)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for adaptive threshold block size
|
||||||
|
cp5.addSlider("thresholdBlockSize")
|
||||||
|
.setLabel("a.t. block size")
|
||||||
|
.setPosition(20,180)
|
||||||
|
.setRange(1,700)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for adaptive threshold constant
|
||||||
|
cp5.addSlider("thresholdConstant")
|
||||||
|
.setLabel("a.t. constant")
|
||||||
|
.setPosition(20,200)
|
||||||
|
.setRange(-100,100)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for blur size
|
||||||
|
cp5.addSlider("blurSize")
|
||||||
|
.setLabel("blur size")
|
||||||
|
.setPosition(20,260)
|
||||||
|
.setRange(1,20)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Slider for minimum blob size
|
||||||
|
cp5.addSlider("blobSizeThreshold")
|
||||||
|
.setLabel("min blob size")
|
||||||
|
.setPosition(20,290)
|
||||||
|
.setRange(0,60)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Store the default background color, we gonna need it later
|
||||||
|
buttonColor = cp5.getController("contrast").getColor().getForeground();
|
||||||
|
buttonBgColor = cp5.getController("contrast").getColor().getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleAdaptiveThreshold(boolean theFlag) {
|
||||||
|
|
||||||
|
useAdaptiveThreshold = theFlag;
|
||||||
|
|
||||||
|
if (useAdaptiveThreshold) {
|
||||||
|
|
||||||
|
// Lock basic threshold
|
||||||
|
setLock(cp5.getController("threshold"), true);
|
||||||
|
|
||||||
|
// Unlock adaptive threshold
|
||||||
|
setLock(cp5.getController("thresholdBlockSize"), false);
|
||||||
|
setLock(cp5.getController("thresholdConstant"), false);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Unlock basic threshold
|
||||||
|
setLock(cp5.getController("threshold"), false);
|
||||||
|
|
||||||
|
// Lock adaptive threshold
|
||||||
|
setLock(cp5.getController("thresholdBlockSize"), true);
|
||||||
|
setLock(cp5.getController("thresholdConstant"), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLock(Controller theController, boolean theValue) {
|
||||||
|
|
||||||
|
theController.setLock(theValue);
|
||||||
|
|
||||||
|
if (theValue) {
|
||||||
|
theController.setColorBackground(color(150,150));
|
||||||
|
theController.setColorForeground(color(100,100));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
theController.setColorBackground(color(buttonBgColor));
|
||||||
|
theController.setColorForeground(color(buttonColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
After Width: | Height: | Size: 221 KiB |
38
lib/opencv_processing/examples/LiveCamTest/LiveCamTest.pde
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
import processing.video.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
Capture video;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(640, 480);
|
||||||
|
video = new Capture(this, 640/2, 480/2);
|
||||||
|
opencv = new OpenCV(this, 640/2, 480/2);
|
||||||
|
opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
|
||||||
|
|
||||||
|
video.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
scale(2);
|
||||||
|
opencv.loadImage(video);
|
||||||
|
|
||||||
|
image(video, 0, 0 );
|
||||||
|
|
||||||
|
noFill();
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
strokeWeight(3);
|
||||||
|
Rectangle[] faces = opencv.detect();
|
||||||
|
println(faces.length);
|
||||||
|
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
println(faces[i].x + "," + faces[i].y);
|
||||||
|
rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void captureEvent(Capture c) {
|
||||||
|
c.read();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
opencv = new OpenCV(this, "test.jpg");
|
||||||
|
size(opencv.width, opencv.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(opencv.getOutput(), 0, 0);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/LoadAndDisplayImage/data/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
lib/opencv_processing/examples/LoadAndDisplayImage/data/test.png
Normal file
After Width: | Height: | Size: 100 KiB |
43
lib/opencv_processing/examples/LumaVsGray/LumaVsGray.pde
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Luma is a better measure of perceived brightness than
|
||||||
|
the tradition grayscale created by averaging R, G, and B channels.
|
||||||
|
This sketch demonstrates converting an image to LAB color space
|
||||||
|
and accessign the Luma channel for comparison with the more common
|
||||||
|
grayscale version. Uses un-wrapped OpenCV cvtColor() function.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
import gab.opencv.*;
|
||||||
|
// Import the OpenCV Improc class,
|
||||||
|
// it has the cvtColor() function we need.
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage colorImage, grayImage;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
colorImage = loadImage("flashlight.jpg");
|
||||||
|
opencv = new OpenCV(this, colorImage);
|
||||||
|
size(opencv.width, opencv.height);
|
||||||
|
// Save the gray image so we can compare it to Luma
|
||||||
|
grayImage = opencv.getSnapshot();
|
||||||
|
// Use built-in OpenCV function to conver the color image from BGR to LAB color space.
|
||||||
|
Imgproc.cvtColor(opencv.getColor(), opencv.getColor(), Imgproc.COLOR_BGR2Lab);
|
||||||
|
// Since the channels start out in the order BGRA,
|
||||||
|
// Converting to LAB will put the Luma in the B channel
|
||||||
|
opencv.setGray(opencv.getB());
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
background(0);
|
||||||
|
pushMatrix();
|
||||||
|
scale(0.5);
|
||||||
|
image(colorImage, colorImage.width/2, 0);
|
||||||
|
image(grayImage, 0, colorImage.height);
|
||||||
|
image(opencv.getOutput(), colorImage.width, colorImage.height);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
fill(255);
|
||||||
|
text("GRAY", 30, height -25);
|
||||||
|
text("LUMA", width/2 + 30, height - 25);
|
||||||
|
}
|
BIN
lib/opencv_processing/examples/LumaVsGray/flashlight.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
@ -0,0 +1,212 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.opencv.core.Core;
|
||||||
|
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.MatOfPoint;
|
||||||
|
import org.opencv.core.MatOfPoint2f;
|
||||||
|
import org.opencv.core.MatOfPoint2f;
|
||||||
|
import org.opencv.core.CvType;
|
||||||
|
|
||||||
|
import org.opencv.core.Point;
|
||||||
|
import org.opencv.core.Size;
|
||||||
|
|
||||||
|
//import java.util.list;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage src, dst, markerImg;
|
||||||
|
ArrayList<MatOfPoint> contours;
|
||||||
|
ArrayList<MatOfPoint2f> approximations;
|
||||||
|
ArrayList<MatOfPoint2f> markers;
|
||||||
|
|
||||||
|
boolean[][] markerCells;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
opencv = new OpenCV(this, "marker_test.jpg");
|
||||||
|
size(opencv.width, opencv.height/2);
|
||||||
|
src = opencv.getInput();
|
||||||
|
|
||||||
|
// hold on to this for later, since adaptiveThreshold is destructive
|
||||||
|
Mat gray = OpenCV.imitate(opencv.getGray());
|
||||||
|
opencv.getGray().copyTo(gray);
|
||||||
|
|
||||||
|
Mat thresholdMat = OpenCV.imitate(opencv.getGray());
|
||||||
|
|
||||||
|
opencv.blur(5);
|
||||||
|
|
||||||
|
Imgproc.adaptiveThreshold(opencv.getGray(), thresholdMat, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY_INV, 451, -65);
|
||||||
|
|
||||||
|
contours = new ArrayList<MatOfPoint>();
|
||||||
|
Imgproc.findContours(thresholdMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
|
||||||
|
|
||||||
|
approximations = createPolygonApproximations(contours);
|
||||||
|
|
||||||
|
markers = new ArrayList<MatOfPoint2f>();
|
||||||
|
markers = selectMarkers(approximations);
|
||||||
|
|
||||||
|
//// Mat markerMat = grat.submat();
|
||||||
|
// Mat warped = OpenCVPro.imitate(gray);
|
||||||
|
//
|
||||||
|
MatOfPoint2f canonicalMarker = new MatOfPoint2f();
|
||||||
|
Point[] canonicalPoints = new Point[4];
|
||||||
|
canonicalPoints[0] = new Point(0, 350);
|
||||||
|
canonicalPoints[1] = new Point(0, 0);
|
||||||
|
canonicalPoints[2] = new Point(350, 0);
|
||||||
|
canonicalPoints[3] = new Point(350, 350);
|
||||||
|
canonicalMarker.fromArray(canonicalPoints);
|
||||||
|
|
||||||
|
println("num points: " + markers.get(0).height());
|
||||||
|
|
||||||
|
Mat transform = Imgproc.getPerspectiveTransform(markers.get(0), canonicalMarker);
|
||||||
|
Mat unWarpedMarker = new Mat(50, 50, CvType.CV_8UC1);
|
||||||
|
Imgproc.warpPerspective(gray, unWarpedMarker, transform, new Size(350, 350));
|
||||||
|
|
||||||
|
|
||||||
|
Imgproc.threshold(unWarpedMarker, unWarpedMarker, 125, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
|
||||||
|
|
||||||
|
float cellSize = 350/7.0;
|
||||||
|
|
||||||
|
markerCells = new boolean[7][7];
|
||||||
|
|
||||||
|
for (int row = 0; row < 7; row++) {
|
||||||
|
for (int col = 0; col < 7; col++) {
|
||||||
|
int cellX = int(col*cellSize);
|
||||||
|
int cellY = int(row*cellSize);
|
||||||
|
|
||||||
|
Mat cell = unWarpedMarker.submat(cellX, cellX +(int)cellSize, cellY, cellY+ (int)cellSize);
|
||||||
|
markerCells[row][col] = (Core.countNonZero(cell) > (cellSize*cellSize)/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int col = 0; col < 7; col++) {
|
||||||
|
for (int row = 0; row < 7; row++) {
|
||||||
|
if (markerCells[row][col]) {
|
||||||
|
print(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = createImage(350, 350, RGB);
|
||||||
|
opencv.toPImage(unWarpedMarker, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ArrayList<MatOfPoint2f> selectMarkers(ArrayList<MatOfPoint2f> candidates) {
|
||||||
|
float minAllowedContourSide = 50;
|
||||||
|
minAllowedContourSide = minAllowedContourSide * minAllowedContourSide;
|
||||||
|
|
||||||
|
ArrayList<MatOfPoint2f> result = new ArrayList<MatOfPoint2f>();
|
||||||
|
|
||||||
|
for (MatOfPoint2f candidate : candidates) {
|
||||||
|
|
||||||
|
if (candidate.size().height != 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Imgproc.isContourConvex(new MatOfPoint(candidate.toArray()))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eliminate markers where consecutive
|
||||||
|
// points are too close together
|
||||||
|
float minDist = src.width * src.width;
|
||||||
|
Point[] points = candidate.toArray();
|
||||||
|
for (int i = 0; i < points.length; i++) {
|
||||||
|
Point side = new Point(points[i].x - points[(i+1)%4].x, points[i].y - points[(i+1)%4].y);
|
||||||
|
float squaredLength = (float)side.dot(side);
|
||||||
|
// println("minDist: " + minDist + " squaredLength: " +squaredLength);
|
||||||
|
minDist = min(minDist, squaredLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
// println(minDist);
|
||||||
|
|
||||||
|
|
||||||
|
if (minDist < minAllowedContourSide) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<MatOfPoint2f> createPolygonApproximations(ArrayList<MatOfPoint> cntrs) {
|
||||||
|
ArrayList<MatOfPoint2f> result = new ArrayList<MatOfPoint2f>();
|
||||||
|
|
||||||
|
double epsilon = cntrs.get(0).size().height * 0.01;
|
||||||
|
println(epsilon);
|
||||||
|
|
||||||
|
for (MatOfPoint contour : cntrs) {
|
||||||
|
MatOfPoint2f approx = new MatOfPoint2f();
|
||||||
|
Imgproc.approxPolyDP(new MatOfPoint2f(contour.toArray()), approx, epsilon, true);
|
||||||
|
result.add(approx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawContours(ArrayList<MatOfPoint> cntrs) {
|
||||||
|
for (MatOfPoint contour : cntrs) {
|
||||||
|
beginShape();
|
||||||
|
Point[] points = contour.toArray();
|
||||||
|
for (int i = 0; i < points.length; i++) {
|
||||||
|
vertex((float)points[i].x, (float)points[i].y);
|
||||||
|
}
|
||||||
|
endShape();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawContours2f(ArrayList<MatOfPoint2f> cntrs) {
|
||||||
|
for (MatOfPoint2f contour : cntrs) {
|
||||||
|
beginShape();
|
||||||
|
Point[] points = contour.toArray();
|
||||||
|
|
||||||
|
for (int i = 0; i < points.length; i++) {
|
||||||
|
vertex((float)points[i].x, (float)points[i].y);
|
||||||
|
}
|
||||||
|
endShape(CLOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
pushMatrix();
|
||||||
|
background(125);
|
||||||
|
scale(0.5);
|
||||||
|
image(src, 0, 0);
|
||||||
|
|
||||||
|
noFill();
|
||||||
|
smooth();
|
||||||
|
strokeWeight(5);
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
drawContours2f(markers);
|
||||||
|
popMatrix();
|
||||||
|
|
||||||
|
pushMatrix();
|
||||||
|
translate(src.width/2, 0);
|
||||||
|
strokeWeight(1);
|
||||||
|
image(dst, 0, 0);
|
||||||
|
|
||||||
|
float cellSize = dst.width/7.0;
|
||||||
|
for (int col = 0; col < 7; col++) {
|
||||||
|
for (int row = 0; row < 7; row++) {
|
||||||
|
if(markerCells[row][col]){
|
||||||
|
fill(255);
|
||||||
|
} else {
|
||||||
|
fill(0);
|
||||||
|
}
|
||||||
|
stroke(0,255,0);
|
||||||
|
rect(col*cellSize, row*cellSize, cellSize, cellSize);
|
||||||
|
//line(i*cellSize, 0, i*cellSize, dst.width);
|
||||||
|
//line(0, i*cellSize, dst.width, i*cellSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/MarkerDetection/marker_test.jpg
Normal file
After Width: | Height: | Size: 372 KiB |
@ -0,0 +1,197 @@
|
|||||||
|
/**
|
||||||
|
* MultipleColorTracking
|
||||||
|
* Select 4 colors to track them separately
|
||||||
|
*
|
||||||
|
* It uses the OpenCV for Processing library by Greg Borenstein
|
||||||
|
* https://github.com/atduskgreg/opencv-processing
|
||||||
|
*
|
||||||
|
* @author: Jordi Tost (@jorditost)
|
||||||
|
* @url: https://github.com/jorditost/ImageFiltering/tree/master/MultipleColorTracking
|
||||||
|
*
|
||||||
|
* University of Applied Sciences Potsdam, 2014
|
||||||
|
*
|
||||||
|
* Instructions:
|
||||||
|
* Press one numerical key [1-4] and click on one color to track it
|
||||||
|
*/
|
||||||
|
|
||||||
|
import gab.opencv.*;
|
||||||
|
import processing.video.*;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
|
||||||
|
Capture video;
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage src;
|
||||||
|
ArrayList<Contour> contours;
|
||||||
|
|
||||||
|
// <1> Set the range of Hue values for our filter
|
||||||
|
//ArrayList<Integer> colors;
|
||||||
|
int maxColors = 4;
|
||||||
|
int[] hues;
|
||||||
|
int[] colors;
|
||||||
|
int rangeWidth = 10;
|
||||||
|
|
||||||
|
PImage[] outputs;
|
||||||
|
|
||||||
|
int colorToChange = -1;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
video = new Capture(this, 640, 480);
|
||||||
|
opencv = new OpenCV(this, video.width, video.height);
|
||||||
|
contours = new ArrayList<Contour>();
|
||||||
|
|
||||||
|
size(opencv.width + opencv.width/4 + 30, opencv.height, P2D);
|
||||||
|
|
||||||
|
// Array for detection colors
|
||||||
|
colors = new int[maxColors];
|
||||||
|
hues = new int[maxColors];
|
||||||
|
|
||||||
|
outputs = new PImage[maxColors];
|
||||||
|
|
||||||
|
video.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
|
||||||
|
background(150);
|
||||||
|
|
||||||
|
if (video.available()) {
|
||||||
|
video.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <2> Load the new frame of our movie in to OpenCV
|
||||||
|
opencv.loadImage(video);
|
||||||
|
|
||||||
|
// Tell OpenCV to use color information
|
||||||
|
opencv.useColor();
|
||||||
|
src = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// <3> Tell OpenCV to work in HSV color space.
|
||||||
|
opencv.useColor(HSB);
|
||||||
|
|
||||||
|
detectColors();
|
||||||
|
|
||||||
|
// Show images
|
||||||
|
image(src, 0, 0);
|
||||||
|
for (int i=0; i<outputs.length; i++) {
|
||||||
|
if (outputs[i] != null) {
|
||||||
|
image(outputs[i], width-src.width/4, i*src.height/4, src.width/4, src.height/4);
|
||||||
|
|
||||||
|
noStroke();
|
||||||
|
fill(colors[i]);
|
||||||
|
rect(src.width, i*src.height/4, 30, src.height/4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print text if new color expected
|
||||||
|
textSize(20);
|
||||||
|
stroke(255);
|
||||||
|
fill(255);
|
||||||
|
|
||||||
|
if (colorToChange > -1) {
|
||||||
|
text("click to change color " + colorToChange, 10, 25);
|
||||||
|
} else {
|
||||||
|
text("press key [1-4] to select color", 10, 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayContoursBoundingBoxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// Detect Functions
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
void detectColors() {
|
||||||
|
|
||||||
|
for (int i=0; i<hues.length; i++) {
|
||||||
|
|
||||||
|
if (hues[i] <= 0) continue;
|
||||||
|
|
||||||
|
opencv.loadImage(src);
|
||||||
|
opencv.useColor(HSB);
|
||||||
|
|
||||||
|
// <4> Copy the Hue channel of our image into
|
||||||
|
// the gray channel, which we process.
|
||||||
|
opencv.setGray(opencv.getH().clone());
|
||||||
|
|
||||||
|
int hueToDetect = hues[i];
|
||||||
|
//println("index " + i + " - hue to detect: " + hueToDetect);
|
||||||
|
|
||||||
|
// <5> Filter the image based on the range of
|
||||||
|
// hue values that match the object we want to track.
|
||||||
|
opencv.inRange(hueToDetect-rangeWidth/2, hueToDetect+rangeWidth/2);
|
||||||
|
|
||||||
|
//opencv.dilate();
|
||||||
|
opencv.erode();
|
||||||
|
|
||||||
|
// TO DO:
|
||||||
|
// Add here some image filtering to detect blobs better
|
||||||
|
|
||||||
|
// <6> Save the processed image for reference.
|
||||||
|
outputs[i] = opencv.getSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
// <7> Find contours in our range image.
|
||||||
|
// Passing 'true' sorts them by descending area.
|
||||||
|
if (outputs[0] != null) {
|
||||||
|
|
||||||
|
opencv.loadImage(outputs[0]);
|
||||||
|
contours = opencv.findContours(true,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayContoursBoundingBoxes() {
|
||||||
|
|
||||||
|
for (int i=0; i<contours.size(); i++) {
|
||||||
|
|
||||||
|
Contour contour = contours.get(i);
|
||||||
|
Rectangle r = contour.getBoundingBox();
|
||||||
|
|
||||||
|
if (r.width < 20 || r.height < 20)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
fill(255, 0, 0, 150);
|
||||||
|
strokeWeight(2);
|
||||||
|
rect(r.x, r.y, r.width, r.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// Keyboard / Mouse
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
void mousePressed() {
|
||||||
|
|
||||||
|
if (colorToChange > -1) {
|
||||||
|
|
||||||
|
color c = get(mouseX, mouseY);
|
||||||
|
println("r: " + red(c) + " g: " + green(c) + " b: " + blue(c));
|
||||||
|
|
||||||
|
int hue = int(map(hue(c), 0, 255, 0, 180));
|
||||||
|
|
||||||
|
colors[colorToChange-1] = c;
|
||||||
|
hues[colorToChange-1] = hue;
|
||||||
|
|
||||||
|
println("color index " + (colorToChange-1) + ", value: " + hue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyPressed() {
|
||||||
|
|
||||||
|
if (key == '1') {
|
||||||
|
colorToChange = 1;
|
||||||
|
|
||||||
|
} else if (key == '2') {
|
||||||
|
colorToChange = 2;
|
||||||
|
|
||||||
|
} else if (key == '3') {
|
||||||
|
colorToChange = 3;
|
||||||
|
|
||||||
|
} else if (key == '4') {
|
||||||
|
colorToChange = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyReleased() {
|
||||||
|
colorToChange = -1;
|
||||||
|
}
|
After Width: | Height: | Size: 606 KiB |
@ -0,0 +1,2 @@
|
|||||||
|
mode.id=processing.mode.java.JavaMode
|
||||||
|
mode=Java
|
36
lib/opencv_processing/examples/OpticalFlow/OpticalFlow.pde
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
import processing.video.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
Movie video;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(568*2, 320);
|
||||||
|
video = new Movie(this, "sample1.mov");
|
||||||
|
opencv = new OpenCV(this, 568, 320);
|
||||||
|
video.loop();
|
||||||
|
video.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
background(0);
|
||||||
|
opencv.loadImage(video);
|
||||||
|
opencv.calculateOpticalFlow();
|
||||||
|
|
||||||
|
image(video, 0, 0);
|
||||||
|
translate(video.width,0);
|
||||||
|
stroke(255,0,0);
|
||||||
|
opencv.drawOpticalFlow();
|
||||||
|
|
||||||
|
PVector aveFlow = opencv.getAverageFlow();
|
||||||
|
int flowScale = 50;
|
||||||
|
|
||||||
|
stroke(255);
|
||||||
|
strokeWeight(2);
|
||||||
|
line(video.width/2, video.height/2, video.width/2 + aveFlow.x*flowScale, video.height/2 + aveFlow.y*flowScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void movieEvent(Movie m) {
|
||||||
|
m.read();
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/OpticalFlow/data/sample1.mov
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
PImage src;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
int roiWidth = 150;
|
||||||
|
int roiHeight = 150;
|
||||||
|
|
||||||
|
boolean useROI = true;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
src = loadImage("test.jpg");
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
size(opencv.width, opencv.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
opencv.loadImage(src);
|
||||||
|
|
||||||
|
if (useROI) {
|
||||||
|
opencv.setROI(mouseX, mouseY, roiWidth, roiHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
opencv.findCannyEdges(20,75);
|
||||||
|
image(opencv.getOutput(), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// toggle ROI on and off
|
||||||
|
void keyPressed() {
|
||||||
|
useROI = !useROI;
|
||||||
|
|
||||||
|
if (!useROI) {
|
||||||
|
opencv.releaseROI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/RegionOfInterest/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
@ -0,0 +1,76 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.opencv.core.MatOfPoint2f;
|
||||||
|
import org.opencv.core.Point;
|
||||||
|
import org.opencv.core.Size;
|
||||||
|
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.CvType;
|
||||||
|
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage src;
|
||||||
|
PImage card;
|
||||||
|
int cardWidth = 250;
|
||||||
|
int cardHeight = 350;
|
||||||
|
|
||||||
|
Contour contour;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
src = loadImage("cards.png");
|
||||||
|
size(src.width + cardWidth, src.height);
|
||||||
|
opencv = new OpenCV(this, src);
|
||||||
|
|
||||||
|
opencv.blur(1);
|
||||||
|
opencv.threshold(120);
|
||||||
|
|
||||||
|
contour = opencv.findContours(false, true).get(0).getPolygonApproximation();
|
||||||
|
|
||||||
|
card = createImage(cardWidth, cardHeight, ARGB);
|
||||||
|
opencv.toPImage(warpPerspective(contour.getPoints(), cardWidth, cardHeight), card);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat getPerspectiveTransformation(ArrayList<PVector> inputPoints, int w, int h) {
|
||||||
|
Point[] canonicalPoints = new Point[4];
|
||||||
|
canonicalPoints[0] = new Point(w, 0);
|
||||||
|
canonicalPoints[1] = new Point(0, 0);
|
||||||
|
canonicalPoints[2] = new Point(0, h);
|
||||||
|
canonicalPoints[3] = new Point(w, h);
|
||||||
|
|
||||||
|
MatOfPoint2f canonicalMarker = new MatOfPoint2f();
|
||||||
|
canonicalMarker.fromArray(canonicalPoints);
|
||||||
|
|
||||||
|
Point[] points = new Point[4];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
points[i] = new Point(inputPoints.get(i).x, inputPoints.get(i).y);
|
||||||
|
}
|
||||||
|
MatOfPoint2f marker = new MatOfPoint2f(points);
|
||||||
|
return Imgproc.getPerspectiveTransform(marker, canonicalMarker);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat warpPerspective(ArrayList<PVector> inputPoints, int w, int h) {
|
||||||
|
Mat transform = getPerspectiveTransformation(inputPoints, w, h);
|
||||||
|
Mat unWarpedMarker = new Mat(w, h, CvType.CV_8UC1);
|
||||||
|
Imgproc.warpPerspective(opencv.getColor(), unWarpedMarker, transform, new Size(w, h));
|
||||||
|
return unWarpedMarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
image(src, 0, 0);
|
||||||
|
noFill();
|
||||||
|
stroke(0, 255, 0);
|
||||||
|
strokeWeight(4);
|
||||||
|
contour.draw();
|
||||||
|
fill(255, 0);
|
||||||
|
ArrayList<PVector> points = contour.getPoints();
|
||||||
|
for (int i = 0; i < points.size(); i++) {
|
||||||
|
text(i, points.get(i).x, points.get(i).y);
|
||||||
|
}
|
||||||
|
|
||||||
|
pushMatrix();
|
||||||
|
translate(src.width, 0);
|
||||||
|
image(card, 0, 0);
|
||||||
|
popMatrix();
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/WarpPerspective/cards.png
Normal file
After Width: | Height: | Size: 846 KiB |
64
lib/opencv_processing/examples/WhichFace/Face.pde
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Which Face Is Which
|
||||||
|
* Daniel Shiffman
|
||||||
|
* http://shiffman.net/2011/04/26/opencv-matching-faces-over-time/
|
||||||
|
*
|
||||||
|
* Modified by Jordi Tost (call the constructor specifying an ID)
|
||||||
|
* @updated: 01/10/2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Face {
|
||||||
|
|
||||||
|
// A Rectangle
|
||||||
|
Rectangle r;
|
||||||
|
|
||||||
|
// Am I available to be matched?
|
||||||
|
boolean available;
|
||||||
|
|
||||||
|
// Should I be deleted?
|
||||||
|
boolean delete;
|
||||||
|
|
||||||
|
// How long should I live if I have disappeared?
|
||||||
|
int timer = 127;
|
||||||
|
|
||||||
|
// Assign a number to each face
|
||||||
|
int id;
|
||||||
|
|
||||||
|
// Make me
|
||||||
|
Face(int newID, int x, int y, int w, int h) {
|
||||||
|
r = new Rectangle(x,y,w,h);
|
||||||
|
available = true;
|
||||||
|
delete = false;
|
||||||
|
id = newID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show me
|
||||||
|
void display() {
|
||||||
|
fill(0,0,255,timer);
|
||||||
|
stroke(0,0,255);
|
||||||
|
rect(r.x,r.y,r.width, r.height);
|
||||||
|
//rect(r.x*scl,r.y*scl,r.width*scl, r.height*scl);
|
||||||
|
fill(255,timer*2);
|
||||||
|
text(""+id,r.x+10,r.y+30);
|
||||||
|
//text(""+id,r.x*scl+10,r.y*scl+30);
|
||||||
|
//text(""+id,r.x*scl+10,r.y*scl+30);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give me a new location / size
|
||||||
|
// Oooh, it would be nice to lerp here!
|
||||||
|
void update(Rectangle newR) {
|
||||||
|
r = (Rectangle) newR.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count me down, I am gone
|
||||||
|
void countDown() {
|
||||||
|
timer--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I am deed, delete me
|
||||||
|
boolean dead() {
|
||||||
|
if (timer < 0) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
162
lib/opencv_processing/examples/WhichFace/WhichFace.pde
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/**
|
||||||
|
* WhichFace
|
||||||
|
* Daniel Shiffman
|
||||||
|
* http://shiffman.net/2011/04/26/opencv-matching-faces-over-time/
|
||||||
|
*
|
||||||
|
* Modified by Jordi Tost (@jorditost) to work with the OpenCV library by Greg Borenstein:
|
||||||
|
* https://github.com/atduskgreg/opencv-processing
|
||||||
|
*
|
||||||
|
* @url: https://github.com/jorditost/BlobPersistence/
|
||||||
|
*
|
||||||
|
* University of Applied Sciences Potsdam, 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
import gab.opencv.*;
|
||||||
|
import processing.video.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
Capture video;
|
||||||
|
OpenCV opencv;
|
||||||
|
|
||||||
|
// List of my Face objects (persistent)
|
||||||
|
ArrayList<Face> faceList;
|
||||||
|
|
||||||
|
// List of detected faces (every frame)
|
||||||
|
Rectangle[] faces;
|
||||||
|
|
||||||
|
// Number of faces detected over all time. Used to set IDs.
|
||||||
|
int faceCount = 0;
|
||||||
|
|
||||||
|
// Scaling down the video
|
||||||
|
int scl = 2;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
size(640, 480);
|
||||||
|
video = new Capture(this, width/scl, height/scl);
|
||||||
|
opencv = new OpenCV(this, width/scl, height/scl);
|
||||||
|
opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
|
||||||
|
|
||||||
|
faceList = new ArrayList<Face>();
|
||||||
|
|
||||||
|
video.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
scale(scl);
|
||||||
|
opencv.loadImage(video);
|
||||||
|
|
||||||
|
image(video, 0, 0 );
|
||||||
|
|
||||||
|
detectFaces();
|
||||||
|
|
||||||
|
// Draw all the faces
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
noFill();
|
||||||
|
strokeWeight(5);
|
||||||
|
stroke(255,0,0);
|
||||||
|
//rect(faces[i].x*scl,faces[i].y*scl,faces[i].width*scl,faces[i].height*scl);
|
||||||
|
rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Face f : faceList) {
|
||||||
|
strokeWeight(2);
|
||||||
|
f.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void detectFaces() {
|
||||||
|
|
||||||
|
// Faces detected in this frame
|
||||||
|
faces = opencv.detect();
|
||||||
|
|
||||||
|
// Check if the detected faces already exist are new or some has disappeared.
|
||||||
|
|
||||||
|
// SCENARIO 1
|
||||||
|
// faceList is empty
|
||||||
|
if (faceList.isEmpty()) {
|
||||||
|
// Just make a Face object for every face Rectangle
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
println("+++ New face detected with ID: " + faceCount);
|
||||||
|
faceList.add(new Face(faceCount, faces[i].x,faces[i].y,faces[i].width,faces[i].height));
|
||||||
|
faceCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCENARIO 2
|
||||||
|
// We have fewer Face objects than face Rectangles found from OPENCV
|
||||||
|
} else if (faceList.size() <= faces.length) {
|
||||||
|
boolean[] used = new boolean[faces.length];
|
||||||
|
// Match existing Face objects with a Rectangle
|
||||||
|
for (Face f : faceList) {
|
||||||
|
// Find faces[index] that is closest to face f
|
||||||
|
// set used[index] to true so that it can't be used twice
|
||||||
|
float record = 50000;
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
float d = dist(faces[i].x,faces[i].y,f.r.x,f.r.y);
|
||||||
|
if (d < record && !used[i]) {
|
||||||
|
record = d;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update Face object location
|
||||||
|
used[index] = true;
|
||||||
|
f.update(faces[index]);
|
||||||
|
}
|
||||||
|
// Add any unused faces
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
if (!used[i]) {
|
||||||
|
println("+++ New face detected with ID: " + faceCount);
|
||||||
|
faceList.add(new Face(faceCount, faces[i].x,faces[i].y,faces[i].width,faces[i].height));
|
||||||
|
faceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCENARIO 3
|
||||||
|
// We have more Face objects than face Rectangles found
|
||||||
|
} else {
|
||||||
|
// All Face objects start out as available
|
||||||
|
for (Face f : faceList) {
|
||||||
|
f.available = true;
|
||||||
|
}
|
||||||
|
// Match Rectangle with a Face object
|
||||||
|
for (int i = 0; i < faces.length; i++) {
|
||||||
|
// Find face object closest to faces[i] Rectangle
|
||||||
|
// set available to false
|
||||||
|
float record = 50000;
|
||||||
|
int index = -1;
|
||||||
|
for (int j = 0; j < faceList.size(); j++) {
|
||||||
|
Face f = faceList.get(j);
|
||||||
|
float d = dist(faces[i].x,faces[i].y,f.r.x,f.r.y);
|
||||||
|
if (d < record && f.available) {
|
||||||
|
record = d;
|
||||||
|
index = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update Face object location
|
||||||
|
Face f = faceList.get(index);
|
||||||
|
f.available = false;
|
||||||
|
f.update(faces[i]);
|
||||||
|
}
|
||||||
|
// Start to kill any left over Face objects
|
||||||
|
for (Face f : faceList) {
|
||||||
|
if (f.available) {
|
||||||
|
f.countDown();
|
||||||
|
if (f.dead()) {
|
||||||
|
f.delete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete any that should be deleted
|
||||||
|
for (int i = faceList.size()-1; i >= 0; i--) {
|
||||||
|
Face f = faceList.get(i);
|
||||||
|
if (f.delete) {
|
||||||
|
faceList.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void captureEvent(Capture c) {
|
||||||
|
c.read();
|
||||||
|
}
|
After Width: | Height: | Size: 390 KiB |
@ -0,0 +1,43 @@
|
|||||||
|
import gab.opencv.*;
|
||||||
|
|
||||||
|
OpenCV opencv;
|
||||||
|
PImage threshold, blur, adaptive, gray;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
PImage img = loadImage("test.jpg");
|
||||||
|
size(img.width, img.height);
|
||||||
|
|
||||||
|
// By default, OpenCV for Processing works with a gray
|
||||||
|
// version of the source image
|
||||||
|
opencv = new OpenCV(this, img);
|
||||||
|
// but you can tell it explicitly to use color instead:
|
||||||
|
opencv.useColor();
|
||||||
|
|
||||||
|
// A lot of OpenCV operations only work on grayscale images.
|
||||||
|
// But some do work in color, like threshold, blur, findCannyEdges, findChessboardCorners, etc.:
|
||||||
|
opencv.threshold(75);
|
||||||
|
threshold = opencv.getSnapshot();
|
||||||
|
|
||||||
|
opencv.blur(30);
|
||||||
|
blur = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// If you try an operation that does not work in color
|
||||||
|
// it will print out an error message and leave the image unaffected
|
||||||
|
opencv.adaptiveThreshold(591, 1);
|
||||||
|
adaptive = opencv.getSnapshot();
|
||||||
|
|
||||||
|
// if you convert the image to gray then you can
|
||||||
|
// do gray-only operations
|
||||||
|
opencv.gray();
|
||||||
|
opencv.adaptiveThreshold(591, 1);
|
||||||
|
gray = opencv.getSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() {
|
||||||
|
scale(0.5);
|
||||||
|
image(threshold, 0, 0);
|
||||||
|
image(blur, threshold.width,0);
|
||||||
|
image(adaptive, 0,threshold.height);
|
||||||
|
image(gray, threshold.width, threshold.height);
|
||||||
|
}
|
||||||
|
|
BIN
lib/opencv_processing/examples/WorkingWithColorImages/test.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
11
lib/opencv_processing/library.properties
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
name=OpenCV for Processing
|
||||||
|
category=Video & Vision
|
||||||
|
authors=[Greg Borenstein](http://gregborenstein.com)
|
||||||
|
url=https://github.com/atduskgreg/opencv-processing
|
||||||
|
sentence=Computer vision with OpenCV.
|
||||||
|
paragraph=Based on the official OpenCV Java API. A nice Processing-style API for common tasks and access to the full power of the OpenCV API for the advanced stuff.
|
||||||
|
version=13
|
||||||
|
prettyVersion=0.5.2
|
||||||
|
lastUpdated=0
|
||||||
|
minRevision=0
|
||||||
|
maxRevision=0
|