互動媒體——基于opencv圖像識別的粒子繪畫

方案設(shè)計

基于opencv圖像識別的粒子交互

主題

編寫一個“繪畫系統(tǒng)”,提供一系列繪畫材料(例如畫筆/顏料/濾鏡)給用戶操作,以創(chuàng)作出動態(tài)/交互的繪畫作品。這個繪畫系統(tǒng)是對“繪畫”的概念的擴(kuò)展靠益,但仍然體現(xiàn)出與傳統(tǒng)繪畫系統(tǒng)的相似性。

材料:電腦的代碼残揉,鍵盤胧后,攝像頭,顯示器

作畫者:人揮動手臂抱环;

交互方式:攝像頭識別壳快;

作品:具有時效性纸巷,本來的想法就是做一個交互裝置,后來想到眶痰,粒子系統(tǒng)和沙子會不會有某些相似性呢瘤旨,也許這個系統(tǒng)可以模擬數(shù)字沙畫;


攝像頭識別的交互

圖像中的粒子是一個個的小草莓

白色圓是識別的中心目標(biāo)點(diǎn)

可以看見識別效果還是很一般的竖伯,不過這只是一個測試版存哲,主要功能就是這個樣子了

主要就是兩個功能的組成:識別和粒子

識別一開始是希望用kinect去做的,后來學(xué)院的沒借上七婴,就只能自己搞攝像頭的手部識別了


手部識別:

int ofApp::handloc()

{

int count = 0;

VideoCapture capture;

capture.open(0);

Mat fram, prefram, result, fg;

int framNum = 0;

while (capture.isOpened())

{

capture >> fram;

fram.convertTo(fram, CV_32FC3);

normalize(fram, fram, 1, 0, CV_MINMAX);

imshow("src", fram);

if (framNum == 0)

{

intial(fram);

}

else if (framNum<30)

{

++count;

accbackgound(fram, prefram);

}

else if (framNum == 30)

backgound(count);

else

{

foregound(fram, prefram);

skin(fram);

}

fram.copyTo(prefram);

framNum++;

char key = (char)waitKey(2);

switch (key)

{

case 27:

return 0;

break;

}

}

}

void ofApp::intial(Mat src)

{

src.copyTo(bg);

}

void ofApp::accbackgound(Mat src, Mat pre)

{

Mat temp;

accumulate(src, bg);

absdiff(src, pre, temp);

if (Th.data == NULL)

{

temp.copyTo(Th);

}

else

accumulate(temp, Th);

}

void ofApp::backgound(int count)

{

bg = bg / count;

Th = Th / count;

normalize(bg, bg, 1, 0, CV_MINMAX);

/*imshow("backgound", bg);*/

Mat t[3];

Mat b[3];

split(Th, t);

split(bg, b);

bglow0 = b[0] - t[0] * low;

bglow1 = b[1] - t[1] * low;

bglow2 = b[2] - t[2] * low;

bghigh0 = b[0] + t[0] * high;

bghigh1 = b[1] + t[1] * high;

bghigh2 = b[2] + t[2] * high;

cout << "Start Traclking" << endl;

}

void ofApp::foregound(Mat src, Mat pre)

{

Mat temp0, temp1, temp2;

Mat framNow[3];

Mat frampre[3];

framNow[0].setTo(Scalar(0, 0, 0));

framNow[1].setTo(Scalar(0, 0, 0));

framNow[2].setTo(Scalar(0, 0, 0));

temp0.setTo(Scalar(0, 0, 0));

temp1.setTo(Scalar(0, 0, 0));

temp2.setTo(Scalar(0, 0, 0));

split(src, framNow);

inRange(framNow[0], bglow0, bghigh0, temp0);

inRange(framNow[1], bglow1, bghigh1, temp1);

inRange(framNow[2], bglow2, bghigh2, temp2);

bitwise_or(temp0, temp1, temp0);

bitwise_or(temp0, temp2, temp0);

bitwise_not(temp0, temp0);

imshow("Show", temp0);

temp0.copyTo(mask0);

}

void ofApp::skin(Mat src)

