這是很好你對齊的RGB和深度流。 有可能在效率方面得到改善幾件事情:
無需重新加載一個黑色圖像的每一個幀(抽獎()循環),因爲你無論如何修改的所有像素:
mask = loadImage("black640.jpg"); //just a black image
而且,因爲你不需要的X,Y座標,你通過用戶數據循環,你可以使用一個for循環應該是快了一點:
for(int i = 0 ; i < numPixels ; i++){
mask.pixels[i] = userMap[i] > 0 ? color(255) : color(0);
}
代替:
for (int y = 0; y < ySize; y++) {
for (int x = 0; x < xSize; x++) {
int index = x + y*xSize;
if (userMap[index]>0) {
mask.pixels[index]=color(255, 255, 255);
}
}
}
你可以做的另一件事哈克是檢索userImage()
代替userData()
從SimpleOpenNI,並應用THRESHOLD
過濾器給它,這在理論上應該給你同樣的結果如上。
例如:
int[] userMap = context.userMap();
background(0, 0, 0);
mask = loadImage("black640.jpg"); //just a black image
int xSize = context.depthWidth();
int ySize = context.depthHeight();
mask.loadPixels();
for (int y = 0; y < ySize; y++) {
for (int x = 0; x < xSize; x++) {
int index = x + y*xSize;
if (userMap[index]>0) {
mask.pixels[index]=color(255, 255, 255);
}
}
}
可能是:
mask = context.userImage();
mask.filter(THRESHOLD);
在濾波方面,如果你要收縮的輪廓,你應該ERODE
和bluring應該給你一點是Photoshop的像羽化。
注意某些filter()調用帶參數(如BLUR
),但其他人不喜歡ERODE
/DILATE
形態濾波器,但你仍然可以推出自己的循環來面對這一切。
我還推薦在玩過濾器時有一些容易調整的界面(可以是花式滑塊或簡單的鍵盤快捷鍵)。
這裏是在重構草圖粗略的嘗試與上述評論:
import SimpleOpenNI.*;
SimpleOpenNI context;
PImage mask;
int numPixels = 640*480;
int dilateAmt = 1;
int erodeAmt = 1;
int blurAmt = 0;
void setup()
{
size(640*2, 480);
context = new SimpleOpenNI(this);
if (context.isInit() == false)
{
exit();
return;
}
context.enableDepth();
context.enableRGB();
context.enableUser();
context.alternativeViewPointDepthToImage();
mask = createImage(640,480,RGB);
}
void draw()
{
frame.setTitle(int(frameRate) + " fps");
context.update();
int[] userMap = context.userMap();
background(0, 0, 0);
//you don't need to keep reloading the image every single frame since you're updating all the pixels bellow anyway
// mask = loadImage("black640.jpg"); //just a black image
// mask.loadPixels();
// int xSize = context.depthWidth();
// int ySize = context.depthHeight();
// for (int y = 0; y < ySize; y++) {
// for (int x = 0; x < xSize; x++) {
// int index = x + y*xSize;
// if (userMap[index]>0) {
// mask.pixels[index]=color(255, 255, 255);
// }
// }
// }
//a single loop is usually faster than a nested loop and you don't need the x,y coordinates anyway
for(int i = 0 ; i < numPixels ; i++){
mask.pixels[i] = userMap[i] > 0 ? color(255) : color(0);
}
//erode
for(int i = 0 ; i < erodeAmt ; i++) mask.filter(ERODE);
//dilate
for(int i = 0 ; i < dilateAmt; i++) mask.filter(DILATE);
//blur
mask.filter(BLUR,blurAmt);
mask.updatePixels();
//preview the mask after you process it
image(mask, 0, 0);
PImage rgb = context.rgbImage();
rgb.mask(mask);
image(rgb, context.depthWidth() + 10, 0);
//print filter values for debugging purposes
fill(255);
text("erodeAmt: " + erodeAmt + "\tdilateAmt: " + dilateAmt + "\tblurAmt: " + blurAmt,15,15);
}
void keyPressed(){
if(key == 'e') erodeAmt--;
if(key == 'E') erodeAmt++;
if(key == 'd') dilateAmt--;
if(key == 'D') dilateAmt++;
if(key == 'b') blurAmt--;
if(key == 'B') blurAmt++;
//constrain values
if(erodeAmt < 0) erodeAmt = 0;
if(dilateAmt < 0) dilateAmt = 0;
if(blurAmt < 0) blurAmt = 0;
}
可惜我不能與實際傳感器測試,現在,所以請使用的概念解釋,但要注意充分裸露草圖代碼未經測試。
上面的草圖(如果它運行)應該允許您使用鍵來控制過濾器參數(e/E降低/增加侵蝕,d/D擴張,b/B模糊)。希望你會得到滿意的結果。
在使用SimpleOpenNI時,我一般建議錄製一個。oni文件(查看RecorderPlay示例)最常見的用例。這樣可以爲您節省一些測試時間,並允許您在傳感器分離的情況下進行遠程工作。有一點要記住,深度分辨率減少到記錄的一半(但使用usingRecording
布爾標誌應該保持安全)
最後也可能是最重要的一點是關於最終結果的質量。如果源圖像不容易處理,您的結果圖像不會好得多。原始Kinect傳感器的深度數據不是很好。華碩傳感器感覺稍微穩定一點,但在大多數情況下,差異仍然可以忽略不計。如果您要堅持使用其中一種傳感器,請確保您有清晰的背景和體面的照明(沒有太多直接的暖光(陽光,白熾燈泡等),因爲它們可能會干擾傳感器)
如果你想要更精確的用戶剪切,並且上面的過濾不能得到你想要的結果,請考慮切換到更好的傳感器,如KinectV2。深度質量好得多,傳感器不易受溫暖的光照。這可能意味着你需要使用Windows(我看到有一個KinectPV2包裝可用)或OpenFrameworks(類似於處理的庫的C++集合),ofxKinectV2
好點,關於OpenCV和你使用的包裝是相當不錯的。我應該從一開始就建議這樣做(但試圖用依賴關係來簡化事情)。 –