दिए गए बिंदुओं के लिए न्यूनतम क्षेत्रफल-आयत ज्ञात करना?


71

जैसा कि आप आंकड़े में देखते हैं, सवाल यह है:

दिए गए बिंदुओं पर फिट किए गए न्यूनतम-क्षेत्र-आयत (MAR) को कैसे खोजें?

और एक सहायक प्रश्न है:

क्या समस्या का कोई विश्लेषणात्मक समाधान है?

(प्रश्न का एक विकास एक 3D बिंदु बादल में बिंदुओं के समूह में एक बॉक्स (3D) फिट करने के लिए होगा।)

पहले चरण के रूप में मैं उन बिंदुओं के लिए उत्तल-पतवार खोजने का प्रस्ताव करता हूं जो समस्या को सुधारता है (उन बिंदुओं को हटाकर समाधान में शामिल नहीं हैं): बहुभुज को एक मार्क फिटिंग करना। आवश्यक विधि एक्स ( आयत का केंद्र ), डी ( दो आयाम ) और ए ( कोण ) प्रदान करेगी ।


समाधान के लिए मेरा प्रस्ताव:

  • बहुभुज का केंद्रक ज्ञात करें ( ऑब्जेक्ट की ज्यामिति का केंद्र ढूँढना? )
  • [एस] कुल्हाड़ियों एक्स और वाई के समानांतर, एक साधारण फिट आयत फिट करें
    • आप minmaxदिए गए बिंदुओं के X और Y के लिए फ़ंक्शन का उपयोग कर सकते हैं (जैसे, बहुभुज के कोने)
  • फिट किए गए आयत के क्षेत्र को स्टोर करें
  • उदाहरण के लिए, 1 डिग्री सेंटीमीटर के बारे में बहुभुज को घुमाएं
  • [एस] से दोहराएं जब तक कि एक पूर्ण रोटेशन न हो जाए
  • परिणाम के रूप में न्यूनतम क्षेत्र के कोण की रिपोर्ट करें

यह मुझे आशाजनक लगता है, हालांकि निम्नलिखित समस्याएं मौजूद हैं:

  • कोण परिवर्तन के लिए एक अच्छे संकल्प का चयन चुनौतीपूर्ण हो सकता है,
  • गणना लागत अधिक है,
  • समाधान विश्लेषणात्मक नहीं बल्कि प्रयोगात्मक है।

यहाँ छवि विवरण दर्ज करें

जवाबों:


45

हां, इस समस्या का एक विश्लेषणात्मक समाधान है। आप जिस एल्गोरिथ्म की तलाश कर रहे हैं, उसे बहुभुज सामान्यीकरण में "सबसे छोटा आसपास का आयत" कहा जाता है।

आपके द्वारा वर्णित एल्गोरिथ्म ठीक है, लेकिन आपके द्वारा सूचीबद्ध समस्याओं को हल करने के लिए, आप इस तथ्य का उपयोग कर सकते हैं कि MAR का अभिविन्यास बिंदु क्लाउड उत्तल पतवार के किनारों में से एक के समान है । तो आपको बस उत्तल पतवार किनारों के झुकाव का परीक्षण करने की आवश्यकता है। तुम्हे करना चाहिए:

  • क्लाउड के उत्तल हल की गणना करें।
  • उत्तल पतवार के प्रत्येक किनारे के लिए:
    • बढ़त अभिविन्यास की गणना करें (आर्कन के साथ),
    • इस अभिविन्यास का उपयोग करके उत्तल पतवार को घुमाएं ताकि घुमाए गए उत्तल पतवार के मिनट / अधिकतम x / y के साथ आयताकार क्षेत्र को आसानी से गणना करने के लिए,
    • पाया न्यूनतम क्षेत्र के लिए उन्मुखीकरण स्टोर,
  • प्राप्त न्यूनतम क्षेत्र के अनुरूप आयत लौटें।

जावा में कार्यान्वयन का एक उदाहरण वहां उपलब्ध है

