Measuring the size of an object using a reference object in a photograph

I would like to calculate the size of the object in the photo, which includes both the target and the reference.

I think I would like to do what this software achieves (I don't know how accurate this software is) https://itunes.apple.com/us/app/photo-meter-picture-measuring/id579961082? mt = 8

I have already found, in general, this is called photogrammetry and seems to be an active field of research.

How would you find the height of the objects set for the image? https://physics.stackexchange.com/questions/151121/can-i-calculate-the-size-of-a-real-object-by-just-looking-at-the-picture-taken-b

But I can not find

  • which is the main way to measure an object in a photograph using a reference object.
  • a way to implement it or standard open source code for it.

Update

  • I can not use the distance from the object and the link from the camera.
  • Link and target are on (approximately) the same plane.
+4
source share
2 answers

Due to your assumption, Link and target are on (approximately) the same plane. you can apply the method "Algorithm 1: flat measurements" described in

. " : (Invited Paper) ". : . . 2449. . Berlin Heidelberg, 2002, pp. 224-239.

, .

P=H*p (1)

p - , , p - 3D- , , H - 3x3, , * - -.

    h11 h12 h13
H = h21 h22 h23
    h31 h32 h33

p - , , , p ​​ r c, [r,c,1]. p , , , 3D- Z=0 p [X,Y,1].

, " 1: ". :

  • H. , 9 H .

  • p1=[r1,c1,1] p2=[r2,c2,1], .

  • (1), P1 P2. -, , . , P1=[X1,Y1,1] - P1=[(c1*h_12 + h_11*r1 + h_13)/(c1*h_32 + h_31*r1 + h_33),(c1*h_22 + h_21*r1 + h_23)/(c1*h_32 + h_31*r1 + h_33),1]. , H , , X1, Y1, X2, Y2 .

  • r P1 P2, R=sqrt(pow(X1-X2,2)+pow(Y1-Y2,2), r . , P1 P2 , , , , , M.

  • s s=M/R, s .

  • H s G . G .

  • p3 p4, .

  • Back-project p3 p4 G, p3 p4. P3=G*p3 P4=G*p4. . P3=[X3,Y3,1] P4=[X4,Y4,1], X3, Y3, X4 Y4 .

  • D p3 p4, D=sqrt(pow(X3-X4,2)+pow(Y3-Y4,2). D .

, H , , OpenCV cv::findHomography: .

, H,

JOHNSON, Micah K.; , . . . Sci., Dartmouth College, Tech. TR2006-579, 2006.

,

. Criminisi. . . Springer-Verlag London Ltd., 2001 . ISBN: 1852334681.

++ OpenCV:

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


void to_homogeneous(const std::vector< cv::Point2f >& non_homogeneous, std::vector< cv::Point3f >& homogeneous )
{
    homogeneous.resize(non_homogeneous.size());
    for ( size_t i = 0; i < non_homogeneous.size(); i++ ) {
        homogeneous[i].x = non_homogeneous[i].x;
        homogeneous[i].y = non_homogeneous[i].y;
        homogeneous[i].z = 1.0;
    }
}

void from_homogeneous(const std::vector< cv::Point3f >& homogeneous, std::vector< cv::Point2f >& non_homogeneous )
{
    non_homogeneous.resize(homogeneous.size());
    for ( size_t i = 0; i < non_homogeneous.size(); i++ ) {
        non_homogeneous[i].x = homogeneous[i].x / homogeneous[i].z;
        non_homogeneous[i].y = homogeneous[i].y / homogeneous[i].z;
    }
}

void draw_cross(cv::Mat &img, const cv::Point center, float arm_length, const cv::Scalar &color, int thickness = 5 )
{
    cv::Point N(center - cv::Point(0, arm_length));
    cv::Point S(center + cv::Point(0, arm_length));
    cv::Point E(center + cv::Point(arm_length, 0));
    cv::Point W(center - cv::Point(arm_length, 0));
    cv::line(img, N, S, color, thickness);
    cv::line(img, E, W, color, thickness);
}

double measure_distance(const cv::Point2f& p1, const cv::Point2f& p2, const cv::Matx33f& GG)
{
    std::vector< cv::Point2f > ticks(2);
    ticks[0] = p1;
    ticks[1] = p2;
    std::vector< cv::Point3f > ticks_h;
    to_homogeneous(ticks, ticks_h);

    std::vector< cv::Point3f > world_ticks_h(2);
    for ( size_t i = 0; i < ticks_h.size(); i++ ) {
        world_ticks_h[i] = GG * ticks_h[i];
    }
    std::vector< cv::Point2f > world_ticks_back;
    from_homogeneous(world_ticks_h, world_ticks_back);

    return cv::norm(world_ticks_back[0] - world_ticks_back[1]);
}

int main(int, char**)
{
    cv::Mat img = cv::imread("single-view-metrology.JPG");
    std::vector< cv::Point2f > world_tenth_of_mm;
    std::vector< cv::Point2f > img_px;

    // Here I manually picked the pixels coordinates of the corners of the A4 sheet.
    cv::Point2f TL(711, 64);
    cv::Point2f BL(317, 1429);
    cv::Point2f TR(1970, 175);
    cv::Point2f BR(1863, 1561);

    // This is the standard size of the A4 sheet:
    const int A4_w_mm = 210;
    const int A4_h_mm = 297;
    const int scale = 10;

    // Here I create the correspondences between the world point and the
    // image points.
    img_px.push_back(TL);
    world_tenth_of_mm.push_back(cv::Point2f(0.0, 0.0));

    img_px.push_back(TR);
    world_tenth_of_mm.push_back(cv::Point2f(A4_w_mm * scale, 0.0));

    img_px.push_back(BL);
    world_tenth_of_mm.push_back(cv::Point2f(0.0, A4_h_mm * scale));

    img_px.push_back(BR);
    world_tenth_of_mm.push_back(cv::Point2f(A4_w_mm * scale, A4_h_mm * scale));

    // Here I estimate the homography that brings the world to the image.
    cv::Mat H = cv::findHomography(world_tenth_of_mm, img_px);

    // To back-project the image points into the world I need the inverse of the homography.
    cv::Mat G = H.inv();

    // I can rectify the image.
    cv::Mat warped;
    cv::warpPerspective(img, warped, G, cv::Size(2600, 2200 * 297 / 210));

    {
        // Here I manually picked the pixels coordinates of ticks '0' and '1' in the slide rule,
        // in the world the distance between them is 10mm.
        cv::Point2f tick_0(2017, 1159);
        cv::Point2f tick_1(1949, 1143);
        // I measure the distance and I write it on the image.
        std::ostringstream oss;
        oss << measure_distance(tick_0, tick_1, G) / scale;
        cv::line(img, tick_0, tick_1, CV_RGB(0, 255, 0));
        cv::putText(img, oss.str(), (tick_0 + tick_1) / 2, cv::FONT_HERSHEY_PLAIN, 3, CV_RGB(0, 255, 0), 3);
    }

    {
        // Here I manually picked the pixels coordinates of ticks '11' and '12' in the slide rule,
        // in the world the distance between them is 10mm.
        cv::Point2f tick_11(1277, 988);
        cv::Point2f tick_12(1211, 973);
        // I measure the distance and I write it on the image.
        std::ostringstream oss;
        oss << measure_distance(tick_11, tick_12, G) / scale;
        cv::line(img, tick_11, tick_12, CV_RGB(0, 255, 0));
        cv::putText(img, oss.str(), (tick_11 + tick_12) / 2, cv::FONT_HERSHEY_PLAIN, 3, CV_RGB(0, 255, 0), 3);
    }

    // I draw the points used in the estimate of the homography.
    draw_cross(img, TL, 40, CV_RGB(255, 0, 0));
    draw_cross(img, TR, 40, CV_RGB(255, 0, 0));
    draw_cross(img, BL, 40, CV_RGB(255, 0, 0));
    draw_cross(img, BR, 40, CV_RGB(255, 0, 0));

    cv::namedWindow( "Input image", cv::WINDOW_NORMAL );
    cv::imshow( "Input image", img );
    cv::imwrite("img.png", img);

    cv::namedWindow( "Rectified image", cv::WINDOW_NORMAL );
    cv::imshow( "Rectified image", warped );
    cv::imwrite("warped.png", warped);

    cv::waitKey(0);

    return 0;
}

, - A4, - : enter image description here

, : enter image description here

: enter image description here

+2

- mm/pixel. , . , , .

- . , , .

.

+1

Source: https://habr.com/ru/post/1629893/


All Articles