android परिप्रेक्ष्य बदलने के गंतव्य छवि का पहलू अनुपात की गणना करना




opencv image-processing (2)

यह कुछ समय पहले एसओ पर आया है, लेकिन मैंने कभी कोई पूरा उत्तर नहीं देखा है, इसलिए यहां चला जाता है। यहां दिखाया गया कार्यान्वयन इस पत्र पर आधारित है जो पूर्ण समीकरण प्राप्त करता है: http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf

मूलतः, यह दिखाता है कि एक पिनहोल कैमरा मॉडल को संभालने के लिए, अनुमानित आयत के लिए पहलू अनुपात की गणना करना संभव है (लेकिन पैमाने पर, आश्चर्यजनक रूप से नहीं) असल में, कोई फोकल लंबाई के लिए हल कर सकता है, फिर पहलू अनुपात प्राप्त करें यहां OpenCV का उपयोग करते हुए अजगर में एक नमूना कार्यान्वयन है ध्यान दें कि आपको 4 ऑब्जेक्ट कोनों को सही क्रम में रखना होगा या यह काम नहीं करेगा (ऑर्डर ध्यान दें, यह एक झोका है)। रिपोर्ट किए गए त्रुटि दर 3-5% सीमा में हैं

import math
import cv2
import scipy.spatial.distance
import numpy as np

img = cv2.imread('img.png')
(rows,cols,_) = img.shape

#image center
u0 = (cols)/2.0
v0 = (rows)/2.0

#detected corners on the original image
p = []
p.append((67,74))
p.append((270,64))
p.append((10,344))
p.append((343,331))

#widths and heights of the projected image
w1 = scipy.spatial.distance.euclidean(p[0],p[1])
w2 = scipy.spatial.distance.euclidean(p[2],p[3])

h1 = scipy.spatial.distance.euclidean(p[0],p[2])
h2 = scipy.spatial.distance.euclidean(p[1],p[3])

w = max(w1,w2)
h = max(h1,h2)

#visible aspect ratio
ar_vis = float(w)/float(h)

#make numpy arrays and append 1 for linear algebra
m1 = np.array((p[0][0],p[0][1],1)).astype('float32')
m2 = np.array((p[1][0],p[1][1],1)).astype('float32')
m3 = np.array((p[2][0],p[2][1],1)).astype('float32')
m4 = np.array((p[3][0],p[3][1],1)).astype('float32')

#calculate the focal disrance
k2 = np.dot(np.cross(m1,m4),m3) / np.dot(np.cross(m2,m4),m3)
k3 = np.dot(np.cross(m1,m4),m2) / np.dot(np.cross(m3,m4),m2)

n2 = k2 * m2 - m1
n3 = k3 * m3 - m1

n21 = n2[0]
n22 = n2[1]
n23 = n2[2]

n31 = n3[0]
n32 = n3[1]
n33 = n3[2]

f = math.sqrt(- (1.0/(n23*n33)) * ((n21*n31 - (n21*n33 + n23*n31)*u0 + n23*n33*u0*u0) + (n22*n32 - (n22*n33+n23*n32)*v0 + n23*n33*v0*v0)))

A = np.array([[f,0,u0],[0,f,v0],[0,0,1]]).astype('float32')

At = np.transpose(A)
Ati = np.linalg.inv(At)
Ai = np.linalg.inv(A)

#calculate the real aspect ratio
ar_real = math.sqrt(np.dot(np.dot(np.dot(n2,Ati),Ai),n2)/np.dot(np.dot(np.dot(n3,Ati),Ai),n3))

if ar_real < ar_vis:
    W = int(w)
    H = int(W / ar_real)
else:
    H = int(h)
    W = int(ar_real * H)

pts1 = np.array(p).astype('float32')
pts2 = np.float32([[0,0],[W,0],[0,H],[W,H]])

#project the image with the new w/h
M = cv2.getPerspectiveTransform(pts1,pts2)

dst = cv2.warpPerspective(img,M,(W,H))

cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.imwrite('orig.png',img)
cv2.imwrite('proj.png',dst)

cv2.waitKey(0)

मूल:

अनुमानित (संकल्प बहुत कम है क्योंकि मैं अपने स्क्रीनशॉट से छवि को क्रॉप किया है, लेकिन पहलू अनुपात सही लगता है):

मैंने हाल ही में एंड्रॉइड में अपने ऐप को ओपेनसीवी में प्रोजेक्टिव ट्रांसफ़ॉर्म किया है । लगभग सब कुछ बिना मुद्दों के काम करता है लेकिन एक पहलू को और अधिक काम करने की आवश्यकता है।

समस्या यह है कि मुझे पता नहीं है कि परिप्रेक्ष्य बदलने के गंतव्य छवि (इसे मैन्युअल रूप से सेट करने की आवश्यकता नहीं है) का सही पहलू अनुपात कैसे गिनना है, ताकि वह छवि के पहलू अनुपात को वास्तविक के आकार में गिना जा सके कैमरे के कोण के बावजूद बात / छवि ध्यान दें कि शुरुआती निर्देशांक ट्रैपेज़ॉइड नहीं बनाते हैं, यह एक चौगुना रूप बनाता है

अगर मेरे पास लगभग 45 डिग्री से ली गई पुस्तक का एक फोटोग्राफ है और मैं चाहता हूं कि गंतव्य छवि पहलू अनुपात बहुत ज्यादा हो, क्योंकि इस पुस्तक के पहलू अनुपात में है यह 2 डी फोटो करने में कठिन है, लेकिन कैमस्कैनर ऐप यह पूरी तरह से करता है। मैंने अपने गंतव्य छवि के आकार की गिनती करने के लिए बहुत आसान तरीका बना दिया है (बिना किसी अपेक्षा के लिए काम करने की उम्मीद के लिए), लेकिन यह छवि को 45 डिग्री के कोण से 20% तक कम बना देता है और जब छवि ऊंचाई कम हो जाती है महत्वपूर्ण है, जबकि कैमसैंकर यह पूरी तरह से कोण के बावजूद करता है:

यहां, कैमसैंकर ने गंतव्य छवि (दूसरा एक) के पहलू अनुपात को बनाए रखा है, जो किताब के समान है, यह ~ 20 डिग्री के कोण पर बिल्कुल सटीक था

इस बीच, मेरा कोड इस तरह दिखता है (गंतव्य छवि के आकार की गिनती करते समय मुझे इस प्रश्न के बारे में पूछने के लिए इसका कोई इरादा नहीं है):

public static Mat PerspectiveTransform(Point[] cropCoordinates, float ratioW, float ratioH, Bitmap croppedImage)
{
    if (cropCoordinates.length != 4) return null;

    double width1, width2, height1, height2, avgw, avgh;
    Mat src = new Mat();
    List<Point> startCoords = new ArrayList<>();
    List<Point> resultCoords = new ArrayList<>();

    Utils.bitmapToMat(croppedImage, src);

    for (int i = 0; i < 4; i++)
    {
        if (cropCoordinates[i].y < 0 ) new Point(cropCoordinates[i].x, 0);
        startCoords.add(new Point(cropCoordinates[i].x * ratioW, cropCoordinates[i].y * ratioH));
    }

    width1 = Math.sqrt(Math.pow(startCoords.get(2).x - startCoords.get(3).x,2) + Math.pow(startCoords.get(2).y - startCoords.get(3).y,2));
    width2 = Math.sqrt(Math.pow(startCoords.get(1).x - startCoords.get(0).x,2) + Math.pow(startCoords.get(1).y - startCoords.get(0).y,2));
    height1 = Math.sqrt(Math.pow(startCoords.get(1).x - startCoords.get(2).x, 2) + Math.pow(startCoords.get(1).y - startCoords.get(2).y, 2));
    height2 = Math.sqrt(Math.pow(startCoords.get(0).x - startCoords.get(3).x, 2) + Math.pow(startCoords.get(0).y - startCoords.get(3).y, 2));
    avgw = (width1 + width2) / 2;
    avgh = (height1 + height2) / 2;

    resultCoords.add(new Point(0, 0));
    resultCoords.add(new Point(avgw-1, 0));
    resultCoords.add(new Point(avgw-1, avgh-1));
    resultCoords.add(new Point(0, avgh-1));

    Mat start = Converters.vector_Point2f_to_Mat(startCoords);
    Mat result = Converters.vector_Point2d_to_Mat(resultCoords);
    start.convertTo(start, CvType.CV_32FC2);
    result.convertTo(result,CvType.CV_32FC2);

    Mat mat = new Mat();
    Mat perspective = Imgproc.getPerspectiveTransform(start, result);
    Imgproc.warpPerspective(src, mat, perspective, new Size(avgw, avgh));

    return mat;
}

और अपेक्षा से समान कोण से मेरी विधि इस परिणाम का उत्पादन करती है:

मुझे क्या जानना है कि यह कैसे करना संभव है? यह मेरे लिए दिलचस्प है कि उन्होंने 4 कोनों के निर्देशांक के द्वारा ऑब्जेक्ट की लंबाई की गणना करने का प्रबंधन कैसे किया? इसके अलावा, यदि यह संभव है, तो कृपया कुछ कोड / गणितीय स्पष्टीकरण या समान / उसी चीज़ के आलेख प्रदान करें।

पहले ही, आपका बहुत धन्यवाद।


Y300 और इस पोस्ट के लिए धन्यवाद https://.com/a/1222855/8746860 मुझे इसे जावा में लागू किया गया है मैं इसे यहाँ छोड़ दूँगा अगर किसी एक ही समस्या है मैं इसे जावा में परिवर्तित किया था ...

public float getRealAspectRatio(int imageWidth, int imageHeight) {

    double u0 = imageWidth/2;
    double v0 = imageHeight/2;
    double m1x = mTopLeft.x - u0;
    double m1y = mTopLeft.y - v0;
    double m2x = mTopRight.x - u0;
    double m2y = mTopRight.y - v0;
    double m3x = mBottomLeft.x - u0;
    double m3y = mBottomLeft.y - v0;
    double m4x = mBottomRight.x - u0;
    double m4y = mBottomRight.y - v0;

    double k2 = ((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x) /
            ((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) ;

    double k3 = ((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x) /
            ((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) ;

    double f_squared =
            -((k3*m3y - m1y)*(k2*m2y - m1y) + (k3*m3x - m1x)*(k2*m2x - m1x)) /
                    ((k3 - 1)*(k2 - 1)) ;

    double whRatio = Math.sqrt(
            (Math.pow((k2 - 1),2) + Math.pow((k2*m2y - m1y),2)/f_squared + Math.pow((k2*m2x - m1x),2)/f_squared) /
                    (Math.pow((k3 - 1),2) + Math.pow((k3*m3y - m1y),2)/f_squared + Math.pow((k3*m3x - m1x),2)/f_squared)
    ) ;

    if (k2==1 && k3==1 ) {
        whRatio = Math.sqrt(
                (Math.pow((m2y-m1y),2) + Math.pow((m2x-m1x),2)) /
                        (Math.pow((m3y-m1y),2) + Math.pow((m3x-m1x),2)));
    }

    return (float)(whRatio);
}




augmented-reality