3D में, समान लागू होता है, सिवाय:

  • उत्तल पतवार एक मात्रा होगी,
  • परीक्षण किए गए झुकाव उत्तल पतवार के चेहरों (3 डी में) के झुकाव होंगे।

सौभाग्य!


11
+1 बहुत अच्छा जवाब! मैं यह बताना चाहता हूं कि बादल का वास्तविक घूमना अनावश्यक है। पहला - आपका शायद यही मतलब था - केवल पतवार के शीर्ष पर विचार करना होगा। दूसरा, घूमने के बजाय, वर्तमान पक्ष को ऑर्थोगोनल यूनिट वैक्टर की एक जोड़ी के रूप में दर्शाते हैं। पतले शीर्ष निर्देशांक (जो एक मैट्रिक्स ऑपरेशन के रूप में किया जा सकता है) के साथ अपने डॉट उत्पादों को लेना, घुमाए गए निर्देशांक देता है: कोई त्रिकोणमिति आवश्यक, तेज और पूरी तरह से सटीक नहीं।
whuber

2
लिंक के लिए धन्यवाद। वास्तव में, केवल किनारों के लिए घूमना प्रस्तावित विधि को बहुत कुशल बनाता है। मैं पा सकता था कागज साबित करता है कि। हालाँकि मैंने इसे पहले अच्छे उत्तर के प्रति निष्ठा के लिए उत्तर के रूप में चिह्नित किया है (दो / अधिक महान जवाब नहीं चुन सकता है :() मैं नीचे दिए गए व्हीबर के पूर्ण उत्तर पर विचार करने की दृढ़ता से अनुशंसा करना चाहूंगा । वहां दी गई विधि की दक्षता (रोटेशन से बचना!)। अविश्वसनीय, और पूरी प्रक्रिया कोड की केवल कुछ पंक्तियाँ है। मेरे लिए यह पायथन के लिए आसानी से अनुवाद योग्य है :)
डेवलपर

क्या आप जावा कार्यान्वयन लिंक को अपडेट कर सकते हैं?
मायरा

हाँ, यह किया है!
जुलिएन

1
ध्यान दें कि 3 डी में विस्तार उससे थोड़ा अधिक जटिल है। 3 डी उत्तल पतवार का प्रत्येक चेहरा बाउंडिंग बॉक्स के एक चेहरे के संभावित अभिविन्यास को परिभाषित करता है , लेकिन इसके लिए लंबवत चेहरों का उन्मुखीकरण नहीं। उस प्लेन में बॉक्स को घुमाने की समस्या उस चेहरे के प्लेन में 2 डी न्यूनतम-बाउंडिंग-आयत समस्या बन जाती है। एक दिए गए विमान पर अनुमानित बादल के उत्तल पतवार के प्रत्येक किनारे के लिए आप एक बाउंडिंग बॉक्स बना सकते हैं जो आपको 3 डी में एक अलग वॉल्यूम देगा।
विल

40

@ जूलियन के महान समाधान के पूरक के लिए, यहां एक कार्यशील कार्यान्वयन है R, जो किसी भी जीआईएस-विशिष्ट कार्यान्वयन का मार्गदर्शन करने के लिए छद्मकोड के रूप में काम कर सकता है (या सीधे Rपाठ्यक्रम में लागू किया जा सकता है )। इनपुट बिंदु निर्देशांक की एक सरणी है। आउटपुट (का मान mbr) न्यूनतम बाउंडिंग आयत के कोने की एक सरणी है (इसे बंद करने के लिए पहले दोहराया गया)। किसी भी त्रिकोणमितीय गणना की पूर्ण अनुपस्थिति पर ध्यान दें।

