1

I was wondering if it is possible to find the dimensions (in pixel) of a cube/cuboid in an image like the one shown below?

I know its nearly impossible because of no information about the depth,the viewing angle, etc. But at least can one find the appropriate corners of the cube so that the length, width and height can be approximated?

Any type help or information would be appreciated.

Thanks in advance.

abie
  • 23
  • 6

1 Answers1

1

I guess I could suggest a solution to the "at least" part of the question. You can find the corners of the cube by finding the lines in the image.

Firstly, find the edges in the image. If the target images are as plain and clear as the provided one, finding edges must be straighforward. Use cv::Canny().

cv::Mat img = cv::imread("cube.png");
cv::Mat edges;
cv::Canny(img, edges, 20, 60);

img to edges

Secondly, in the edges image, detect the straight lines. Use either cv::HoughLines() or cv::HoughLinesP(). Here, I proceed with the former one:

std::vector<cv::Vec2f> lines;
cv::HoughLines(edges, lines, 0.6, CV_PI / 120, 50);

Plaese refer to the on the OpenCV documentation on Hough lines. I also took the code for the visualization from there.

edges to hough

The cv::HoughLines() function detects straight lines and, for each line, returns 2 values (ρ - distance, and θ - rotation angle) which define this line's equation in polar coordinates. This function would often return several lines for one source edge (as it did for a couple of lines here). In our case, we can remove such duplicates by filtering lines with the very close ρ values.

The benefit of our case is that the sides of the cube resposible for each dimension (length, width, and height) will have the same rotation angle θ in found line equations. For instance, we can expect vertical sides of the cube (responsible for the height dimension) to remain vertical and have their θ close to 0 or π (see the OpenCV documentation). We could find such lines in the vector of the detected Hough lines:

std::vector<cv::Vec2f> vertical_lines;
std::copy_if(lines.begin(), lines.end(), std::back_inserter(vertical_lines), [](cv::Vec2f line) {
    //copy if θ is near 0 or CV_PI
    return ((0 < line[1]) && (line[1] < 0 + CV_PI / 10)) ||
           ((line[1] < CV_PI) && (line[1] > CV_PI - CV_PI / 10));
});

lines to vertical lines

The same reasoning applies to finding the lines for the rest of the cube sides. Just filter the found Hough lines by appropriate θ.

Now that we have the equations of the lines of our interest, we can find their corresponding edge pixels (not optimal code below, just demo):

std::vector<cv::Point> non_zero_points;
cv::findNonZero(edges, non_zero_points);

std::vector<std::vector<cv::Point>> corresponding_points(vertical_lines.size());
for (int i = 0; i < vertical_lines.size(); ++i)
    for (auto point : non_zero_points)
        if (abs(cos(vertical_lines[i][1])*point.x + sin(vertical_lines[i][1])*point.y - vertical_lines[i][0]) < 2)
            corresponding_points[i].push_back(point);

enter image description here

Now, for each found cluster find the top-most, the bottom-most points (or left-most/right-most for the other sides) and get your cube corners.

Please note the pixel I denoted by exclamation marks. It got accidently sorted to one of the vertical Hough lines, but it actually belongs to a non-vertical top side. It needs to be removed, by some outlier detection or by some other approach to the corresponding pixel search.

About retreiving actual lengths of the sides: to my knowledge, it is really a non-trivial problem. Maybe this SO question would be a good place to start.

kazarey
  • 814
  • 1
  • 15
  • 32
  • That's a really nice approach. Actually, I was thinking to go for corner detection. What are your thoughts about that? – abie Jun 04 '17 at 19:15
  • It sounds like a solution, but in my hands `cornerHarris()` would always lose some genuine corners and find false corners on the cube edges. My guess, that's because of the green outline of the cube which confuses `Sobel()` under the hood. Line detection may be bulky, but it feels more robust to me. But, surely, there could be a way to make corner detection work robustly as well. – kazarey Jun 04 '17 at 19:55
  • It just hit me: you could apply `cornerHarris()` to the `Canny()` output. And I have managed to tweak its parameters so that it yields accurate corners - it's `cornerHarris(canny,dst,7,7,0.04)`. Though other image may require different parameters. But still, to recap, corner detection may very well be another way to go. – kazarey Jun 04 '17 at 20:15
  • Thanks for the help. I used both the corners and the lines into a correlation matrix to get the accurate corners of the cube. After that, just the basic geometrical rules were suffice to build the 3D model. Thanks – abie Jun 06 '17 at 17:55