顯示具有 OpenCV 標籤的文章。 顯示所有文章
顯示具有 OpenCV 標籤的文章。 顯示所有文章

2017年3月12日 星期日

Raspberry Pi: Install OpenCV 3 with Python2,Python3

since: 2017/03/12
since: 2017/03/31
reference:
1. Install guide: Raspberry Pi 3 + Raspbian Jessie + OpenCV 3 - PyImageSearch
2. Accessing the Raspberry Pi Camera with OpenCV and Python - PyImageSearch

A. 前置準備
    1. Raspberry Pi 3
    2. 16 GB microSD Card (編譯 OpenCV 大約會佔用 3G 的容量)
    3. Camera Module
    4. Enable Camera Interface
         > $ sudo raspi-config




    5. (optional) delete the Wolfram engine to free up some space
        $ sudo apt-get purge wolfram-engine

    6. check Python version
        $ python -V
           Python 2.7.9

        $ python3 -V
           Python 3.4.2

-----------------------------------------------------------------------------------------------

B. 安裝相關套件
    1. update and upgrade any existing packages
        $ sudo apt-get update
        $ sudo apt-get upgrade

    2. install some developer tools
        $ sudo apt-get install build-essential cmake pkg-config

    3. install some image I/O packages
        $ sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev


    4. install some video I/O packages
        $ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
        $ sudo apt-get install libxvidcore-dev libx264-dev

    5. install the GTK development for highgui
        $ sudo apt-get install libgtk2.0-dev

    6. installing a few extra dependencies for optimized
        $ sudo apt-get install libatlas-base-dev gfortran

    7. install both the Python 2.7 and Python 3 header files
        $ sudo apt-get install python2.7-dev python3-dev

-----------------------------------------------------------------------------------------------

C. 下載 OpenCV source code
     1. opencv
         $ cd ~
         $ wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.2.0.zip
         $ chmod 755 opencv.zip
         $ unzip opencv.zip

     2. opencv_contrib (full install of OpenCV)
         $ wget -O opencv_contrib.zip https://github.com/Itseez/opencv_contrib/archive/3.2.0.zip
         $ chmod 755 opencv_contrib.zip
         $ unzip opencv_contrib.zip

Note: Make sure your opencv  and opencv_contrib  versions are the same
          (in this case, 3.2.0)


-----------------------------------------------------------------------------------------------

D. Install Python package manager
     $ wget https://bootstrap.pypa.io/get-pip.py
     $ chmod 755 get-pip.py
     $ sudo python get-pip.py
     $ sudo python3 get-pip.py

-----------------------------------------------------------------------------------------------

E. Installing NumPy
    $ pip install numpy (it may take a bit of time)

-----------------------------------------------------------------------------------------------

F. Compile and Install OpenCV
    $ cd ~/opencv-3.2.0
    $ mkdir build
    $ cd build
    $ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D INSTALL_PYTHON_EXAMPLES=ON -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.2.0/modules -D BUILD_EXAMPLES=ON ..

備註: 選擇性參數: -D INSTALL_C_EXMAPLES=ON

   => Ensuring that Python 2.7 and Python 3 will be used

   > compile OpenCV
     // The Raspberry Pi 3 has four cores, thus we supply a value of 4  to allow OpenCV
     // to compile faster. However, due to race conditions, there are times when
     // make  errors out when using multiple cores.
     // $ make -j4

     $ make // about 7 hours
     $ sudo make install
     $ sudo ldconfig

-----------------------------------------------------------------------------------------------

G. 檢查與測試安裝結果
     1. 檢查
         $ ls -al /usr/local/lib/python2.7/dist-packages/cv2.so
         $ ls -al /usr/local/lib/python3.4/dist-packages/cv2.cpython-34m.so
         //$ cd /usr/local/lib/python3.4/dist-packages/
         //$ sudo cp cv2.cpython-34m.so cv2.so    

     2. 測試 
// python2
$ cd
$ python
>>> import cv2
>>> cv2.__version__
'3.2.0'
>>> exit()

// python3
$ cd
$ python3
>>> import cv2
>>> cv2.__version__
'3.2.0'
>>> exit()

-----------------------------------------------------------------------------------------------

H. 程式測試   
     1. Test out the camera module
         $ raspistill -o output.jpg

-----------------------------------------------------------------------------------------------
     2. Installing picamera
         // when using Python bindings, OpenCV represents images as NumPy arrays

         $ pip install "picamera[array]"

-----------------------------------------------------------------------------------------------
     3. Grabbing a single image (需要先啟動 X Window: $ startx)
         // test_image.py


# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2

# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
rawCapture = PiRGBArray(camera)

# allow the camera to warmup
time.sleep(0.1)

# grab an image from the camera
camera.capture(rawCapture, format="bgr")
image = rawCapture.array

# display the image on screen and wait for a keypress
cv2.imshow("Image", image)
cv2.waitKey(0)


$ python test_image.py


-----------------------------------------------------------------------------------------------

     4. access the video stream (需要先啟動 X Window: $ startx)
         // test_video.py

# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2

# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(640, 480))

# allow the camera to warmup
time.sleep(0.1)

# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    # grab the raw NumPy array representing the image, then initialize the timestamp
    # and occupied/unoccupied text

    image = frame.array

    # show the frame
    cv2.imshow("Frame", image)
    key = cv2.waitKey(1) & 0xFF

    # clear the stream in preparation for the next frame
    rawCapture.truncate(0)

    # if the `q` key was pressed, break from the loop
    if key == ord("q"):
        break

 
$ python test_video.py


2016年5月8日 星期日

Raspberry Pi: Real-Time Face Detection With Camera Module

since: 2016/05/08
update: 2016/05/08
reference:
1. openframeworks
2. I touchs: openFrameworks: Control The Raspberry Pi Camera Module

A. 功能測試: opencvHaarFinderExample
    // 單張照片臉部辨識
    $ cd /home/pi/of_v0.9.3/examples/addons/opencvHaarFinderExample
    $ make
    $ ./bin/opencvHaarFinderExample    // 結果


-----------------------------------------------------------------------------------------------
B. 功能測試: example-texture-mode
     // Camera Module
     $ cd /home/pi/of_v0.9.3/addons/
     $ git clone https://github.com/jvcleave/ofxRPiCameraVideoGrabber
     $ cd /home/pi/of_v0.9.3/addons/ofxRPiCameraVideoGrabber/example-texture-mode
     $ make
     $ ./bin/example-texture-mode

-----------------------------------------------------------------------------------------------

C. Face Detection With Camera Module
     1. addons.make
         ofxOpenCv
         ofxRPiCameraVideoGrabber

***********************************************

     2. main.cpp
#include "ofMain.h"
#include "ofApp.h"
#include "ofGLProgrammableRenderer.h"

int main()
{
    ofSetLogLevel(OF_LOG_VERBOSE);
   
    // read config file
    vector<string> _linesOfTheFile;
    ofBuffer _buffer = ofBufferFromFile("config.txt");
    for (auto line : _buffer.getLines()){
        _linesOfTheFile.push_back(line);
    }
   
    // local variables
    int _debug = ofToBool(_linesOfTheFile[1]);
    int _camWidth = ofToInt(_linesOfTheFile[4]);
    int _camHeight = ofToInt(_linesOfTheFile[7]);
    bool _fullScreen = ofToBool(_linesOfTheFile[10]);
   
    // show debug message
    if(_debug) {
        ofLog() << "****** main()";
        ofLog() << "debug: " << _debug;
        ofLog() << "OpenGL width: " << _camWidth;
        ofLog() << "OpenGL height: " << _camHeight;
        ofLog() << "fullScreen: " << _fullScreen;
    }
   
    ofGLESWindowSettings settings;
    //settings.width = 320;
    //settings.height = 240;

    settings.width = _camWidth;
    settings.height = _camHeight;
   
    settings.setGLESVersion(2);
    ofCreateWindow(settings);
   
    ofRunApp( new ofApp());
}


***********************************************

     3. ofApp.h
#pragma once

#include "ofMain.h"
#include "TerminalListener.h"
#include "RPiVideoGrabber.h"
#include "ofxCvHaarFinder.h"

class ofApp : public ofBaseApp, public KeyListener{

    public:

        void setup();
        void update();
        void draw();
        void keyPressed(int key);

    void onCharacterReceived(KeyListenerEventData& e);
    TerminalListener consoleListener;
   
    //wrapper class for drop-in replacement of ofVideoGrabber
    RPiVideoGrabber vidGrabber;
   
    //@add for CvHaarFinder
    ofxCvHaarFinder finder;
    ofImage grayImg;
    //ofImage img;

    //@add second record
    float countROI;
    long readSeconds; // read from totalSeconds record file
    long writeSeconds; // write to totalSeconds record file
    long latestSeconds; // latestSeconds
   
    // config file
    bool debug;
    int camWidth;
    int camHeight;
    bool fullScreen;
    int frameRate;
    bool concurrentVisit;
    float minROI;
    float maxROI;
    float weightROI;
    string recordFile;
};


***********************************************

    4. ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------

void ofApp::setup()
{
    ofSetLogLevel(OF_LOG_VERBOSE);
   
    // read config file
    vector<string> linesOfTheFile;
    ofBuffer buffer = ofBufferFromFile("config.txt");
    for (auto line : buffer.getLines()){
        linesOfTheFile.push_back(line);
    }
    //for (int i = 0; i < linesOfTheFile.size(); i++) {
    //    ofLog(OF_LOG_VERBOSE, "cur.width = %s", linesOfTheFile[i].c_str());
    //}

   
    debug = ofToBool(linesOfTheFile[1]);
    camWidth = ofToInt(linesOfTheFile[4]);
    camHeight = ofToInt(linesOfTheFile[7]);
    fullScreen = ofToBool(linesOfTheFile[10]);
    frameRate = ofToInt(linesOfTheFile[13]);
    concurrentVisit = ofToBool(linesOfTheFile[16]);
    minROI = ofToFloat(linesOfTheFile[19]);
    maxROI = ofToFloat(linesOfTheFile[22]);
    weightROI = ofToFloat(linesOfTheFile[25]);
    recordFile = linesOfTheFile[28];
   
    if(debug)
    {
        ofLog() << "****** ofApp::setup()";
        ofLog() << "debug: " << debug;
        ofLog() << "camWidth: " << camWidth;
        ofLog() << "camHeight: " << camHeight;
        ofLog() << "fullScreen: " << fullScreen;
        ofLog() << "frameRate: " << frameRate;
        ofLog() << "concurrentVisit: " << concurrentVisit;
        ofLog() << "minROI: " << minROI;
        ofLog() << "maxROI: " << maxROI;
        ofLog() << "weightROI: " << weightROI;
        ofLog() << "recordFile: " << recordFile;
    }
   
    // read totalSeconds record file
    vector<string> totalSecondsFile;
    ofBuffer sbuffer = ofBufferFromFile(recordFile);
    for (auto line : sbuffer.getLines()){
        totalSecondsFile.push_back(line);
    }
   
    readSeconds = ofToFloat(totalSecondsFile[0]);
   
    if(debug)
    {
        ofLog() << "****** read totalSeconds record file";
        ofLog() << "readSeconds: " << readSeconds;
    }
   
    //ofSetFrameRate(5);
    ofSetFrameRate(frameRate);
   
    //allows keys to be entered via terminal remotely (ssh)
    consoleListener.setup(this);
   
    //vidGrabber.setDesiredFrameRate(30);
    vidGrabber.setDesiredFrameRate(frameRate);
    vidGrabber.initGrabber(camWidth, camHeight);
   
    //@add for CvHaarFinder
    //img.load("test.jpg");

    finder.setup("haarcascade_frontalface_default.xml");
    //finder.findHaarObjects(img);
}

