2011-01-21 15 views
5

Tôi đang chơi với trình điều khiển Kinect, CL NUI và cố gắng lấy độ sâu tương đối của các mục.Sử dụng trình điều khiển CL NUI Kinect, chuyển đổi độ sâu màu thành khoảng cách tương đối thực tế

Thư viện cung cấp cách để có được hình ảnh thể hiện độ sâu của một đối tượng trên màn hình. Dưới đây là ví dụ:
Kinect Depth Image

Có cách nào dễ dàng để chuyển đổi từ màu pixel sang độ sâu hình ảnh không? Ví dụ: màu gần nhất có thể có độ sâu là 0 và màu xa nhất có thể là độ sâu 1.

Có ai biết cách thực hiện điều đó không?

tôi thấy những cacluations về cách chuyển đổi các dữ liệu chiều sâu cho màu sắc, những gì tôi muốn là nghịch đảo:

float RawDepthToMeters(int depthValue) 
{ 
    if (depthValue < 2047) 
    { 
     return float(1.0/(double(depthValue) * -0.0030711016 + 3.3309495161)); 
    } 
    return 0.0f; 
} 

Vec3f DepthToWorld(int x, int y, int depthValue) 
{ 
    static const double fx_d = 1.0/5.9421434211923247e+02; 
    static const double fy_d = 1.0/5.9104053696870778e+02; 
    static const double cx_d = 3.3930780975300314e+02; 
    static const double cy_d = 2.4273913761751615e+02; 

    Vec3f result; 
    const double depth = RawDepthToMeters(depthValue); 
    result.x = float((x - cx_d) * depth * fx_d); 
    result.y = float((y - cy_d) * depth * fy_d); 
    result.z = float(depth); 
    return result; 
} 

Vec2i WorldToColor(const Vec3f &pt) 
{ 
    static const Matrix4 rotationMatrix(
          Vec3f(9.9984628826577793e-01f, 1.2635359098409581e-03f, -1.7487233004436643e-02f), 
          Vec3f(-1.4779096108364480e-03f, 9.9992385683542895e-01f, -1.2251380107679535e-02f), 
          Vec3f(1.7470421412464927e-02f, 1.2275341476520762e-02f, 9.9977202419716948e-01f)); 
    static const Vec3f translation(1.9985242312092553e-02f, -7.4423738761617583e-04f, -1.0916736334336222e-02f); 
    static const Matrix4 finalMatrix = rotationMatrix.Transpose() * Matrix4::Translation(-translation); 

    static const double fx_rgb = 5.2921508098293293e+02; 
    static const double fy_rgb = 5.2556393630057437e+02; 
    static const double cx_rgb = 3.2894272028759258e+02; 
    static const double cy_rgb = 2.6748068171871557e+02; 

    const Vec3f transformedPos = finalMatrix.TransformPoint(pt); 
    const float invZ = 1.0f/transformedPos.z; 

    Vec2i result; 
    result.x = Utility::Bound(Math::Round((transformedPos.x * fx_rgb * invZ) + cx_rgb), 0, 639); 
    result.y = Utility::Bound(Math::Round((transformedPos.y * fy_rgb * invZ) + cy_rgb), 0, 479); 
    return result; 
} 

My Matrix Math là yếu, và tôi không chắc chắn làm thế nào để đảo ngược sự tính toán.

Trả lời

3

Tôi đã tìm ra giải pháp.

Giá trị độ sâu được lưu trữ trong hình ảnh CLNUIDevice.GetCameraDepthFrameRAW. Màu của hình ảnh này được tạo từ giá trị độ sâu 11 bit. I E. bạn có 24 bit cho màu RGB (32 nếu ARGB). Để có được chiều sâu, bạn cần phải cắt bớt các bit không cần thiết như thế này:

private int colorToDepth(Color c) { 
     int colorInt = c.ToArgb(); 

     return (colorInt << 16) >> 16; 
    } 

Bạn sử dụng 16, vì số 11 bit được đệm 0 cho vị trí 16 bit. I E. bạn có một số trông như thế này: 1111 1111 0000 0 ### #### #### trong đó 1 là kênh alpha, số không là phần đệm và '#' là giá trị thực. Bitshifting bên trái 16 lá bạn với 0000 0 ### #### #### 0000 0000, mà bạn muốn đẩy trở lại chuyển của tôi sang phải 16 lần: 0000 0000 0000 0 ### #### # ####

+0

Bitwise VÀ nó với 0x7FF – CWMan

0

Sửa lỗi nếu tôi sai nhưng từ những gì tôi hiểu mã của bạn nhận mảng sâu từ Kinect, chuyển đổi nó thành đối tượng "thế giới" (với toạ độ x, y, z) sử dụng DepthToWorld, sau đó chuyển đổi thành mảng màu 2D sử dụng WorldToColor. Từ đó, bạn đang cố gắng lấy khoảng cách (tính bằng mét) của mỗi pixel tương ứng với Kinect. Đúng?

Vậy tại sao bạn không lấy mảng chiều sâu ban đầu mà bạn nhận được từ Kinect và gọi hàm RawDepthToMeters trên mỗi pixel?

Đảo ngược các hoạt động được thực hiện bởi mã của bạn ngay trước đây là mất mát lớn về hiệu suất ...

+0

Đó là bên trong thư viện, tôi chỉ nhận được kết quả màu. – Malfist