seeing machines
Week 1-2:
Conway’s Game of Life is a cellular automata simulation where a 2D grid of cells evolve between alive and dead states.
- The Game of Life is a zero-player game, where you just set the initial state and the rules, and watch the evolution happen.
- A cell’s state in the next frame depends on the state of its immediate neighbors in the current frame. It is set by counting the number of live or dead neighbors and applying the corresponding rule.
- Depending on this initial state and rules, interesting patterns can emerge where cells can appear to oscillate or travel across the board.
#include “ofApp.h”
//————————————————————–
void ofApp::setup(){
floorImage.load(“photo.jpg”);
ofSetWindowShape(floorImage.getWidth(), floorImage.getHeight());
}
//————————————————————–
void ofApp::update() {
}
//————————————————————–
void ofApp::draw(){
floorImage.draw(0, 0);
ofPixels floorPix = floorImage.getPixels();
for (int y = 0; y < floorImage.getHeight(); y++)
{//画幅高
for (int x = 0; x < floorImage.getWidth(); x++)
{//画幅宽
int statusCount = 0;
ofColor col = floorImage.getColor(x, y);
if (col == ofColor(0)) {//死亡
for (int i = y – 1; i < y + 2; i++) {
for (int j = x – 1; j < x + 2; j++) {//死亡目标坐标的周围
ofColor colAround = floorImage.getColor(j, i);
if (colAround != ofColor(0)) {
statusCount++;
}
}
}
if (statusCount == 3) {
floorPix.setColor(x, y, ofColor(255));
}
}
else {
for (int k = y – 1; k < y + 2; k++) {
for (int l = x – 1; l < x + 2; l++) {
ofColor colAround = floorImage.getColor(l, k);
if (colAround == ofColor(0)) {//存活目标坐标的周围
statusCount++;
}
}
}
}
if (statusCount >= 2 && statusCount<=3) {
floorPix.setColor(x, y, ofColor(0));
}
}
}
floorImage.setFromPixels(floorPix);
}
I solved the problem by using two loops to identify each pixel and set the rules around the impact of the square, and it worked as I expected.
week 3 Opencv
I firstly try to use my laptop camera as the default and make the background subtraction, I also combine the GuiPanel so that it’s more user friendly. (Gif 1)
PS: command the line: ofxCv::threshold(resultImg, briThreshold); will make the video more realistic (image 2)
There are two options for addons:
ofxOpenCv
is the built-in OpenCV addon. This wrapper hides most of the native OpenCV structures and methods and allows us to work strictly in “OF space”. While this simplifies our work, we are limited by the data types and algorithms that are included in the addon.ofxCv
is a user-contributed addon that takes a more transparent approach. Interchange between OF and CV is facilitated with helper functions, but the majority of the work is done using native OpenCV calls. While this may seem more complicated, it reduces our dependency to OF as we are learning how to use OpenCV directly.
#pragma once
#include “ofMain.h”
#include “ofxGui.h”
#include “ofxCv.h”
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
ofVideoGrabber grabber;
ofImage backgroundImg;
ofImage resultImg;
ofParameter<bool> captureBackground;
ofParameter<int> briThreshold;
ofxPanel guiPanel;
};
#include “ofApp.h”
//————————————————————–
void ofApp::setup(){
//grabber.setDeviceID(1);
grabber.setup(1280, 720);
captureBackground.set(“Capture BG”, true);
briThreshold.set(“briThresh”, 127, 0, 255);
guiPanel.setup(“Background sub”);
guiPanel.add(captureBackground);
guiPanel.add(briThreshold);
ofSetWindowShape(1280, 720);
}
//————————————————————–
void ofApp::update(){
grabber.update();
ofImage grabberColorImg;
grabberColorImg.setFromPixels(grabber.getPixels());
ofImage grabberGrayImg;
ofxCv::copyGray(grabberColorImg, grabberGrayImg);
if (captureBackground) {
backgroundImg = grabberGrayImg;
captureBackground = false;
}
ofxCv::absdiff(backgroundImg, grabberGrayImg, resultImg);
ofxCv::threshold(resultImg, briThreshold);
resultImg.update();
}
//————————————————————–
void ofApp::draw() {
resultImg.draw(0, 0);
guiPanel.draw();
}
I firstly try to use my laptop camera as the default and make the background subtraction, I also combine the GuiPanel so that it’s more user friendly.
Next I tried Face Detection, and I also tried the sensitivity of the dector, seems like it can detect face but it can’t reconize whether it’s real human face or fake face.
Note that it does not come with the Haar cascade file, you’ll need to add it yourself to the OF/addons/ofxCv/example-face/bin/data/
folder. You can get the face file in the OF/examples/computer_vision/opencvHaarFinderExample/bin/data/
folder, or you can try some of the other ones from the OpenCV repository.
// ofApp.h
#pragma once
#include “ofMain.h”
#include “ofxCv.h”
class ofApp : public ofBaseApp
{
public:
void setup();
void update();
void draw();
ofVideoGrabber cam;
ofxCv::ObjectFinder finder;
};
// ofApp.cpp
#include “ofApp.h”
using namespace ofxCv;
using namespace cv;
void ofApp::setup()
{
ofSetVerticalSync(true);
ofSetFrameRate(120);
finder.setup(“haarcascade_frontalface_default.xml”);
finder.setPreset(ObjectFinder::Fast);
cam.setup(640, 480);
}
void ofApp::update()
{
cam.update();
if (cam.isFrameNew())
{
finder.update(cam);
}
}
void ofApp::draw()
{
cam.draw(0, 0);
finder.draw();
ofDrawBitmapStringHighlight(ofToString(finder.size()), 10, 20);
}
Next I tried object tracking, it is tracked by determine the color, it is useful if the object color is unique, how ever if there are too many same color in the place, then it might messed up.
If we break it down, this usually consist of many steps:
1: Convert the pixel data to an appropriate color space.
2: Threshold the image based on a target color and offset. As we saw previously, video pixel colors vary over frames, so we need to use an offset to look for a color range.
3: Run the OpenCV contour finding operation on the image.
4: Filter the array of contours and only keep the ones that match the requested parameters.
// ofApp.h
#pragma once
#include “ofMain.h”
#include “ofxCv.h”
#include “ofxGui.h”
class ofApp : public ofBaseApp
{
public:
void setup();
void update();
void draw();
void mousePressed(int x, int y, int button);
ofVideoGrabber grabber;
ofImage processImg;
ofxCv::ContourFinder contourFinder;
ofParameter<ofColor> colorTarget;
ofParameter<int> colorOffset;
ofColor colorUnderMouse;
ofxPanel guiPanel;
};
// ofApp.cpp
#include “ofApp.h”
void ofApp::setup()
{
ofSetWindowShape(640, 480);
// Setup the grabber.
grabber.setup(640, 480);
// Setup the contour finder and parameters.
contourFinder.setUseTargetColor(true);
colorTarget.set(“Color Target”, ofColor(255, 0, 0));
colorOffset.set(“Color Offset”, 10, 0, 255);
// Setup the gui.
guiPanel.setup(“Color Tracker”, “settings.json”);
guiPanel.add(colorTarget);
guiPanel.add(colorOffset);
}
void ofApp::update()
{
grabber.update();
if (grabber.isFrameNew())
{
processImg.setFromPixels(grabber.getPixels());
// Save the color of the pixel under the mouse.
colorUnderMouse = processImg.getColor(ofGetMouseX(), ofGetMouseY());
// Update parameters.
contourFinder.setTargetColor(colorTarget, ofxCv::TRACK_COLOR_HSV);
contourFinder.setThreshold(colorOffset);
// Find contours.
contourFinder.findContours(processImg);
}
}
void ofApp::draw()
{
ofSetColor(255);
// Draw the grabber image.
grabber.draw(0, 0, ofGetWidth(), ofGetHeight());
// Draw the found contours.
contourFinder.draw();
// Draw the color under the mouse.
ofPushStyle();
ofSetColor(colorUnderMouse);
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofNoFill();
ofSetColor(colorUnderMouse.getInverted());
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofPopStyle();
// Draw the gui.
guiPanel.draw();
}
void ofApp::mousePressed(int x, int y, int button)
{
if (!guiPanel.getShape().inside(x, y))
{
// Track the color under the mouse.
colorTarget = colorUnderMouse;
}
}
Area Range: So the next step is to set up the detect range, so it can detect the object in any range we like.
Blur: Another solution is to blur the whole picture, by this way, we can have less small color blocks to affect our result
// ofApp.h
#pragma once
#include “ofMain.h”
#include “ofxCv.h”
#include “ofxGui.h”
class ofApp : public ofBaseApp
{
public:
void setup();
void update();
void draw();
void mousePressed(int x, int y, int button);
ofVideoGrabber grabber;
ofImage processImg;
ofxCv::ContourFinder contourFinder;
ofParameter<ofColor> colorTarget;
ofParameter<int> colorOffset;
ofColor colorUnderMouse;
ofParameter<float> minArea;
ofParameter<float> maxArea;
ofxPanel guiPanel;
};
// ofApp.cpp
#include “ofApp.h”
void ofApp::setup()
{
ofSetWindowShape(640, 480);
// Setup the grabber.
grabber.setup(640, 480);
// Setup the contour finder and parameters.
contourFinder.setUseTargetColor(true);
colorTarget.set(“Color Target”, ofColor(255, 0, 0));
colorOffset.set(“Color Offset”, 10, 0, 255);
minArea.set(“Min Area”, 0.01f, 0, 0.5f);
maxArea.set(“Max Area”, 0.05f, 0, 0.5f);
// Setup the gui.
guiPanel.setup(“Color Tracker”, “settings.json”);
guiPanel.add(colorTarget);
guiPanel.add(colorOffset);
guiPanel.add(minArea);
guiPanel.add(maxArea);
}
void ofApp::update()
{
grabber.update();
if (grabber.isFrameNew())
{
processImg.setFromPixels(grabber.getPixels());
// Save the color of the pixel under the mouse.
colorUnderMouse = processImg.getColor(ofGetMouseX(), ofGetMouseY());
// Update parameters.
contourFinder.setTargetColor(colorTarget, ofxCv::TRACK_COLOR_HSV);
contourFinder.setThreshold(colorOffset);
contourFinder.setMinAreaNorm(minArea);
contourFinder.setMaxAreaNorm(maxArea);
// Find contours.
contourFinder.findContours(processImg);
}
}
void ofApp::draw()
{
ofSetColor(255);
// Draw the grabber image.
grabber.draw(0, 0, ofGetWidth(), ofGetHeight());
// Draw the found contours.
contourFinder.draw();
// Draw the color under the mouse.
ofPushStyle();
ofSetColor(colorUnderMouse);
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofNoFill();
ofSetColor(colorUnderMouse.getInverted());
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofPopStyle();
// Draw the gui.
guiPanel.draw();
}
void ofApp::mousePressed(int x, int y, int button)
{
if (!guiPanel.getShape().inside(x, y))
{
// Track the color under the mouse.
colorTarget = colorUnderMouse;
}
}
// ofApp.h
#pragma once
#include “ofMain.h”
#include “ofxCv.h”
#include “ofxGui.h”
class ofApp : public ofBaseApp
{
public:
void setup();
void update();
void draw();
void mousePressed(int x, int y, int button);
ofVideoGrabber grabber;
ofImage processImg;
ofxCv::ContourFinder contourFinder;
ofParameter<ofColor> colorTarget;
ofParameter<int> colorOffset;
ofColor colorUnderMouse;
ofParameter<float> minArea;
ofParameter<float> maxArea;
ofParameter<int> blurAmount;
ofParameter<bool> debugProcess;
ofxPanel guiPanel;
};
// ofApp.cpp
#include “ofApp.h”
void ofApp::setup()
{
ofSetWindowShape(640, 480);
// Setup the grabber.
grabber.setup(640, 480);
// Setup the contour finder and parameters.
contourFinder.setUseTargetColor(true);
colorTarget.set(“Color Target”, ofColor(255, 0, 0));
colorOffset.set(“Color Offset”, 10, 0, 255);
minArea.set(“Min Area”, 0.01f, 0, 0.5f);
maxArea.set(“Max Area”, 0.05f, 0, 0.5f);
blurAmount.set(“Blur Amount”, 0, 0, 100);
debugProcess.set(“Debug Process”, false);
// Setup the gui.
guiPanel.setup(“Color Tracker”, “settings.json”);
guiPanel.add(colorTarget);
guiPanel.add(colorOffset);
guiPanel.add(minArea);
guiPanel.add(maxArea);
guiPanel.add(blurAmount);
guiPanel.add(debugProcess);
}
void ofApp::update()
{
grabber.update();
if (grabber.isFrameNew())
{
processImg.setFromPixels(grabber.getPixels());
// Filter the image.
if (blurAmount > 0)
{
//ofxCv::blur(processImg, blurAmount);
//ofxCv::GaussianBlur(processImg, blurAmount);
ofxCv::medianBlur(processImg, blurAmount);
processImg.update();
}
// Save the color of the pixel under the mouse.
colorUnderMouse = processImg.getColor(ofGetMouseX(), ofGetMouseY());
// Update parameters.
contourFinder.setTargetColor(colorTarget, ofxCv::TRACK_COLOR_HSV);
contourFinder.setThreshold(colorOffset);
contourFinder.setMinAreaNorm(minArea);
contourFinder.setMaxAreaNorm(maxArea);
// Find contours.
contourFinder.findContours(processImg);
}
}
void ofApp::draw()
{
ofSetColor(255);
if (debugProcess)
{
// Draw the process image.
processImg.draw(0, 0, ofGetWidth(), ofGetHeight());
}
else
{
// Draw the grabber image.
grabber.draw(0, 0, ofGetWidth(), ofGetHeight());
}
// Draw the found contours.
contourFinder.draw();
// Draw the color under the mouse.
ofPushStyle();
ofSetColor(colorUnderMouse);
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofNoFill();
ofSetColor(colorUnderMouse.getInverted());
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofPopStyle();
// Draw the gui.
guiPanel.draw();
}
void ofApp::mousePressed(int x, int y, int button)
{
if (!guiPanel.getShape().inside(x, y))
{
// Track the color under the mouse.
colorTarget = colorUnderMouse;
}
}
The last step is to tracking, and I put a label here to track them well. Tracked blobs are identified using a label. If two blobs from different frames have the same label, then they are considered the same.
// ofApp.h
#pragma once
#include “ofMain.h”
#include “ofxCv.h”
#include “ofxGui.h”
class ofApp : public ofBaseApp
{
public:
void setup();
void update();
void draw();
void mousePressed(int x, int y, int button);
ofVideoGrabber grabber;
ofImage processImg;
ofxCv::ContourFinder contourFinder;
ofParameter<ofColor> colorTarget;
ofParameter<int> colorOffset;
ofColor colorUnderMouse;
ofParameter<float> minArea;
ofParameter<float> maxArea;
ofParameter<int> blurAmount;
ofParameter<int> erodeIterations;
ofParameter<int> persistence;
ofParameter<float> maxDistance;
ofParameter<bool> showLabels;
ofParameter<bool> debugProcess;
ofxPanel guiPanel;
};
// ofApp.cpp
#include “ofApp.h”
void ofApp::setup()
{
ofSetWindowShape(640, 480);
// Setup the grabber.
grabber.setup(640, 480);
// Setup the contour finder and parameters.
contourFinder.setUseTargetColor(true);
colorTarget.set(“Color Target”, ofColor(255, 0, 0));
colorOffset.set(“Color Offset”, 10, 0, 255);
minArea.set(“Min Area”, 0.01f, 0, 0.5f);
maxArea.set(“Max Area”, 0.05f, 0, 0.5f);
blurAmount.set(“Blur Amount”, 0, 0, 100);
erodeIterations.set(“Erode Iterations”, 0, 0, 10);
persistence.set(“Persistence”, 15, 0, 60);
maxDistance.set(“Max Distance”, 64, 0, 640);
showLabels.set(“Show Labels”, false);
debugProcess.set(“Debug Process”, false);
// Setup the gui.
guiPanel.setup(“Color Tracker”, “settings.json”);
guiPanel.add(colorTarget);
guiPanel.add(colorOffset);
guiPanel.add(minArea);
guiPanel.add(maxArea);
guiPanel.add(blurAmount);
guiPanel.add(erodeIterations);
guiPanel.add(persistence);
guiPanel.add(maxDistance);
guiPanel.add(showLabels);
guiPanel.add(debugProcess);
}
void ofApp::update()
{
grabber.update();
if (grabber.isFrameNew())
{
processImg.setFromPixels(grabber.getPixels());
// Filter the image.
if (blurAmount > 0)
{
//ofxCv::blur(processImg, blurAmount);
//ofxCv::GaussianBlur(processImg, blurAmount);
ofxCv::medianBlur(processImg, blurAmount);
}
if (erodeIterations > 0)
{
ofxCv::erode(processImg, erodeIterations.get());
}
processImg.update();
// Save the color of the pixel under the mouse.
colorUnderMouse = processImg.getColor(ofGetMouseX(), ofGetMouseY());
// Update parameters.
contourFinder.setTargetColor(colorTarget, ofxCv::TRACK_COLOR_HSV);
contourFinder.setThreshold(colorOffset);
contourFinder.setMinAreaNorm(minArea);
contourFinder.setMaxAreaNorm(maxArea);
contourFinder.getTracker().setPersistence(persistence);
contourFinder.getTracker().setMaximumDistance(maxDistance);
// Find contours.
contourFinder.findContours(processImg);
}
}
void ofApp::draw()
{
ofSetColor(255);
if (debugProcess)
{
// Draw the process image.
processImg.draw(0, 0, ofGetWidth(), ofGetHeight());
}
else
{
// Draw the grabber image.
grabber.draw(0, 0, ofGetWidth(), ofGetHeight());
}
// Draw the found contours.
contourFinder.draw();
if (showLabels)
{
ofxCv::RectTracker& tracker = contourFinder.getTracker();
ofSetColor(255);
for (int i = 0; i < contourFinder.size(); i++)
{
ofPoint center = ofxCv::toOf(contourFinder.getCenter(i));
int label = contourFinder.getLabel(i);
string msg = ofToString(label) + “:” + ofToString(tracker.getAge(label));
ofDrawBitmapString(msg, center.x, center.y);
ofVec2f velocity = ofxCv::toOf(contourFinder.getVelocity(i));
ofDrawLine(center.x, center.y, center.x + velocity.x, center.y + velocity.y);
}
}
// Draw the color under the mouse.
ofPushStyle();
ofSetColor(colorUnderMouse);
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofNoFill();
ofSetColor(colorUnderMouse.getInverted());
ofDrawRectangle(ofGetMouseX() – 25, ofGetMouseY() – 25, 50, 50);
ofPopStyle();
// Draw the gui.
guiPanel.draw();
}
void ofApp::mousePressed(int x, int y, int button)
{
if (!guiPanel.getShape().inside(x, y))
{
// Track the color under the mouse.
colorTarget = colorUnderMouse;
}
}
By using this, users can change the windowScale by their want and do not effect anything
// Save the color of the pixel under the mouse.
int x = (ofGetMouseX() / (float)ofGetWidth()) * processImg.getWidth();
//int y = (ofGetMouseY() / (float)ofGetHeight()) * processImg.getHeight();
int y = ofMap(ofGetMouseY(), 0, ofGetHeight(), 0, processImg.getHeight(), true);
colorUnderMouse = processImg.getColor(x, y);