//--------------------------------------------------------------
void ofApp::update()
{
    ofBackground(100, 100, 100);
    vidGrabber.update();
   
    if(vidGrabber.isFrameNew())
    {
        //ofPixels & pixels = vidGrabber.getPixels();
        //finder.findHaarObjects(pixels);

        grayImg.setFromPixels(vidGrabber.getPixels());
        grayImg.setImageType(OF_IMAGE_GRAYSCALE);

       
        finder.findHaarObjects(grayImg);
    }
}


//--------------------------------------------------------------
void ofApp::draw(){

    ofSetHexColor(0xffffff);
    //ofSetColor(ofColor::white);
   
    vidGrabber.draw(0, 0);
   
    //@add for CvHaarFinder
    //img.draw(0, 0);

    ofNoFill();
   
    for(unsigned int i = 0; i < finder.blobs.size(); i++) {
       
        ofRectangle cur = finder.blobs[i].boundingRect;
       
        //if(debug){
        //    ofLog(OF_LOG_VERBOSE, "ROI width = %f", cur.width);
        //    ofLog(OF_LOG_VERBOSE, "ROI height = %f", cur.height);
        //}

       
        //if((cur.width >= 50.0 && cur.width <= 150.0) &&
        //   (cur.height >= 50.0 && cur.height <= 150.0)) {

        if((cur.width >= (minROI * camWidth) && cur.width <= (maxROI * camWidth)) &&
           (cur.height >= (minROI * camWidth) && cur.height <= (maxROI * camWidth))) {
            countROI++;
            ofSetColor(255, 0, 0); // red color
            ofDrawRectangle(cur.x, cur.y, cur.width, cur.height);
           
            if(debug) {
                ofSetColor(ofColor::yellow);
                ofDrawBitmapString("ROI = " + ofToString(cur.width) + " x " + ofToString(cur.height), camWidth/5, camHeight/1.02);
            }
            // not concurrent Visit
            if(!concurrentVisit){
                break;
            }
        }
        else {
            ofSetColor(0, 0, 255); // blue color
            ofDrawRectangle(cur.x, cur.y, cur.width, cur.height);
        }
    }
   
    // writeSeconds
    writeSeconds = readSeconds + (countROI / frameRate * weightROI); // weightROI: for calibrate detect missing
   

    if(writeSeconds > latestSeconds){
        // Write data
        if(debug) {
            // totalSeconds record file
            ofLog() << "****** write totalSeconds record file: " << writeSeconds;
        }
       
        ofBuffer secondsBuff;
        secondsBuff.set(ofToString(writeSeconds));
        bool fileWritten = ofBufferToFile(recordFile, secondsBuff);
       
        latestSeconds = writeSeconds;
    }
   
    if(debug){
        // show message
        ofSetColor(ofColor::white);
        ofDrawBitmapString("total seconds: " + ofToString(writeSeconds), camWidth/5, camHeight/1.2);
        ofDrawBitmapString(ofToString(minROI * camWidth) + " <= ROI <= " + ofToString(maxROI * camWidth), camWidth/5, camHeight/1.1);
    }
   
    ofSetColor(100, 100, 100);
}

//--------------------------------------------------------------
void ofApp::keyPressed  (int key)
{
    ofLog(OF_LOG_VERBOSE, "%c keyPressed", key);
    //if (key == 'e')
    //{
    //}
    //@add for VideoGrabber

    if(key == 'd' || key == 'D'){
        debug = !debug;
    }
}

void ofApp::onCharacterReceived(KeyListenerEventData& e)
{
    keyPressed((int)e.character);
}


***********************************************

   5. bin/data 資料夾
        a. haarcascade_frontalface_default.xml // from ofxOpenCv

        b. totalSeconds.txt // record second
            0

        c. config.txt // config file
# debug (true/false)
false

# cam width (int)
320

# cam height (int)
240

# full screen (true/false)
false

# frame rate (int)
5

