【问题标题】:kinect depth image processingkinect 深度图像处理
【发布时间】:2013-05-16 22:37:04
【问题描述】:

这是我的问题

Kinect 安装在房间顶部(天花板上)。然后我拍摄了 kinect 下方人员的深度图像。

所以我得到的是下面人物的俯视图。

那我要提取人头来统计人数。

在我看来,这个问题需要识别图像的 LOCAL 最小区域。但我想不出办法。

有人可以建议我实现这一目标的方法吗?

有没有获取局部最小区域的 OpenCV 函数??

谢谢。

【问题讨论】:

  • 您是否使用深度图像来查找局部最小值?或者你在用 RGB 图像做什么?
  • 我正在使用深度图像来寻找局部最小区域
  • 是人们所处的场景,是静态的吗?
  • 假设它是静态图像。人头的静态深度图像

标签: c++ image-processing kinect


【解决方案1】:

您可以尝试watershed transform 来查找局部最小值。快速搜索找到了这个sample code,您可能想用 OpenCV 尝试一下。

【讨论】:

  • 感谢您的回复。分水岭算法需要一个点来操作。在我的应用程序中,我无法为算法提供任何输入。
【解决方案2】:

我会进行前景-背景分割,将静态背景与动态“前景”(人物)分开。

然后,一旦你有了人的点云/深度图,你就可以用一些区域增长 (flood fill) 方法对它们进行分割。这样你就可以得到分开的人,如果你专门寻找人头,你可以计算或找到他们的最低点。

【讨论】:

  • 感谢您的回复。我已经在做你建议的事情了。但是如果两个人非常接近,那么你的方法会将他们识别为一个人。
【解决方案3】:

我会采用简单的方法,例如对近深度和远深度进行阈值处理,使用 and 操作将两者合并并在结果图像中找到轮廓。

它不是超级灵活,因为您需要对深度范围(预期的最低人体高度)进行硬编码,但它很容易设置/调整,并且计算成本不应该那么高。或者,您可以使用一些模糊和侵蚀/扩张来帮助细化轮廓。

虽然它比我解释的要多,你可以看一个演示here

这是一个使用 OpenCV 和 OpenNI 的基本示例:

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

int threshNear = 60;
int threshFar = 100;
int dilateAmt = 1;
int erodeAmt = 1;
int blurAmt = 1;
int blurPre = 1;
void on_trackbar(int, void*){}

int main( )
{
    VideoCapture capture;
    capture.open(CV_CAP_OPENNI);
    if( !capture.isOpened() )
    {
        cout << "Can not open a capture object." << endl;
        return -1;
    }
    cout << "ready" << endl;
    vector<vector<Point> > contours;
    namedWindow("depth map");
    createTrackbar( "amount dilate", "depth map", &dilateAmt,16, on_trackbar );
    createTrackbar( "amount erode", "depth map", &erodeAmt,16, on_trackbar );
    createTrackbar( "amount blur", "depth map", &blurAmt,16, on_trackbar );
    createTrackbar( "blur pre", "depth map", &blurPre,1, on_trackbar );
    createTrackbar( "threshold near", "depth map", &threshNear,255, on_trackbar );
    createTrackbar( "threshold far", "depth map", &threshFar,255, on_trackbar );
    for(;;)
    {
        Mat depthMap;
        if( !capture.grab() )
        {
            cout << "Can not grab images." << endl;
            return -1;
        }
        else
        {
            if( capture.retrieve( depthMap, CV_CAP_OPENNI_DEPTH_MAP ) )
            {
                const float scaleFactor = 0.05f;
                Mat show; depthMap.convertTo( show, CV_8UC1, scaleFactor );
                //threshold
                Mat tnear,tfar;
                show.copyTo(tnear);
                show.copyTo(tfar);
                threshold(tnear,tnear,threshNear,255,CV_THRESH_TOZERO);
                threshold(tfar,tfar,threshFar,255,CV_THRESH_TOZERO_INV);
                show = tnear & tfar;//or cvAnd(tnear,tfar,show,NULL); to join the two thresholded images
                //filter
                if(blurPre == 1) blur(show,show,Size(blurAmt+1,blurAmt+1));
                Mat cntr; show.copyTo(cntr);
                erode(cntr,cntr,Mat(),Point(-1,-1),erodeAmt);
                if(blurPre == 0) blur(cntr,cntr,Size(blurAmt+1,blurAmt+1));
                dilate(cntr,cntr,Mat(),Point(-1,-1),dilateAmt);

                //compute and draw contours
                findContours(cntr,contours,0,1);
                drawContours(cntr,contours,-1,Scalar(192,0,0),2,3);

                //optionally compute bounding box and circle to exclude small blobs(non human) or do further filtering,etc.
                int numContours = contours.size();
                vector<vector<Point> > contours_poly( numContours );
                vector<Rect> boundRect( numContours );
                vector<Point2f> centers( numContours );
                vector<float> radii(numContours);
                for(int i = 0; i < numContours; i++ ){
                    approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
                    boundRect[i] = boundingRect( Mat(contours_poly[i]) );
                    minEnclosingCircle(contours_poly[i],centers[i],radii[i]);
                    rectangle( cntr, boundRect[i].tl(), boundRect[i].br(), Scalar(64), 2, 8, 0 );
                    circle(cntr,centers[i],radii[i],Scalar(192));
                 }

                imshow( "depth map", show );
                imshow( "contours", cntr );
            }

        }

        if( waitKey( 30 ) == 27 ) break;//exit on esc
    }
}

即使您不使用 OpenNI 来获取深度流,您仍然可以将深度图像插入 OpenCV。此外,您可以检测边界框和圆圈,这可能有助于进一步过滤事物。假设您设置在办公空间中,您可能希望避开柱子、高大的植物、架子等,以便检查边界圆的半径或边界框的宽高比。

【讨论】:

  • 感谢您的回复。这个方法也可以。但不像你提到的那样灵活。如果两个或更多人彼此靠近,此算法将失败。
  • true,也取决于高度和阈值。如果你在一个无聊的场景中围绕头部设置阈值,你可能不会遇到 blob 合并,但如果人们拥抱/亲吻/其他两个头在一起的情况,你会遇到。