Just to say how appreciative I am of the input here - totally blown away by your knowledge, clarity and consideration.
I’ve landed on the below - and using some images based on microorganisms and adding Blob detection the result is looking pretty splendid. I’ll soon be working towards sending OSC messages from selected Blob values - mentioning this because there might be implications for my next question.
///////////////////////////////////////////////////////// IMPORT LIBS
import blobDetection.*;
import java.util.Date;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import java.util.Objects;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import milchreis.imageprocessing.*; //unused right now!@!@
import netP5.*;
import oscP5.*;
import processing.video.*;
///////////////////////////////////////////////////////// Blob Variables
PImage Blobimg;
BlobDetection theBlobDetection;
PImage img;
///////////////////////////////////////////////////////// Camera Variables (for BlobDetection)
Capture cam;
boolean newFrame=false;
///////////////////////////////////////////////////////// Graphics Variables
PGraphics canvas;
///////////////////////////////////////////////////////// Img Variables
ArrayList<PImage> images;
int currentImage=0;
int lastImageIndex = 0;
int nextImageIndex = 1;
int cImageIndex = 1;
float alphaValue = 0;
//float alphaShift = 0.0004; // very slow
//float alphaShift = 0.004; // slow
float alphaShift = 0.008; // MEDIUM
//float alphaShift = 0.04; // fast
int randomIndexFade;
float zoomFactor = 0.1;
///////////////////////////////////////////////////////// OSC / Network Variables
OscP5 oscP5;
NetAddress myRemoteLocation;
void setup() { /////////////////////////////////////////////////////////////// setup starts
//fullScreen(P3D,0);
//size(1920,1080, P3D); // HDTV 1080, FullHD, 1080p
//size(1280, 720, P3D); //HD
size(1024,576, P3D);
canvas = createGraphics(width, height);
cam = new Capture(this,160,120); // for Blob
cam.start();
// BlobDetection
// img which will be sent to detection (a smaller copy of the cam frame);
Blobimg = new PImage(80,60);
theBlobDetection = new BlobDetection(Blobimg.width, Blobimg.height);
theBlobDetection.setPosDiscrimination(true);
theBlobDetection.setThreshold(0.08); // will detect bright areas whose luminosity > 0.1;
try (Stream<Path> stream = Files.list(Paths.get(dataPath("")))) {
images = stream // get a list of file objects as stream
.filter(Files::isRegularFile) // filter for regular files
.map(Path::toAbsolutePath) // Get the Filename
.map(Path::toString) // convert to a path string
.filter(str -> str.matches(".*(?i)(\\.(jpg|png))$")) // filter for wanted extensions
.peek(str -> print("try loading image [" + str + "]: ")) // print info which image should be loaded
.map(str -> loadImage(str)) // make it a PImage
.peek(pimg -> println((pimg==null || pimg.width==-1) ? "failed!" : "pass!")) // print loding info message
.filter(Objects::nonNull) // filter for successfully loaded images
.filter(pimg -> pimg.width != -1) // filter for successfully loaded images
.collect(Collectors.toCollection(ArrayList::new)); // convert to ArrayList of PImage
}
catch(Exception e) {
println("Warning: " + e.getMessage());
images = new ArrayList<>();
}
if (images.size() < 1)
print("No valid images found!");
else
print("images found: " + images.size());
myRemoteLocation = new NetAddress("192.168.2.10",12000); // to BlackIpad TouchOSC
noStroke();
frameRate(60);
} //////////////////////////////////////////////////////////////////////////// setup ends
void captureEvent(Capture cam) //////////////////////////////////////////// captureEvent()
{
cam.read();
newFrame = true;
}
void draw() { ////////////////////////////////////////////////////////////////// draw loop
background(0);
if (images.size() > 0) {
surface.setTitle("Image: " + currentImage);
image(images.get(currentImage), 0, 0, width, height);
if (frameCount % 120 == 0)
currentImage = (currentImage + 1) % images.size();
} else {
text("No valid images found!", width/2, height/2);
return;
}
int ListSize = images.size();
float RandomIndex = random(ListSize);
int RandomIndexInt = round (RandomIndex);
fade(lastImageIndex, nextImageIndex, alphaValue, nextImageIndex % 2 != 0);
if (alphaValue >= 1.0) {
lastImageIndex = nextImageIndex;
nextImageIndex = (lastImageIndex + RandomIndexInt) % images.size();
cImageIndex = (lastImageIndex + RandomIndexInt) % images.size();
alphaValue = 0;
}
alphaValue += alphaShift;
if (newFrame)
{
newFrame=false;
image(cam,0,0,0,0);
Blobimg.copy(canvas, 0, 0, canvas.width, canvas.height, 0, 0, Blobimg.width, Blobimg.height);
theBlobDetection.computeBlobs(Blobimg.pixels);
drawBlobsAndEdges(true,true);
}
} ///////////////////////////////////////////////////////////////////////// draw loop end
void fade(int l, int n, float a, boolean zi) { //////////////////////////// fade Start
canvas.beginDraw();
canvas.background(0);
canvas.pushMatrix();
//canvas.image(outAB, 0,0);
if (l >= 0) {
float invAlpha = 1.0-a;
canvas.tint(#0000ff,invAlpha * 255);
PImage limg=images.get(l);
canvas.imageMode(CENTER);
canvas.image(limg, width/2, height/2, width, height);
}
canvas.tint(#0000ff, a * 255);
PImage nimg=images.get(n);
canvas.imageMode(CENTER);
canvas.image(nimg, width/2, height /2, width, height);
canvas.popMatrix();
canvas.endDraw();
image(canvas, 0, 0);
} //////////////////////////////////////////////////////////////////////////////// fade End
void drawBlobsAndEdges(boolean drawBlobs, boolean drawEdges) { ////////////// BlobsAndEdges
strokeWeight(width /999);
Blob b;
EdgeVertex eA,eB;
for (int n=0 ; n<theBlobDetection.getBlobNb() ; n++)
{
b=theBlobDetection.getBlob(n);
if (b!=null)
{
if (drawEdges) // Edges
{
smooth();
strokeWeight(3);
stroke(255, 255, 255, 127);
for (int m=0;m<b.getEdgeNb();m++)
{ eA = b.getEdgeVertexA(m); eB = b.getEdgeVertexB(m);
if (eA !=null && eB !=null)
line(eA.x * width, eA.y * height, eB.x * width, eB.y * height );
//println(theBlobDetection.getBlobNb()+ " blobs"); use the first 8 blobs at any given time
//- send their x and y as SC
}
}
if (drawBlobs) // Blobs
noFill();
{
strokeWeight(1);
stroke(0, 127, 255, 127);
rect(b.xMin * width,b.yMin * height, b.w * width,b.h * height);}
fill(#00ccff, 127);
textSize(9);
text(b.xMin, b.xMin * width,b.yMin * height);
println(b.xMin + " x " + b.yMin + " y ");
}
}
} /////////////////////////////////////////////////////////////////////// BlobsAndEdges end
The next nut to crack, (and my brain melts at even trying to formulate the question) relates to this code’s role in the larger project I’m working on. GoToLoop and Chrisir might recall GoTo’s awesome solution to an earlier question How should I organise this? 256 array with conditional content - Class? - #4 by GoToLoop Is it possible to put this Slideshow into an abstract class? Perhaps not because now “those cool stuffs don’t fit into a method”?