Cách đo độ tương tự của các đối tượng SpatialLines


9

Tôi đã tạo hai SpatialLinesđối tượng trong R : nhân vật.

Những đối tượng này đã được tạo ra theo cách này:

library(sp)
xy <- cbind(x,y)
xy.sp = sp::SpatialPoints(xy)
spl1 <- sp::SpatialLines(list(Lines(Line(xy.sp), ID="a")))

Bây giờ tôi muốn bằng cách nào đó kết luận rằng đây là cùng một dòng được xoay và lật, và sự khác biệt giữa chúng bằng 0 (tức là hình dạng bằng nhau).

Để làm điều đó, người ta có thể sử dụng maptoolsgói và xoay dòng # 1, ví dụ:

spl180 <- maptools::elide(spl1, rotate=180)

Mỗi dòng được xoay phải được kiểm tra so với dòng số 2 bằng cách sử dụng rgeosgói, ví dụ:

hdist <- rgeos::gDistance(spl180, spl2, byid=FALSE, hausdorff=TRUE)

Tuy nhiên, đây là cách tính toán rất tốn kém để khớp với SpatialLinescác đối tượng, đặc biệt nếu số lượng đối tượng khoảng 1000.

Có cách nào thông minh để làm công việc này?

PS Hơn nữa, cách tiếp cận được mô tả ở trên không đảm bảo tất cả các phép quay và lật có thể.

P.S2. Nếu dòng số 1 được thu nhỏ so với dòng số 2, thì sự khác biệt giữa dòng số 1 và số 2 vẫn phải bằng 0.

CẬP NHẬT:

nhập mô tả hình ảnh ở đây

Câu trả lời:


9

Bất kỳ phương pháp hiệu quả thực sự có mục đích chung nào cũng sẽ tiêu chuẩn hóa các biểu diễn của các hình dạng để chúng không thay đổi khi xoay, dịch, phản xạ hoặc thay đổi nhỏ trong biểu diễn bên trong.

Một cách để làm điều này là liệt kê mỗi hình dạng được kết nối thành một chuỗi xen kẽ các độ dài cạnh và các góc (đã ký), bắt đầu từ một đầu. .

(Bởi vì bất kỳ polyline kết nối của n đỉnh sẽ có n -1 cạnh nhau bởi n -2 góc, tôi đã tìm thấy nó thuận tiện trong Rcode dưới đây để sử dụng một cấu trúc dữ liệu bao gồm hai mảng, một cho độ dài cạnh $lengthsvà một cho các các góc , $angles. Một đoạn đường sẽ không có góc nào cả, vì vậy điều quan trọng là phải xử lý các mảng có độ dài bằng không trong cấu trúc dữ liệu như vậy.)

Các đại diện như vậy có thể được đặt hàng từ vựng. Một số phụ cấp nên được thực hiện cho các lỗi dấu phẩy động được tích lũy trong quá trình tiêu chuẩn hóa. Một thủ tục tao nhã sẽ ước tính các lỗi đó là một hàm của tọa độ ban đầu. Trong giải pháp dưới đây, một phương pháp đơn giản hơn được sử dụng trong đó hai độ dài được coi là bằng nhau khi chúng khác nhau một lượng rất nhỏ trên cơ sở tương đối. Các góc có thể chỉ khác nhau một lượng rất nhỏ trên cơ sở tuyệt đối.

Để làm cho chúng bất biến dưới sự đảo ngược của định hướng cơ bản, chọn biểu diễn từ vựng sớm nhất giữa đa giác và đảo ngược của nó.

Để xử lý các polylines đa phần, sắp xếp các thành phần của chúng theo thứ tự từ điển.

Để tìm các lớp tương đương dưới các phép biến đổi Euclide, sau đó,

  • Tạo các đại diện tiêu chuẩn của các hình dạng.

  • Thực hiện một loại từ điển của các đại diện được tiêu chuẩn hóa.

  • Thực hiện chuyển qua thứ tự được sắp xếp để xác định chuỗi các biểu diễn bằng nhau.

Thời gian tính toán tỷ lệ thuận với O (n * log (n) * N) trong đó n là số lượng tính năng và N là số lượng đỉnh lớn nhất trong bất kỳ tính năng nào. Đây là hiệu quả.