# concurrent visit (true/false)

false

# minimum width ratio of ROI(region of interest) (float)
0.125

# maximum width ratio of ROI(region of interest) (float)
0.5

# weight of ROI (float)
1.0

# recordFile (string)
totalSeconds.txt

Raspberry Pi: Real-Time Face Detection With USB Webcam & GPIO(I2C)

since: 2016/05/08
update: 2016/08/11
reference:
1. openframeworks
2. GitHub - kashimAstro/ofxGPIO
3. I touchs: Raspberry Pi: Connected Arduino Using I2C


A. 功能測試: opencvHaarFinderExample

    // 單張照片臉部辨識
    $ cd /home/pi/of_v0.9.3/examples/addons/opencvHaarFinderExample
    $ make
    $ ./bin/opencvHaarFinderExample    // 結果

-----------------------------------------------------------------------------------------------

B. 功能測試: videoGrabberExample
    // USB Web Cam
    $ cd /home/pi/of_v0.9.3/examples/video/videoGrabberExample
    $ make
    $ ./bin/videoGrabberExample

    // 結果

-----------------------------------------------------------------------------------------------

C. Face Detection With USB Webcam
    1. addons.make
        ofxOpenCv

***********************************************

    2. main.cpp
#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){
    ofSetLogLevel(OF_LOG_VERBOSE);
   
    // read config file
    vector<string> _linesOfTheFile;
    ofBuffer _buffer = ofBufferFromFile("config.txt");
    for (auto line : _buffer.getLines()){
        _linesOfTheFile.push_back(line);
    }
   
    // local variables
    int _debug = ofToBool(_linesOfTheFile[1]);
    int _camWidth = ofToInt(_linesOfTheFile[4]);
    int _camHeight = ofToInt(_linesOfTheFile[7]);
    bool _fullScreen = ofToBool(_linesOfTheFile[10]);
   
    // show debug message
    if(_debug) {
        ofLog() << "****** main()";
        ofLog() << "debug: " << _debug;
        ofLog() << "OpenGL width: " << _camWidth;
        ofLog() << "OpenGL height: " << _camHeight;
        ofLog() << "fullScreen: " << _fullScreen;
    }

    // fullScreen
    if(_fullScreen) {
        // set camWidth & camHeight as window's
        ofSetupOpenGL(_camWidth, _camHeight, OF_FULLSCREEN);
    }
    // window
    else {
        // set camWidth & camHeight as window's
        ofSetupOpenGL(_camWidth, _camHeight, OF_WINDOW);
    }
   
    // this kicks off the running of my app
    // can be OF_WINDOW or OF_FULLSCREEN
    // pass in width and height too:

    ofRunApp(new ofApp());
}


***********************************************

    3. ofApp.h
#pragma once

#include "ofMain.h"
#include "ofxCvHaarFinder.h"

class ofApp : public ofBaseApp{

    public:
        void setup();
        void update();
        void draw();

        void keyPressed(int key);
        void keyReleased(int key);
        void mouseMoved(int x, int y );
        void mouseDragged(int x, int y, int button);
        void mousePressed(int x, int y, int button);
        void mouseReleased(int x, int y, int button);
        void mouseEntered(int x, int y);
        void mouseExited(int x, int y);
        void windowResized(int w, int h);
        void dragEvent(ofDragInfo dragInfo);
        void gotMessage(ofMessage msg);
   
        //@add for VideoGrabber
        ofVideoGrabber vidGrabber;

        //@add for CvHaarFinder
        //ofImage img;

        ofxCvHaarFinder finder;
   
        //@add second record
        float countROI;
        long readSeconds; // read from totalSeconds record file
        long writeSeconds; // write to totalSeconds record file
        long latestSeconds; // latestSeconds
   
        // config file
        bool debug;
        int camWidth;
        int camHeight;
        bool fullScreen;
        int frameRate;
        bool concurrentVisit;
        float minROI;
        float maxROI;
        float weightROI;
        string recordFile;
};