MBR <- function(p) {
  # Analyze the convex hull edges     
  a <- chull(p)                                   # Indexes of extremal points
  a <- c(a, a[1])                                 # Close the loop
  e <- p[a[-1],] - p[a[-length(a)], ]             # Edge directions
  norms <- sqrt(rowSums(e^2))                     # Edge lengths
  v <- e / norms                                  # Unit edge directions
  w <- cbind(-v[,2], v[,1])                       # Normal directions to the edges

  # Find the MBR
  vertices <- p[a, ]                              # Convex hull vertices
  x <- apply(vertices %*% t(v), 2, range)         # Extremes along edges
  y <- apply(vertices %*% t(w), 2, range)         # Extremes normal to edges
  areas <- (y[1,]-y[2,])*(x[1,]-x[2,])            # Areas
  k <- which.min(areas)                           # Index of the best edge (smallest area)

  # Form a rectangle from the extremes of the best edge
  cbind(x[c(1,2,2,1,1),k], y[c(1,1,2,2,1),k]) %*% rbind(v[k,], w[k,])
}

यहाँ इसके उपयोग का एक उदाहरण है:

# Create sample data
set.seed(23)
p <- matrix(rnorm(20*2), ncol=2)                 # Random (normally distributed) points
mbr <- MBR(points)

# Plot the hull, the MBR, and the points
limits <- apply(mbr, 2, range) # Plotting limits
plot(p[(function(x) c(x, x[1]))(chull(p)), ], 
     type="l", asp=1, bty="n", xaxt="n", yaxt="n",
     col="Gray", pch=20, 
     xlab="", ylab="",
     xlim=limits[,1], ylim=limits[,2])                # The hull
lines(mbr, col="Blue", lwd=3)                         # The MBR
points(points, pch=19)                                # The points

एमबीआर

टाइमिंग उत्तल पतवार एल्गोरिथ्म की गति से सीमित है, क्योंकि पतवार की संख्या कुल की तुलना में लगभग हमेशा कम है। अधिकांश उत्तल पतवार एल्गोरिदम हैं asymptotically O (n * log (n)) n अंक के लिए: आप निर्देशांक पढ़ सकते हैं जितनी तेजी से गणना कर सकते हैं।


+1 क्या अद्भुत उपाय है! ऐसा विचार लंबे अनुभवों के बाद ही आता है। अब से मैं इस महान उत्तर से प्रेरित होकर अपने मौजूदा कोड को अनुकूलित करने के लिए उत्सुक होऊंगा।
डेवलपर

काश मैं इसे दो बार बढ़ा सकता। मैं आर सीख रहा हूं और आपके उत्तर प्रेरणा का एक निरंतर स्रोत हैं।
जॉन पॉवेल 10

1
@retrovius (घुमाए गए) बिंदुओं के एक सेट की बाउंडिंग आयत चार संख्याओं द्वारा निर्धारित की जाती है: सबसे छोटा x निर्देशांक, सबसे बड़ा x निर्देशांक, सबसे छोटा y निर्देशांक और सबसे बड़ा y निर्देशांक। यही "किनारों के साथ चरम" को संदर्भित करता है।
whuber

1
@retrovius मूल इन गणनाओं में कोई भूमिका नहीं निभाता है, क्योंकि सब कुछ अंत में छोड़कर निर्देशांक के अंतर पर आधारित है, जहां घुमाए गए निर्देशांक में गणना के रूप में सबसे अच्छा आयत बस वापस घुमाया जाता है। यद्यपि यह एक समन्वय प्रणाली का उपयोग करने के लिए एक स्मार्ट विचार है, जिसमें मूल बिंदुओं के करीब है (फ्लोटिंग पॉइंट परिशुद्धता के नुकसान को कम करने के लिए), मूल अन्यथा अप्रासंगिक है।
whuber

1
@Retrovius आप रोटेशन की एक संपत्ति के संदर्भ में इसकी व्याख्या कर सकते हैं: अर्थात्, रोटेशन का मैट्रिक्स ऑर्थोगोनल है। इस प्रकार, एक प्रकार का संसाधन रैखिक बीजगणित (आमतौर पर) या विश्लेषणात्मक यूक्लिडियन ज्यामिति (विशेष रूप से) का अध्ययन होगा। हालांकि, मैंने पाया है कि विमान में घुमाव (और अनुवाद और पुनर्विक्रेता) से निपटने का सबसे आसान तरीका है कि बिंदुओं को जटिल संख्याओं के रूप में देखें: रोटेशन को इकाई-लंबाई संख्याओं द्वारा मूल्यों को गुणा करके किया जाता है।
व्हीबर