Có lẽ đáng nói đến khi thông qua rằng một nhóm sơ bộ dựa trên các thuộc tính hình học bất biến được tính toán dễ dàng, chẳng hạn như chiều dài đa tuyến, tâm và các khoảnh khắc về trung tâm đó, thường có thể được áp dụng để hợp lý hóa toàn bộ quá trình. Người ta chỉ cần tìm các nhóm nhỏ các tính năng phù hợp trong mỗi nhóm sơ bộ như vậy. Phương pháp đầy đủ được đưa ra ở đây sẽ là cần thiết cho các hình dạng mà nếu không thì sẽ rất giống nhau đến mức những bất biến đơn giản như vậy vẫn không thể phân biệt được chúng. Các tính năng đơn giản được xây dựng từ dữ liệu raster có thể có các đặc điểm như vậy, ví dụ. Tuy nhiên, vì giải pháp được đưa ra ở đây dù sao cũng rất hiệu quả, nên nếu ai đó sẽ nỗ lực thực hiện nó, thì nó có thể tự hoạt động tốt.


Thí dụ

Hình bên trái cho thấy năm polylines cộng thêm 15 cái nữa thu được từ những thứ đó thông qua dịch thuật ngẫu nhiên, xoay, phản xạ và đảo ngược hướng bên trong (không nhìn thấy được). Hình bên tay phải tô màu chúng theo lớp tương đương Euclide của chúng: tất cả các hình có màu chung là đồng dạng; màu sắc khác nhau không đồng nhất.

Nhân vật

Rmã theo sau. Khi các đầu vào được cập nhật thành 500 hình, 500 hình phụ (đồng dạng), với giá trị trung bình là 100 đỉnh trên mỗi hình, thời gian thực hiện trên máy này là 3 giây.

Mã này không đầy đủ:Rkhông có sắp xếp từ vựng gốc và tôi không cảm thấy như mã hóa từ đầu, tôi chỉ đơn giản thực hiện sắp xếp trên tọa độ đầu tiên của mỗi hình dạng chuẩn. Điều đó sẽ tốt cho các hình dạng ngẫu nhiên được tạo ra ở đây, nhưng đối với công việc sản xuất, nên thực hiện một loại từ điển đầy đủ. Chức năng order.shapesẽ là người duy nhất bị ảnh hưởng bởi sự thay đổi này. Đầu vào của nó là một danh sách các hình dạng được tiêu chuẩn hóa svà đầu ra của nó là chuỗi các chỉ mục vào sđó sẽ sắp xếp nó.

#
# Create random shapes.
#
n.shapes <- 5      # Unique shapes, up to congruence
n.shapes.new <- 15 # Additional congruent shapes to generate
p.mean <- 5        # Expected number of vertices per shape
set.seed(17)       # Create a reproducible starting point
shape.random <- function(n) matrix(rnorm(2*n), nrow=2, ncol=n)
shapes <- lapply(2+rpois(n.shapes, p.mean-2), shape.random)
#
# Randomly move them around.
#
move.random <- function(xy) {
  a <- runif(1, 0, 2*pi)
  reflection <- sign(runif(1, -1, 1))
  translation <- runif(2, -8, 8)
  m <- matrix(c(cos(a), sin(a), -sin(a), cos(a)), 2, 2) %*%
    matrix(c(reflection, 0, 0, 1), 2, 2)
  m <- m %*% xy + translation
  if (runif(1, -1, 0) < 0) m <- m[ ,dim(m)[2]:1]
  return (m)
}
i <- sample(length(shapes), n.shapes.new, replace=TRUE)
shapes <- c(shapes, lapply(i, function(j) move.random(shapes[[j]])))
#
# Plot the shapes.
#
range.shapes <- c(min(sapply(shapes, min)), max(sapply(shapes, max)))
palette(gray.colors(length(shapes)))
par(mfrow=c(1,2))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(shapes), function(i) lines(t(shapes[[i]]), col=i, lwd=2)))
#
# Standardize the shape description.
#
standardize <- function(xy) {
  n <- dim(xy)[2]
  vectors <- xy[ ,-1, drop=FALSE] - xy[ ,-n, drop=FALSE]
  lengths <- sqrt(colSums(vectors^2))
  if (which.min(lengths - rev(lengths))*2 < n) {
    lengths <- rev(lengths)
    vectors <- vectors[, (n-1):1]
  }
  if (n > 2) {
    vectors <- vectors / rbind(lengths, lengths)
    perps <- rbind(-vectors[2, ], vectors[1, ])
    angles <- sapply(1:(n-2), function(i) {
      cosine <- sum(vectors[, i+1] * vectors[, i])
      sine <- sum(perps[, i+1] * vectors[, i])
      atan2(sine, cosine)
    })
    i <- min(which(angles != 0))
    angles <- sign(angles[i]) * angles
  } else angles <- numeric(0)
  list(lengths=lengths, angles=angles)
}
shapes.std <- lapply(shapes, standardize)
#
# Sort lexicographically.  (Not implemented: see the text.)
#
order.shape <- function(s) {
  order(sapply(s, function(s) s$lengths[1]))
}
i <- order.shape(shapes.std)
#
# Group.
#
equal.shape <- function(s.0, s.1) {
  same.length <- function(a,b) abs(a-b) <= (a+b) * 1e-8
  same.angle <- function(a,b) min(abs(a-b), abs(a-b)-2*pi) < 1e-11
  r <- function(u) {
    a <- u$angles
    if (length(a) > 0) {
      a <- rev(u$angles)
      i <- min(which(a != 0))
      a <- sign(a[i]) * a
    }
    list(lengths=rev(u$lengths), angles=a)
  }
  e <- function(u, v) {
    if (length(u$lengths) != length(v$lengths)) return (FALSE)
    all(mapply(same.length, u$lengths, v$lengths)) &&
      all(mapply(same.angle, u$angles, v$angles))
    }
  e(s.0, s.1) || e(r(s.0), s.1)
}
g <- rep(1, length(shapes.std))
for (j in 2:length(i)) {
  i.0 <- i[j-1]
  i.1 <- i[j]
  if (equal.shape(shapes.std[[i.0]], shapes.std[[i.1]])) 
    g[j] <- g[j-1] else g[j] <- g[j-1]+1
}
palette(rainbow(max(g)))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(i), function(j) lines(t(shapes[[i[j]]]), col=g[j], lwd=2)))