***********************************************

    4. ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofSetLogLevel(OF_LOG_VERBOSE);
   
    // read config file
    vector<string> linesOfTheFile;
    ofBuffer buffer = ofBufferFromFile("config.txt");
    for (auto line : buffer.getLines()){
        linesOfTheFile.push_back(line);
    }
    //for (int i = 0; i < linesOfTheFile.size(); i++) {
    //    ofLog(OF_LOG_VERBOSE, "cur.width = %s", linesOfTheFile[i].c_str());
    //}

   
    debug = ofToBool(linesOfTheFile[1]);
    camWidth = ofToInt(linesOfTheFile[4]);
    camHeight = ofToInt(linesOfTheFile[7]);
    fullScreen = ofToBool(linesOfTheFile[10]);
    frameRate = ofToInt(linesOfTheFile[13]);
    concurrentVisit = ofToBool(linesOfTheFile[16]);
    minROI = ofToFloat(linesOfTheFile[19]);
    maxROI = ofToFloat(linesOfTheFile[22]);
    weightROI = ofToFloat(linesOfTheFile[25]);
    recordFile = linesOfTheFile[28];
   
    if(debug)
    {
        ofLog() << "****** ofApp::setup()";
        ofLog() << "debug: " << debug;
        ofLog() << "camWidth: " << camWidth;
        ofLog() << "camHeight: " << camHeight;
        ofLog() << "fullScreen: " << fullScreen;
        ofLog() << "frameRate: " << frameRate;
        ofLog() << "concurrentVisit: " << concurrentVisit;
        ofLog() << "minROI: " << minROI;
        ofLog() << "maxROI: " << maxROI;
        ofLog() << "weightROI: " << weightROI;
        ofLog() << "recordFile: " << recordFile;
    }
   
    // read totalSeconds record file
    vector<string> totalSecondsFile;
    ofBuffer sbuffer = ofBufferFromFile(recordFile);
    for (auto line : sbuffer.getLines()){
        totalSecondsFile.push_back(line);
    }
   
    readSeconds = ofToFloat(totalSecondsFile[0]);
   
    if(debug)
    {
        ofLog() << "****** read totalSeconds record file";
        ofLog() << "readSeconds: " << readSeconds;
    }
   
    //ofSetFrameRate(5);
    ofSetFrameRate(frameRate);
   
    //@add for VideoGrabber
    //we can now get back a list of devices.

    vector<ofVideoDevice> devices = vidGrabber.listDevices();
   
    for(int i = 0; i < devices.size(); i++){
        if(devices[i].bAvailable){
            ofLogNotice() << devices[i].id << ": " << devices[i].deviceName;
        }else{
            ofLogNotice() << devices[i].id << ": " << devices[i].deviceName << " - unavailable ";
        }
    }
   
    vidGrabber.setDeviceID(0);
    //vidGrabber.setDesiredFrameRate(60);
    vidGrabber.setDesiredFrameRate(frameRate);
    vidGrabber.initGrabber(camWidth, camHeight);
    ofSetVerticalSync(true);
   
    //@add for CvHaarFinder
    //img.load("test.jpg");

    finder.setup("haarcascade_frontalface_default.xml");
    //finder.findHaarObjects(img);
}