8

मैंने इसे स्वयं लागू किया और अपना उत्तर StackOverflow पर पोस्ट किया , लेकिन मुझे लगा कि मैं अपना संस्करण दूसरों के देखने के लिए यहाँ छोड़ दूँगा:

import numpy as np
from scipy.spatial import ConvexHull

def minimum_bounding_rectangle(points):
    """
    Find the smallest bounding rectangle for a set of points.
    Returns a set of points representing the corners of the bounding box.

    :param points: an nx2 matrix of coordinates
    :rval: an nx2 matrix of coordinates
    """
    from scipy.ndimage.interpolation import rotate
    pi2 = np.pi/2.

    # get the convex hull for the points
    hull_points = points[ConvexHull(points).vertices]

    # calculate edge angles
    edges = np.zeros((len(hull_points)-1, 2))
    edges = hull_points[1:] - hull_points[:-1]

    angles = np.zeros((len(edges)))
    angles = np.arctan2(edges[:, 1], edges[:, 0])

    angles = np.abs(np.mod(angles, pi2))
    angles = np.unique(angles)

    # find rotation matrices
    # XXX both work
    rotations = np.vstack([
        np.cos(angles),
        np.cos(angles-pi2),
        np.cos(angles+pi2),
        np.cos(angles)]).T
#     rotations = np.vstack([
#         np.cos(angles),
#         -np.sin(angles),
#         np.sin(angles),
#         np.cos(angles)]).T
    rotations = rotations.reshape((-1, 2, 2))

    # apply rotations to the hull
    rot_points = np.dot(rotations, hull_points.T)

    # find the bounding points
    min_x = np.nanmin(rot_points[:, 0], axis=1)
    max_x = np.nanmax(rot_points[:, 0], axis=1)
    min_y = np.nanmin(rot_points[:, 1], axis=1)
    max_y = np.nanmax(rot_points[:, 1], axis=1)

    # find the box with the best area
    areas = (max_x - min_x) * (max_y - min_y)
    best_idx = np.argmin(areas)

    # return the best box
    x1 = max_x[best_idx]
    x2 = min_x[best_idx]
    y1 = max_y[best_idx]
    y2 = min_y[best_idx]
    r = rotations[best_idx]

    rval = np.zeros((4, 2))
    rval[0] = np.dot([x1, y2], r)
    rval[1] = np.dot([x2, y2], r)
    rval[2] = np.dot([x2, y1], r)
    rval[3] = np.dot([x1, y1], r)

    return rval

क्रिया में इसके चार अलग-अलग उदाहरण दिए गए हैं। प्रत्येक उदाहरण के लिए, मैंने 4 यादृच्छिक अंक उत्पन्न किए और बाउंडिंग बॉक्स पाया।

यहाँ छवि विवरण दर्ज करें

यह 4 बिंदुओं पर इन नमूनों के लिए अपेक्षाकृत जल्दी है:

>>> %timeit minimum_bounding_rectangle(a)
1000 loops, best of 3: 245 µs per loop

हाय JesseBuesking, क्या आप 90 नीचे के कोनों के साथ आयत बनाने में सक्षम हैं? आपका कोड समांतर चतुर्भुज प्राप्त करने के लिए बहुत अच्छा काम कर रहा है, लेकिन मेरे विशिष्ट उपयोग के मामले में 90 डिग्री कोनों की आवश्यकता है। क्या आप सुझा सकते हैं कि उस तक पहुंचने के लिए आपके कोड को कैसे संशोधित किया जा सकता है? धन्यवाद!
नादेर एलेक्सन