Khi một bao gồm các pha loãng tùy ý (hoặc "isotheties") trong nhóm các phép biến đổi, các lớp tương đương là các lớp đồng dạng của hình học affine . Biến chứng này được xử lý dễ dàng: ví dụ tiêu chuẩn hóa tất cả các polylines để có tổng chiều dài đơn vị.
whuber

Cảm ơn rất nhiều. Chỉ cần một câu hỏi: hình dạng nên được biểu diễn dưới dạng SpatialLines hoặc SpatialPolygons?
Klausos Klausos

Đa giác tạo ra một sự phức tạp khác: ranh giới của chúng không có điểm cuối xác định. Có nhiều cách để xử lý điều đó, chẳng hạn như tiêu chuẩn hóa biểu diễn để bắt đầu tại (giả sử) đỉnh sắp xếp đầu tiên theo thứ tự từ điển xy và tiến hành theo hướng ngược chiều kim đồng hồ quanh đa giác. (Một đa giác được kết nối "sạch" về mặt tôpô sẽ chỉ có một đỉnh như vậy.) Hình dạng được coi là đa giác hay đa giác phụ thuộc vào loại tính năng mà nó thể hiện: không có cách nào để nói về bất kỳ danh sách đóng nào cho dù đó là dự định là một đa giác hoặc đa giác.
whuber

Xin lỗi vì một câu hỏi đơn giản, nhưng tôi nên yêu cầu nó hiểu ví dụ của bạn. Đối tượng của bạn hình dạng.std có cả độ dài $ và góc $. Tuy nhiên, nếu tôi chạy mã này trên dữ liệu xy của mình (ví dụ: [1,] 3093.5 -2987.8 [2,] 3072.7 -2991.0, v.v.), nó không ước tính các góc, không vẽ hình. Nếu tôi chạy cốt truyện (hình [[1]]), thì tôi có thể thấy rõ đường đa tuyến của mình. Vì vậy, làm thế nào tôi nên lưu polylines trong R để có thể kiểm tra mã của bạn trên dữ liệu của tôi?
Klausos Klausos

Tôi đã bắt đầu với cấu trúc dữ liệu giống như bạn đã làm: một mảng tọa độ (x, y). Mảng của tôi đặt các tọa độ đó vào các cột (như thể bạn đã sử dụng rbind(x,y)thay vì cbind(x,y)). Đó là tất cả những gì bạn cần: spthư viện không được sử dụng. Nếu bạn muốn làm theo những gì được thực hiện một cách chi tiết, tôi đề nghị bạn bắt đầu với, nói, n.shapes <- 2, n.shapes.new <- 3, và p.mean <- 1. Sau đó shapes, shapes.stdvv tất cả đều đủ nhỏ để dễ dàng kiểm tra. Cách thanh lịch - và "đúng" - để đối phó với tất cả điều này sẽ là tạo ra một lớp các biểu diễn tính năng được tiêu chuẩn hóa.
whuber

1