//--------------------------------------------------------------
void ofApp::update(){
    //@add for VideoGrabber
    ofBackground(100, 100, 100);
    vidGrabber.update();
   
    //@add for CvHaarFinder
    if(vidGrabber.isFrameNew()){
        ofPixels & pixels = vidGrabber.getPixels();
        finder.findHaarObjects(pixels);
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
   
    //@add for VideoGrabber
    ofSetHexColor(0xffffff);
    vidGrabber.draw(0, 0);
   
    //@add for CvHaarFinder
    //img.draw(0, 0);

   
    ofNoFill();
    for(unsigned int i = 0; i < finder.blobs.size(); i++) {
       
        ofRectangle cur = finder.blobs[i].boundingRect;
       
        //if(debug){
        //    ofLog(OF_LOG_VERBOSE, "ROI width = %f", cur.width);
        //    ofLog(OF_LOG_VERBOSE, "ROI height = %f", cur.height);
        //}
       
        //if((cur.width >= 50.0 && cur.width <= 150.0) &&
        //   (cur.height >= 50.0 && cur.height <= 150.0)) {

        if((cur.width >= (minROI * camWidth) && cur.width <= (maxROI * camWidth)) &&
          (cur.height >= (minROI * camWidth) && cur.height <= (maxROI * camWidth))) {
           
            countROI++;
            ofSetColor(255, 0, 0); // red color
            ofDrawRectangle(cur.x, cur.y, cur.width, cur.height);
           
            if(debug) {
                ofSetColor(ofColor::yellow);
                ofDrawBitmapString("ROI = " + ofToString(cur.width) + " x " + ofToString(cur.height), camWidth/5, camHeight/1.02);
            }
           
            // not concurrent Visit
            if(!concurrentVisit){
                break;
            }
        }
        else {
            ofSetColor(0, 0, 255); // blue color
            ofDrawRectangle(cur.x, cur.y, cur.width, cur.height);
        }
    }
   
    // writeSeconds
    writeSeconds = readSeconds + (countROI / frameRate * weightROI); // weightROI: for calibrate detect missing
   
    if(writeSeconds > latestSeconds){
        // Write data
        if(debug) {
            // totalSeconds record file
            ofLog() << "****** write totalSeconds record file: " << writeSeconds;
        }
       
        ofBuffer secondsBuff;
        secondsBuff.set(ofToString(writeSeconds));
        bool fileWritten = ofBufferToFile(recordFile, secondsBuff);
       
        latestSeconds = writeSeconds;
    }

    if(debug){
        // show message
        ofSetColor(ofColor::white);
        ofDrawBitmapString("total seconds: " + ofToString(writeSeconds), camWidth/5, camHeight/1.2);
        ofDrawBitmapString(ofToString(minROI * camWidth) + " <= ROI <= " + ofToString(maxROI * camWidth), camWidth/5, camHeight/1.1);
    }
   
    ofSetColor(100, 100, 100);
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    //@add for VideoGrabber
    if(key == 'd' || key == 'D'){
        debug = !debug;
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}


***********************************************

    5. bin/data 資料夾
        a. haarcascade_frontalface_default.xml // from ofxOpenCv

        b. totalSeconds.txt // record second
            0

        c. config.txt // config file
# debug (true/false)
false

# cam width (int)
320

# cam height (int)
240

# full screen (true/false)
false

# frame rate (int)
5

# concurrent visit (true/false)

false

# minimum width ratio of ROI(region of interest) (float)
0.125

# maximum width ratio of ROI(region of interest) (float)
0.5

# weight of ROI (float)
1.0

# recordFile (string)
totalSeconds.txt

-----------------------------------------------------------------------------------------------

* 無法正常作用(可能要配合 ofx 0.9.2) *
D. 利用 GPIO( or I²C: Inter-Integrated Circuit) 傳送資料給 Arduino
     1. 參考: I touchs: Raspberry Pi: Connected Arduino Using I2C
         > 讓 Raspberry Pi 的 I2C 功能啟用, 並且記下以下的資料

           $ ls /dev/i2c*
           /dev/i2c-1

           以及 Arduino 裡的定義:
          
#define SLAVE_ADDRESS 0x04
 
     2. 安裝 ofxGPIO
         $ cd /home/pi/of_v0.9.3/addons 
         $ git clone https://github.com/kashimAstro/ofxGPIO

     3. 修改專案的 addons.make 檔案如下:
         /home/pi/of_v0.9.3/apps/myApps/DPHeadTrackingUSB/addons.make
         ofxOpenCv
         ofxGPIO


     4.
修改 ofApp.h 如下:
/home/pi/of_v0.9.3/apps/myApps/DPHeadTrackingUSB/src/
ofApp.h
 
#pragma once

#include "ofMain.h"
#include "ofxCvHaarFinder.h"
//@add for GPIO
#include "ofxGPIO.h"

class ofApp : public ofBaseApp{

    public:
        void setup();
        void update();
        void draw();
        //@add for GPIO 
        //void exit();

        void keyPressed(int key);
        void keyReleased(int key);
        void mouseMoved(int x, int y );
        void mouseDragged(int x, int y, int button);
        void mousePressed(int x, int y, int button);
        void mouseReleased(int x, int y, int button);
        void mouseEntered(int x, int y);
        void mouseExited(int x, int y);
        void windowResized(int w, int h);
        void dragEvent(ofDragInfo dragInfo);
        void gotMessage(ofMessage msg);
   
        //@add for VideoGrabber
        ofVideoGrabber vidGrabber;

        //@add for CvHaarFinder
        //ofImage img;
        ofxCvHaarFinder finder;
   
        //@add second record
        float countROI;
        long readSeconds; // read from totalSeconds record file
        long writeSeconds; // write to totalSeconds record file
        long latestSeconds; // latestSeconds
   
        // config file
        bool debug;
        int camWidth;
        int camHeight;
        bool fullScreen;
        int frameRate;
        bool concurrentVisit;
        float minROI;
        float maxROI;
        float weightROI;
        string recordFile;

        //@add for I2C
        //I2CBus * bus;

        //@add for GPIO
        //GPIO ofxGPIO;
        GPIO* ofxGPIO;

};

 
     5.
修改 ofApp.cpp 如下:
/home/pi/of_v0.9.3/apps/myApps/DPHeadTrackingUSB/src/ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofSetLogLevel(OF_LOG_VERBOSE);

    // read config file
    vector<string> linesOfTheFile;
    ofBuffer buffer = ofBufferFromFile("config.txt");
    for (auto line : buffer.getLines()){
        linesOfTheFile.push_back(line);
    }
    //for (int i = 0; i < linesOfTheFile.size(); i++) {
    //    ofLog(OF_LOG_VERBOSE, "cur.width = %s", linesOfTheFile[i].c_str());
    //}
   
    debug = ofToBool(linesOfTheFile[1]);
    camWidth = ofToInt(linesOfTheFile[4]);
    camHeight = ofToInt(linesOfTheFile[7]);
    fullScreen = ofToBool(linesOfTheFile[10]);
    frameRate = ofToInt(linesOfTheFile[13]);
    concurrentVisit = ofToBool(linesOfTheFile[16]);
    minROI = ofToFloat(linesOfTheFile[19]);
    maxROI = ofToFloat(linesOfTheFile[22]);
    weightROI = ofToFloat(linesOfTheFile[25]);
    recordFile = linesOfTheFile[28];
   
    if(debug)
    {
        ofLog() << "****** ofApp::setup()";
        ofLog() << "debug: " << debug;
        ofLog() << "camWidth: " << camWidth;
        ofLog() << "camHeight: " << camHeight;
        ofLog() << "fullScreen: " << fullScreen;
        ofLog() << "frameRate: " << frameRate;
        ofLog() << "concurrentVisit: " << concurrentVisit;
        ofLog() << "minROI: " << minROI;
        ofLog() << "maxROI: " << maxROI;
        ofLog() << "weightROI: " << weightROI;
        ofLog() << "recordFile: " << recordFile;
    }
   
    // read totalSeconds record file
    vector<string> totalSecondsFile;
    ofBuffer sbuffer = ofBufferFromFile(recordFile);
    for (auto line : sbuffer.getLines()){
        totalSecondsFile.push_back(line);
    }
   
    readSeconds = ofToFloat(totalSecondsFile[0]);
   
    if(debug)
    {
        ofLog() << "****** read totalSeconds record file";
        ofLog() << "readSeconds: " << readSeconds;
    }
   
    //ofSetFrameRate(5);
    ofSetFrameRate(frameRate);
   
    //@add for VideoGrabber
    //we can now get back a list of devices.
    vector<ofVideoDevice> devices = vidGrabber.listDevices();
   
    for(int i = 0; i < devices.size(); i++){
        if(devices[i].bAvailable){
            ofLogNotice() << devices[i].id << ": " << devices[i].deviceName;
        }else{
            ofLogNotice() << devices[i].id << ": " << devices[i].deviceName << " - unavailable ";
        }
    }
   
    vidGrabber.setDeviceID(0);
    //vidGrabber.setDesiredFrameRate(60);
    vidGrabber.setDesiredFrameRate(frameRate);
    vidGrabber.initGrabber(camWidth, camHeight);
    ofSetVerticalSync(true);
   
    //@add for CvHaarFinder
    //img.load("test.jpg");
    finder.setup("haarcascade_frontalface_default.xml");
    //finder.findHaarObjects(img);

    //@add for GPIO
    //bus = new I2CBus("/dev/i2c-1");
    //bus->addressSet(0x04);


    //@add for GPIO (pin) 
    //ofxGPIO.setup("7");
    //ofxGPIO.export_gpio();
    //ofxGPIO.setdir_gpio("out");

    ofxGPIO = new GPIO("7");
    ofxGPIO->export_gpio();
    ofxGPIO->setdir_gpio("out");

}

//--------------------------------------------------------------
void ofApp::update(){
    //@add for VideoGrabber
    ofBackground(100, 100, 100);
    vidGrabber.update();
   
    //@add for CvHaarFinder
    if(vidGrabber.isFrameNew()){
        ofPixels & pixels = vidGrabber.getPixels();
        finder.findHaarObjects(pixels);
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
   
    //@add for VideoGrabber
    ofSetHexColor(0xffffff);
    vidGrabber.draw(0, 0);
   
    //@add for CvHaarFinder
    //img.draw(0, 0);
   
    ofNoFill();
    for(unsigned int i = 0; i < finder.blobs.size(); i++) {
       
        ofRectangle cur = finder.blobs[i].boundingRect;
       
        //if(debug){
        //    ofLog(OF_LOG_VERBOSE, "ROI width = %f", cur.width);
        //    ofLog(OF_LOG_VERBOSE, "ROI height = %f", cur.height);
        //}
       
        //if((cur.width >= 50.0 && cur.width <= 150.0) &&
        //   (cur.height >= 50.0 && cur.height <= 150.0)) {
        if((cur.width >= (minROI * camWidth) && cur.width <= (maxROI * camWidth)) &&
          (cur.height >= (minROI * camWidth) && cur.height <= (maxROI * camWidth))) {
           
            countROI++;
            ofSetColor(255, 0, 0); // red color
            ofDrawRectangle(cur.x, cur.y, cur.width, cur.height);
           
            if(debug) {
                ofSetColor(ofColor::yellow);
                ofDrawBitmapString("ROI = " + ofToString(cur.width) + " x " + ofToString(cur.height), camWidth/5, camHeight/1.02);
            }
           
            // not concurrent Visit
            if(!concurrentVisit){
                break;
            }
        }
        else {
            ofSetColor(0, 0, 255); // blue color
            ofDrawRectangle(cur.x, cur.y, cur.width, cur.height);
        }
    }
   
    // writeSeconds
    writeSeconds = readSeconds + (countROI / frameRate * weightROI); // weightROI: for calibrate detect missing
   
    if(writeSeconds > latestSeconds){
        // Write data
        if(debug) {
            // totalSeconds record file
            ofLog() << "****** write totalSeconds record file: " << writeSeconds;
        }
       
        ofBuffer secondsBuff;
        secondsBuff.set(ofToString(writeSeconds));
        bool fileWritten = ofBufferToFile(recordFile, secondsBuff);
       
        latestSeconds = writeSeconds;

        //@add for GPIO
        //bus->writeByte(0x04, writeSeconds);
        //usleep(50000); // sleep for 0.05 second

        //@add for test

        /*
        bus->writeByte(0x04,1);
        usleep(500000); // sleep for 0.5 second
        bus->writeByte(0x04,0);
        usleep(500000); // sleep for 0.5 second  

        */  

        //@add for GPIO
        //ofxGPIO.setval_gpio("1");
        //usleep(50000); // sleep for 0.05 second
        //ofxGPIO.setval_gpio("0");
        //usleep(50000); // sleep for 0.05 second

        ofxGPIO->setval_gpio("1");
        usleep(50000); // sleep for 0.05 second
        ofxGPIO->setval_gpio("0");
        usleep(50000); // sleep for 0.05 second

    }

    if(debug){
        // show message
        ofSetColor(ofColor::white);
        ofDrawBitmapString("total seconds: " + ofToString(writeSeconds), camWidth/5, camHeight/1.2);
        ofDrawBitmapString(ofToString(minROI * camWidth) + " <= ROI <= " + ofToString(maxROI * camWidth), camWidth/5, camHeight/1.1);
    }
   
    ofSetColor(100, 100, 100);
}

/*
//--------------------------------------------------------------
void ofApp::exit(){
   
    //@add for GPIO
    ofxGPIO.unexport_gpio();
}

*/

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    //@add for VideoGrabber
    if(key == 'd' || key == 'D'){
        debug = !debug;
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){
}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){
}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}

 
     6. 編譯與執行:
         $ cd /home/pi/of_v0.9.3/apps/myApps/DPHeadTrackingUSB
         $ make         

         $ ./bin/DPHeadTrackingUSB

     7. 開機後自動執行: (console 的訊息會出不來, 建議改成在 .bashrc 裡執行程式)
         $ cd
         $ touch startHeadTracking.sh
         $ chmod 755 startHeadTracking.sh

         $ sudo nano startHeadTracking.sh