@ NaderAlexan यदि आप पूछ रहे हैं कि क्या यह वर्गों को संभाल सकता है, तो हाँ यह निश्चित रूप से कर सकता है! मैंने इसे केवल एक इकाई वर्ग पर आज़माया points = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]), और आउटपुट वह है array([[1.00000000e+00, 6.12323400e-17], [0.00000000e+00, 0.00000000e+00], [6.12323400e-17, 1.00000000e+00], [1.00000000e+00, 1.00000000e+00]])जो इकाई वर्ग ही है (कुछ फ़्लोटिंग पॉइंट राउंडिंग त्रुटियों सहित)। नोट: एक वर्ग बराबर पक्षों के साथ एक आयत है, इसलिए मैं मान रहा हूं कि क्या यह एक वर्ग को संभाल सकता है जो सभी आयतों को सामान्य करता है।
JesseBuesking

आपके उत्तर के लिए धन्यवाद। हां, यह बहुत अच्छा काम कर रहा है, लेकिन मैं इसे किसी भी अन्य 4-पक्षीय बहुभुज के ऊपर हमेशा एक आयत (प्रत्येक पक्ष के लिए 90 डिग्री कोण के साथ 4 पक्ष) का उत्पादन करने के लिए मजबूर करने का प्रयास कर रहा हूं, हालांकि कुछ मामलों में यह एक आयत का उत्पादन नहीं करता है, ऐसा प्रतीत नहीं होता है एक स्थिर बाधा बनने के लिए, क्या आप जानते हैं कि इस बाधा को जोड़ने के लिए कोड को कैसे संशोधित किया जाए? धन्यवाद!
नादेर एलेक्सन

हो सकता है कि gis.stackexchange.com/a/22934/48041 आपको इस समाधान के लिए मार्गदर्शन कर सकता है, उनके उत्तर में यह बाधा प्रतीत होती है? एक बार जब आप कोई समाधान ढूंढ लेते हैं, तो आपको इसे योगदान देना चाहिए क्योंकि मुझे यकीन है कि अन्य इसे उपयोगी पाएंगे। सौभाग्य!
जेसिबेस्किंग

7