Bạn đang yêu cầu rất nhiều với sự xoay vòng và giãn nở tùy ý! Không chắc khoảng cách hữu ích của Hausdorff sẽ ở đó, nhưng hãy kiểm tra nó. Cách tiếp cận của tôi sẽ là giảm số lượng các trường hợp để kiểm tra thông qua dữ liệu giá rẻ. Ví dụ: bạn có thể bỏ qua các so sánh đắt tiền nếu độ dài của hai linestrings không phải là tỷ lệ số nguyên ( giả sử tỷ lệ số nguyên / chia độ ). Bạn có thể kiểm tra tương tự nếu khu vực hộp giới hạn hoặc khu vực thân lồi của chúng có tỷ lệ đẹp hay không. Tôi chắc chắn có rất nhiều kiểm tra giá rẻ bạn có thể làm đối với trung tâm, như khoảng cách hoặc góc từ đầu / cuối.

Chỉ sau đó, nếu bạn phát hiện mở rộng quy mô, hoàn tác nó và thực hiện kiểm tra thực sự tốn kém.

Làm rõ: Tôi không biết các gói bạn đang sử dụng. Theo tỷ lệ số nguyên tôi có nghĩa là bạn nên chia cả hai khoảng cách, kiểm tra xem kết quả có phải là số nguyên không, nếu không, đảo ngược giá trị đó (có thể bạn đã chọn sai thứ tự) và kiểm tra lại. Nếu bạn nhận được một số nguyên hoặc đủ gần, bạn có thể suy luận rằng có lẽ đã có tỷ lệ xảy ra. Hoặc nó chỉ có thể là hai hình dạng khác nhau.

Đối với hộp giới hạn, bạn có thể có các điểm đối diện của hình chữ nhật đại diện cho nó, vì vậy việc lấy diện tích ra khỏi chúng là số học đơn giản. Nguyên tắc đằng sau so sánh tỷ lệ là như nhau, chỉ là kết quả sẽ được bình phương. Đừng bận tâm với vỏ lồi nếu bạn không thể lấy chúng ra khỏi gói R đó một cách độc đáo, đó chỉ là một ý tưởng (dù sao cũng không đủ rẻ).


Cảm ơn rất nhiều. Bạn có thể giải thích làm thế nào để phát hiện nếu chiều dài của hai linestrings không phải là một tỷ lệ số nguyên? Ngoài ra, tôi đánh giá cao rất nhiều nếu bạn có thể đưa ra một ví dụ về việc kiểm tra "nếu khu vực hộp giới hạn hoặc khu vực vỏ lồi có tỷ lệ tốt"
Klausos Klausos

Chẳng hạn, nếu tôi trích xuất hộp giới hạn không gian từ dữ liệu không gian, thì tôi chỉ nhận được hai điểm: spl <- sp :: SpatialLines (list (Lines (Line (xy.sp), ID = i))) b <- bbox ( spl)
Klausos Klausos

Mở rộng bài chính.
lynxlynxlynx

"Nếu bạn nhận được một số nguyên hoặc đủ gần, bạn có thể suy luận rằng có lẽ đã mở rộng quy mô." Người dùng không thể áp dụng thang điểm 1,4 hay sao?
Germán Carrillo

Chắc chắn, nhưng giả định của tôi đã được làm rõ, đặc biệt là với các chỉnh sửa sau này. Tôi đã tưởng tượng thu phóng kiểu webmap, trong đó một cái được giới hạn độc đáo.
lynxlynxlynx

1

Một phương pháp tốt để so sánh các polylines này là dựa vào biểu diễn dưới dạng một chuỗi (khoảng cách, góc quay) ở mỗi đỉnh: Đối với một dòng gồm các điểm P1, P2, ..., PN, chuỗi đó sẽ là:

(khoảng cách (P1P2), góc (P1, P2, P3), khoảng cách (P2P3), ..., góc (P (N-2), P (N-1), PN), khoảng cách (P (N-1 ) PN)).

Theo yêu cầu của bạn, hai dòng bằng nhau khi và chỉ khi các chuỗi tương ứng của chúng giống nhau (modulo thứ tự và hướng góc). So sánh dãy số là chuyện nhỏ.

Bằng cách tính toán mỗi chuỗi polyline chỉ một lần và, như được đề xuất bởi lynxlynxlynx, chỉ kiểm tra độ tương tự của chuỗi đối với polyline có các đặc điểm tầm thường giống nhau (chiều dài, số đỉnh ...), việc tính toán sẽ rất nhanh!


Đây là ý tưởng đúng. Tuy nhiên, để nó thực sự hoạt động, nhiều chi tiết cần được giải quyết, chẳng hạn như đối phó với sự phản xạ, định hướng bên trong, khả năng của nhiều thành phần được kết nối và lỗi làm tròn điểm nổi. Họ được thảo luận trong giải pháp tôi cung cấp.
whuber

Vâng, tôi chỉ mô tả ý chính. Câu trả lời của bạn đầy đủ hơn đáng kể (như thường xuyên :-)
julien
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.