{

src.convertTo(src, CV_8UC3, 255);

Mat yuv, dst;

cvtColor(src, yuv, CV_BGR2YCrCb);

Mat dstTemp1(src.rows, src.cols, CV_8UC1);

Mat dstTemp2(src.rows, src.cols, CV_8UC1);

// 對YUV空間進(jìn)行量化祟偷,得到2值圖像,亮的部分為手的形狀

inRange(yuv, Scalar(0, 133, 0), Scalar(256, 173, 256), dstTemp1);

inRange(yuv, Scalar(0, 0, 77), Scalar(256, 256, 127), dstTemp2);

bitwise_and(dstTemp1, dstTemp2, mask);

dst.setTo(Scalar::all(0));

bitwise_and(mask, mask0, mask);

src.copyTo(dst, mask);

vector< vector<Point> > contours; // 輪廓

vector< vector<Point> > filterContours; // 篩選后的輪廓

vector< Vec4i > hierarchy; // 輪廓的結(jié)構(gòu)信息

vector< Point > hull; // 凸包絡(luò)的點(diǎn)集

contours.clear();

hierarchy.clear();

filterContours.clear();

// 得到手的輪廓

findContours(mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

// 去除偽輪廓

for (size_t i = 0; i < contours.size(); i++)

{

if (fabs(contourArea(Mat(contours[i]))) > 1000 && fabs(arcLength(Mat(contours[i]), true))<2000) //判斷手進(jìn)入?yún)^(qū)域的閾值

{

filterContours.push_back(contours[i]);

}

}

cv::Rect rect;

float radius;

if (!filterContours.empty()) {

minEnclosingCircle(filterContours[0], handcenter, radius);

//cout << handcenter.x << " " << handcenter.y << endl;

}

// 畫輪廓

drawContours(src, filterContours, -1, Scalar(0, 0, 255), 2); //8, hierarchy);

imshow("traclking", src);

}


通過圖像的二值化和手部顏色的識別可以大致識別皮膚的位置打厘,然后通過對識別區(qū)域大小的過濾可以大致識別出手部的位子

思路是這樣修肠,識別出來的效果還是一般,很容易把臉給識別出來婚惫,同時對人物的遠(yuǎn)近沒有自適應(yīng)性氛赐,所以只能在攝像頭前半米的位子識別

總之這樣就獲得了大致手部位子


粒子系統(tǒng):

用openframework帶的例子

#include "demoParticle.h"

#include "ofApp.h"

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

demoParticle::demoParticle(){

attractPoints = NULL;

testphoto.load("C:\\Users\\Yon\\Desktop\\testphoto.png");

}

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

void demoParticle::setMode(particleMode newMode){

mode = newMode;

}

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

void demoParticle::setAttractPoints( vector <ofPoint> * attract ){

attractPoints = attract;

}

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

void demoParticle::reset(){

//為每個粒子設(shè)置不同的屬性

uniqueVal = ofRandom(-10000, 10000);

pos.x = ofRandomWidth();

pos.y = ofRandomHeight();

vel.x = ofRandom(-3.9, 3.9);

vel.y = ofRandom(-3.9, 3.9);

frc? = ofPoint(0,0,0);

scale = ofRandom(0.5, 1.0);

if( mode == PARTICLE_MODE_NOISE ){

drag? = ofRandom(0.97, 0.99);

vel.y = fabs(vel.y) * 3.0; //下降

}else{

drag? = ofRandom(0.95, 0.998);

}

}

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

void demoParticle::update(){

//不同的粒子模式

if( mode == PARTICLE_MODE_ATTRACT ){

ofPoint attractPt(handPoint.x, handPoint.y);

frc = attractPt-pos; // 跟隨鼠標(biāo)

frc.normalize(); //通過標(biāo)準(zhǔn)化,我們忽略了粒子離吸引點(diǎn)有多近

vel *= drag; //apply drag

vel += frc * 0.6; //apply force

}

else if( mode == PARTICLE_MODE_REPEL ){

ofPoint attractPt(handPoint.x, handPoint.y);

frc = attractPt-pos;

//遠(yuǎn)離鼠標(biāo)

float dist = frc.length();

frc.normalize();

vel *= drag;

if( dist < 150 ){

vel += -frc * 0.6; //frc取負(fù)值即可排斥點(diǎn)

}else{

frc.x = ofSignedNoise(uniqueVal, pos.y * 0.001, ofGetElapsedTimef()*0.02);

frc.y = ofSignedNoise(uniqueVal, pos.x * 0.001, ofGetElapsedTimef()*0.02);

vel += frc * 0.004;

}

}

else if( mode == PARTICLE_MODE_NOISE ){

//模擬下墜粒子

float fakeWindX = ofSignedNoise(pos.x * 0.003, pos.y * 0.006, ofGetElapsedTimef() * 0.6);

frc.x = fakeWindX * 0.25 + ofSignedNoise(uniqueVal, pos.y * 0.04) * 0.6;

frc.y = ofSignedNoise(uniqueVal, pos.x * 0.006, ofGetElapsedTimef()*0.2) * 0.09 + 0.18;

vel *= drag;

vel += frc * 0.4;

//底部刷新

if( pos.y + vel.y > ofGetHeight() ){

pos.y -= ofGetHeight();

}

}

else if( mode == PARTICLE_MODE_NEAREST_POINTS ){

if( attractPoints ){

//找到最近點(diǎn)

ofPoint closestPt;

int closest = -1;

float closestDist = 9999999;

for(unsigned int i = 0; i < attractPoints->size(); i++){

float lenSq = ( attractPoints->at(i)-pos ).lengthSquared();

if( lenSq < closestDist ){

closestDist = lenSq;

closest = i;

}

}

//附加指向點(diǎn)的力

if( closest != -1 ){

closestPt = attractPoints->at(closest);

float dist = sqrt(closestDist);

//使力與距離成比例先舷。

frc = closestPt - pos;

vel *= drag;

//f控制受力距離

if( dist < 300 && dist > 40 && !ofGetKeyPressed('f') ){

vel += frc * 0.003;

}else{

frc.x = ofSignedNoise(uniqueVal, pos.y * 0.01, ofGetElapsedTimef()*0.2);

frc.y = ofSignedNoise(uniqueVal, pos.x * 0.01, ofGetElapsedTimef()*0.2);

vel += frc * 0.4;

}

}

}

}

//刷新位子

pos += vel;

if( pos.x > ofGetWidth() ){

pos.x = ofGetWidth();

vel.x *= -1.0;

}else if( pos.x < 0 ){

pos.x = 0;

vel.x *= -1.0;

}

if( pos.y > ofGetHeight() ){

pos.y = ofGetHeight();

vel.y *= -1.0;

}

else if( pos.y < 0 ){

pos.y = 0;

vel.y *= -1.0;

}

}

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

void demoParticle::draw(){

testphoto.draw(pos.x- scale * 50, pos.y - scale * 50, scale*100, scale*100);

ofSetColor(250, 250, 250);

ofDrawCircle(handPoint.x, handPoint.y, 30);

if( mode == PARTICLE_MODE_ATTRACT ){

ofSetColor(255, 63, 180);

}

else if( mode == PARTICLE_MODE_REPEL ){

ofSetColor(208, 255, 63);

}

else if( mode == PARTICLE_MODE_NOISE ){

ofSetColor(99, 63, 255);

}

else if( mode == PARTICLE_MODE_NEAREST_POINTS ){

ofSetColor(103, 160, 237);

}

ofDrawCircle(pos.x, pos.y, scale * 4.0);

}

void demoParticle::drawflower(int x,int y,int radious)

{

}

課后感想:

感覺中間的一些難點(diǎn)還是在將兩個系統(tǒng)搭建在一起的時候,因?yàn)閮蓚€系統(tǒng)都是持續(xù)觸發(fā)的滓侍,所以一起運(yùn)行的時候總有些錯誤蒋川,不過后來好在都解決了。