इस सटीक समस्या को हल करने के लिए व्हाइटबॉक्स GAT ( http://www.uoguelph.ca/~hydrogeo/Whitebox/ ) को न्यूनतम बाउंडिंग बॉक्स कहा जाता है। वहाँ भी एक न्यूनतम उत्तल पतवार उपकरण है। पैच शेप टूलबॉक्स में कई उपकरण, जैसे पैच ओरिएंटेशन और बढ़ाव, न्यूनतम बाउंडिंग बॉक्स खोजने पर आधारित हैं।

यहाँ छवि विवरण दर्ज करें


4

एक न्यूनतम-क्षेत्र बाउंडिंग आयत के लिए पायथन समाधान की तलाश करते हुए मैं इस धागे के पार आया।

यहां मेरा कार्यान्वयन है , जिसके लिए परिणाम मतलाब के साथ सत्यापित किए गए थे।

टेस्ट कोड सरल बहुभुज के लिए शामिल है, और मैं इसे 3D डीक्लाकॉड के लिए 2 डी न्यूनतम बाउंडिंग बॉक्स और कुल्हाड़ियों के निर्देशों को खोजने के लिए उपयोग कर रहा हूं।


क्या आपका उत्तर हटा दिया गया है?
पॉल रिक्टर

@PaRRichter जाहिरा तौर पर। स्रोत यहाँ था github.com/dbworth/minimum-area-oubing-rectangle हालांकि
sehe

3

धन्यवाद @ व्हीबर का जवाब। यह एक महान समाधान है, लेकिन बड़े बिंदु बादल के लिए धीमा है। मैंने पाया convhullnकि आर पैकेज में फ़ंक्शन geometryबहुत तेज़ है (200000 अंकों के लिए 138 एस बनाम 0.03 एस)। मैंने किसी के लिए अपने कोड यहां पेस्ट किए हैं जो एक तेज़ समाधान के लिए दिलचस्प है।

library(alphahull)                                  # Exposes ashape()
MBR <- function(points) {
    # Analyze the convex hull edges                       
    a <- ashape(points, alpha=1000)                 # One way to get a convex hull...
    e <- a$edges[, 5:6] - a$edges[, 3:4]            # Edge directions
    norms <- apply(e, 1, function(x) sqrt(x %*% x)) # Edge lengths
    v <- diag(1/norms) %*% e                        # Unit edge directions
    w <- cbind(-v[,2], v[,1])                       # Normal directions to the edges

    # Find the MBR
    vertices <- (points) [a$alpha.extremes, 1:2]    # Convex hull vertices
    minmax <- function(x) c(min(x), max(x))         # Computes min and max
    x <- apply(vertices %*% t(v), 2, minmax)        # Extremes along edges
    y <- apply(vertices %*% t(w), 2, minmax)        # Extremes normal to edges
    areas <- (y[1,]-y[2,])*(x[1,]-x[2,])            # Areas
    k <- which.min(areas)                           # Index of the best edge (smallest area)

    # Form a rectangle from the extremes of the best edge
    cbind(x[c(1,2,2,1,1),k], y[c(1,1,2,2,1),k]) %*% rbind(v[k,], w[k,])
}

MBR2 <- function(points) {
    tryCatch({
        a2 <- geometry::convhulln(points, options = 'FA')

        e <- points[a2$hull[,2],] - points[a2$hull[,1],]            # Edge directions
        norms <- apply(e, 1, function(x) sqrt(x %*% x)) # Edge lengths

        v <- diag(1/norms) %*% as.matrix(e)                        # Unit edge directions


        w <- cbind(-v[,2], v[,1])                       # Normal directions to the edges

        # Find the MBR
        vertices <- as.matrix((points) [a2$hull, 1:2])    # Convex hull vertices
        minmax <- function(x) c(min(x), max(x))         # Computes min and max
        x <- apply(vertices %*% t(v), 2, minmax)        # Extremes along edges
        y <- apply(vertices %*% t(w), 2, minmax)        # Extremes normal to edges
        areas <- (y[1,]-y[2,])*(x[1,]-x[2,])            # Areas
        k <- which.min(areas)                           # Index of the best edge (smallest area)

        # Form a rectangle from the extremes of the best edge
        as.data.frame(cbind(x[c(1,2,2,1,1),k], y[c(1,1,2,2,1),k]) %*% rbind(v[k,], w[k,]))
    }, error = function(e) {
        assign('points', points, .GlobalEnv)
        stop(e)  
    })
}


# Create sample data
#set.seed(23)
points <- matrix(rnorm(200000*2), ncol=2)                 # Random (normally distributed) points
system.time(mbr <- MBR(points))
system.time(mmbr2 <- MBR2(points))


# Plot the hull, the MBR, and the points
limits <- apply(mbr, 2, function(x) c(min(x),max(x))) # Plotting limits
plot(ashape(points, alpha=1000), col="Gray", pch=20, 
     xlim=limits[,1], ylim=limits[,2])                # The hull
lines(mbr, col="Blue", lwd=10)                         # The MBR
lines(mbr2, col="red", lwd=3)                         # The MBR2
points(points, pch=19)   

दो तरीकों से एक ही उत्तर मिलता है (उदाहरण के लिए 2000 अंक):

यहाँ छवि विवरण दर्ज करें


क्या इस कार्यान्वयन को 3 डी स्थान तक विस्तारित करना संभव है (यानी एक न्यूनतम वॉल्यूम बॉक्स ढूंढें जिसमें 3 डी स्थान में सभी दिए गए बिंदु शामिल हैं)?
साशा

0

मैं बस OpenCV के बिल्ड-इन फ़ंक्शन की सिफारिश करता हूं minAreaRect, जो इनपुट 2 डी बिंदु सेट को घेरने वाले न्यूनतम क्षेत्र की एक घुमाया हुआ आयत पाता है। यह देखने के लिए कि इस फ़ंक्शन का उपयोग कैसे किया जाए, कोई इस ट्यूटोरियल को संदर्भित कर सकता है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.