#!/bin/bash
sleep 5
cd /home/pi/of_v0.9.3/apps/myApps/DPHeadTrackingUSB
./bin/DPHeadTrackingUSB


         $ cat startHeadTracking.sh

         $ sudo crontab -e
         ....
         @reboot /home/pi/startHeadTracking.sh

         $ sudo crontab -l

2014年1月3日 星期五

OpenCV: Erosion and Dilation

since: 2014/01/03
update: 2014/01/03

reference:
1. Amazon.com: Practical OpenCV eBook
2. Welcome to opencv documentation!
3. I touchs: Using OpenCV on Mac OS X

A. 前置作業:
     1. 先依照 I touchs: Using OpenCV on Mac OS X 的說明, 建置好開發環境.

     2. 需要加入到專案的 OpenCV 函式庫爲: (Add Files to Project...)
          libopencv_core.dylib
          libopencv_highgui.dylib
          libopencv_imgproc.dylib

     3. 將 main.cpp 的 main function 更名.(不作為程式執行的進入點)
          //int main(int argc, const char * argv[])  
          int main_main(int argc, const char * argv[])

     4. 爲專案新增 C++ 檔案:      
         點選專案 > New File... > OS X > C and C++ > C++ Class > Next >
         Save as: ErosionAndDilation.cpp > Create