手部識別的判定還是很糟撩笆,一方面是我這個電腦的攝像頭不怎么樣捺球,另一方面,關(guān)于形態(tài)學(xué)識別的部分還是不夠完好夕冲,如果用kinect的話就不用自己寫手部追蹤的部分了

粒子系統(tǒng)雖然用的范例氮兵,但還是有我自己的創(chuàng)新,如導(dǎo)入圖片和對手部點(diǎn)的讀取判斷歹鱼,受限于電腦性能泣栈,處理的粒子不多,而且也很卡弥姻,程序運(yùn)行在x64的平臺上就不流暢南片,不曉得是什么原因。

感覺openframework實(shí)現(xiàn)的效果還蠻不錯的庭敦,就是相關(guān)的教程資料很少疼进,只有官網(wǎng)上有,再就是看example里的代碼秧廉,估計以后還會繼續(xù)玩openframework伞广,希望能做出更棒的作品

導(dǎo)入的草莓png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拣帽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嚼锄,更是在濱河造成了極大的恐慌诞外,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灾票,死亡現(xiàn)場離奇詭異峡谊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)刊苍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門既们,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人正什,你說我怎么就攤上這事啥纸。” “怎么了婴氮?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵斯棒,是天一觀的道長。 經(jīng)常有香客問我主经,道長荣暮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任罩驻,我火速辦了婚禮穗酥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惠遏。我一直安慰自己砾跃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布节吮。 她就那樣靜靜地躺著抽高,像睡著了一般。 火紅的嫁衣襯著肌膚如雪透绩。 梳的紋絲不亂的頭發(fā)上翘骂,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音渺贤,去河邊找鬼雏胃。 笑死,一個胖子當(dāng)著我的面吹牛志鞍,可吹牛的內(nèi)容都是我干的瞭亮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼固棚,長吁一口氣:“原來是場噩夢啊……” “哼统翩!你這毒婦竟也來了仙蚜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤厂汗,失蹤者是張志新(化名)和其女友劉穎委粉,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娶桦,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贾节,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了衷畦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栗涂。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖祈争,靈堂內(nèi)的尸體忽然破棺而出斤程,到底是詐尸還是另有隱情,我是刑警寧澤菩混,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布忿墅,位于F島的核電站,受9級特大地震影響沮峡,放射性物質(zhì)發(fā)生泄漏保礼。R本人自食惡果不足惜壹蔓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一谎倔、第九天 我趴在偏房一處隱蔽的房頂上張望茅糜。 院中可真熱鬧,春花似錦秘症、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至采转,卻和暖如春聪廉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背故慈。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工板熊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人察绷。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓干签,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拆撼。 傳聞我的和親對象是個殘疾皇子容劳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容