6
votes

-- Update 2 --

The following article is really useful (although it is using Python instead of C++) if you are using a single camera to calculate the distance: Find distance from camera to object/marker using Python and OpenCV

Best link is Stereo Webcam Depth Detection. The implementation of this open source project is really clear.

Below is the original question.


For my project I am using two camera's (stereo vision) to track objects and to calculate the distance. I calibrated them with the sample code of OpenCV and generated a disparity map.

I already implemented a method to track objects based on color (this generates a threshold image).

My question: How can I calculate the distance to the tracked colored objects using the disparity map/ matrix?

Below you can find a code snippet that gets the x,y and z coordinates of each pixel. The question: Is Point.z in cm, pixels, mm?

Can I get the distance to the tracked object with this code?

Thank you in advance!

cvReprojectImageTo3D(disparity, Image3D, _Q);

vector<CvPoint3D32f> PointArray;
CvPoint3D32f Point;

for (int y = 0; y < Image3D->rows; y++) {    

    float *data = (float *)(Image3D->data.ptr + y * Image3D->step);  

    for (int x = 0; x < Image3D->cols * 3; x = x + 3) 
    {   
        Point.x = data[x];        
        Point.y =  data[x+1];     
        Point.z = data[x+2];
        PointArray.push_back(Point);
        //Depth > 10
        if(Point.z > 10)
        {
            printf("%f %f %f", Point.x, Point.y, Point.z);              
        }
    }
}
cvReleaseMat(&Image3D);

--Update 1--

For example I generated this thresholded image (of the left camera). I almost have the same of the right camera.

enter image description here

Besides the above threshold image, the application generates a disparity map. How can I get the Z-coordinates of the pixels of the hand in the disparity map?

I actually want to get all the Z-coordinates of the pixels of the hand to calculate the average Z-value (distance) (using the disparity map).

3

3 Answers

2
votes

The math for converting disparity (in pixels or image width percentage) to actual distance is pretty well documented (and not very difficult) but I'll document it here as well.

Below is an example given a disparity image (in pixels) and an input image width of 2K (2048 pixels across) image:

Convergence Distance is determined by the rotation between camera lenses. In this example it will be 5 meters. Convergence distance of 5 (meters) means that the disparity of objects 5 meters away is 0.

CD = 5 (meters)        

Inverse of convergence distance is: 1 / CD

IZ = 1/5 = 0.2M

Size of camera's sensor in meters

SS  = 0.035 (meters)    //35mm camera sensor

The width of a pixel on the sensor in meters

PW = SS/image resolution = 0.035 / 2048(image width) = 0.00001708984

The focal length of your cameras in meters

FL = 0.07 //70mm lens

InterAxial distance: The distance from the center of left lens to the center of right lens

IA = 0.0025 //2.5mm

The combination of the physical parameters of your camera rig

A = FL * IA / PW

Camera Adjusted disparity: (For left view only, right view would use positive [disparity value])

AD = 2 * (-[disparity value] / A) 

From here you can compute actual distance using the following equation:

realDistance = 1 / (IZ – AD)

This equation only works for "toe-in" camera systems, parallel camera rigs will use a slightly different equation to avoid infinity values, but I'll leave it at this for now. If you need the parallel stuff just let me know.

0
votes
if len(puntos) == 2:
    x1, y1, w1, h1 = puntos[0]
    x2, y2, w2, h2 = puntos[1]
    
    if x1 < x2:
        distancia_pixeles = abs(x2 - (x1+w1)) 
        distancia_cm = (distancia_pixeles*29.7)/720
        cv2.putText(imagen_A4, "{:.2f} cm".format(distancia_cm), (x1+w1+distancia_pixeles//2, y1-30), 2, 0.8, (0,0,255), 1,

cv2.LINE_AA) cv2.line(imagen_A4,(x1+w1,y1-20),(x2, y1-20),(0, 0, 255),2) cv2.line(imagen_A4,(x1+w1,y1-30),(x1+w1, y1-10),(0, 0, 255),2) cv2.line(imagen_A4,(x2,y1-30),(x2, y1-10),(0, 0, 255),2) else: distancia_pixeles = abs(x1 - (x2+w2)) distancia_cm = (distancia_pixeles*29.7)/720 cv2.putText(imagen_A4, "{:.2f} cm".format(distancia_cm), (x2+w2+distancia_pixeles//2, y2-30), 2, 0.8, (0,0,255), 1, cv2.LINE_AA) cv2.line(imagen_A4,(x2+w2,y2-20),(x1, y2-20),(0, 0, 255),2) cv2.line(imagen_A4,(x2+w2,y2-30),(x2+w2, y2-10),(0, 0, 255),2) cv2.line(imagen_A4,(x1,y2-30),(x1, y2-10),(0, 0, 255),2)

        cv2.imshow('imagen_A4',imagen_A4)

    cv2.imshow('frame',frame)    
    k = cv2.waitKey(1) & 0xFF
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()

I think this is a good way to measure the distance between two objects