----------------------------------------------------------------------------------------

B. 撰寫程式:
    1. 開啓 ErosionAndDilation.h 檔案, 修改如下:
#ifndef __HelloOpenCV__ErosionAndDilation__
#define __HelloOpenCV__ErosionAndDilation__

#include <iostream>

//@add
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>


#endif /* defined(__HelloOpenCV__ErosionAndDilation__) */

---------------------------------------------------------------------------------
    2. 開啓 ErosionAndDilation.cpp 檔案, 修改如下:
#include "ErosionAndDilation.h"

using namespace std;
using namespace cv;


// 原始照片, 處理過的照片

Mat ED_image, ED_imageProcessed;

// 選擇的形態學類型: 0: erode(侵蝕), 1: dilate(擴張)
int choice_slider = 0;

// 形態學的結構元素的大小: n x n (ex: 5 x 5)
int size_slider = 5;

const int choice_slider_max = 1; // 選擇形態學類型的最大值
const int size_slider_max = 21; // 形態學的結構元素之最大值

// 進行形態學處理
void process()
{

    // 設定形態學的結構元素(在此為矩形, 長寬皆為 size_slider 的大小)
    Mat st_elem = getStructuringElement(MORPH_RECT, Size(size_slider, size_slider));
   
    // erode(侵蝕)
    if (choice_slider == 0) {
        erode(ED_image, ED_imageProcessed, st_elem);
    }

    // dilate(擴張)
    else {
        dilate(ED_image, ED_imageProcessed, st_elem);
    }
   
    imshow("Processed image", ED_imageProcessed);
    printf("morphological type: %s \n", choice_slider == 0 ? "Erosion" : "Dilation");
    printf("size_slider position: %d \n\n", size_slider);
}


// 選擇形態學類型
void on_choice_slider(int, void*)
{
    process();
}


// 調整形態學的結構元素大小
void on_size_slider(int, void*)
{

    // 將形態學的結構元素大小(值為 size_slider), 調整為大於零的奇數
    size_slider = max(1, size_slider);
    size_slider = size_slider % 2 == 0 ? size_slider + 1 : size_slider;
    setTrackbarPos("Kernel Size", "Processed image", size_slider);
   
    process();
}

int main()
{

    // 讀取檔案
    ED_image = imread("/Lanli/RD/Projects/OpenCV_Mac/HelloOpenCV/pipiGray.png");
    namedWindow("Original image");
    namedWindow("Processed image");
    imshow("Original image", ED_image);

   
    // 設定形態學的結構元素(在此為矩形, 長寬皆為 size_slider 的大小)
    Mat st_elem = getStructuringElement(MORPH_RECT, Size(size_slider, size_slider));
   
    // erode(侵蝕)
    erode(ED_image, ED_imageProcessed, st_elem);
    imshow("Processed image", ED_imageProcessed);
   
    createTrackbar("Erode/Dilate", "Processed image", &choice_slider, choice_slider_max, on_choice_slider);
    createTrackbar("Kernel Size", "Processed image", &size_slider, size_slider_max, on_size_slider);
   
    printf("morphological type: %s \n", choice_slider == 0 ? "Erosion" : "Dilation");
    printf("size_slider position: %d \n\n", size_slider);
   
    while (char(waitKey(1) != 'q')) {}
   
    return 0;
}


----------------------------------------------------------------------------------------

C. 執行結果:
     原始圖片:

     erosion(侵蝕): 結構元素大小: 5 x 5

     dilation(擴張): 結構元素大小: 5 x 5