How should I measure a object accurately using camera from any distance

image

Your question is pretty open-ended. A few questions come to mind right away:

  1. What do you mean by measure?
  2. What do you mean by accurately? +/- 10%?
  3. How are the objects boundaries designated? Fully automatic? User-guided? Fully manual?

If you want to use a camera to measure lengths / areas in units like inches, meters, etc (as opposed to pixels, or some relative units) you will have to calibrate the camera. First calibrate the camera intrinsics (see cv::calibrateCamera() which characterizes the fixed (assuming you don’t change focus or zoom etc) parameters of the camera. Focal length and image center - these are necessary to model the geometric relationship between “world” points and where they project to the image plane. Additionally calibrating the camera will estimate the optical distortion (which is clearly present in your image) - correcting for distortion is important if you want accurate (as defined by me) measurements.

Once you have a calibrated camera, it is possible to convert lengths in the image (in pixels) to lengths in inches, cm, etc. - with a catch. You have to know the distance and orientation of the object in the camera reference frame… Your question said “from any distance” - so you need a way to get that. The general approach is to calibrate the object position/orientation in the camera frame - look at solvePnP() for that. Note that you will need world reference points (known 3D locations) and the corresponding image locations.

There are less general ways to go about this, which don’t require a full calibration of the camera or the object pose. Based on the one image you provided, it looks like the objects you want to measure all lie in the same (approximate) plane in world space. If so, you can get started by computing a homography that describes how world points map to image points. You can do this with a list of world points with their corresponding image points - for example the corners of the box(?) that frames whatever it is you are looking at. see cv::findHomography() for details on that.

Simplifying even further, if you not only have a planar surface you are imaging, but also know that the camera optical axis is perfectly perpendicular to that plane (hint: it isn’t, but it might be close enough, depending again on what you mean by accurately), you could add an object of known length to the objects you are imaging, and just use a scale factor from pixels to whatever units you want.

I suspect you will need to correct for the distortion of your lens (or get a lens with minimal distortion) in order to get results you find satisfactory.

So, the easiest way is to get a low distortion lens, ensure your camera is pointed perpendicular to the world plane, and use an object of known length to compute a scale factor from pixels to cm (or whatever), then apply that scale factor to distances measured in the image (pixels).

The best way is to calibrate the camera intrinsics, including optical distortion, and using solvePnP to get the pose (rotation & translation) of the object in the camera frame (using some world reference with known dimensions, like the “box” that contains your objects of interest.)

If you objects aren’t all in the same plane, things get more complicated.

If you have visions of doing all of this automagically (isolating the objects, creating a boundary for each etc.), that’s a whole different ball of wax (and is orthogonal from the camera calibration process).