33

Tôi đã làm việc trên một dự án trực quan hóa cho dữ liệu liên tục 2 chiều. Đó là loại điều bạn có thể sử dụng để nghiên cứu dữ liệu độ cao hoặc các mẫu nhiệt độ trên bản đồ 2D. Ở cốt lõi của nó, nó thực sự là một cách làm phẳng 3 chiều thành hai chiều cộng với màu sắc. Trong lĩnh vực nghiên cứu cụ thể của tôi, tôi không thực sự làm việc với dữ liệu độ cao địa lý, nhưng đó là một ẩn dụ tốt, vì vậy tôi sẽ gắn bó với nó trong suốt bài đăng này.Vẽ Bản đồ địa hình

Nhưng dù sao, vào thời điểm này, tôi có một "màu liên tục" renderer rằng tôi rất hài lòng với:

Continuous Color Renderer

Gradient là tiêu chuẩn màu bánh, nơi pixel màu đỏ chỉ ra tọa độ với giá trị cao và điểm ảnh màu tím cho biết giá trị thấp.

Cấu trúc dữ liệu cơ bản sử dụng thuật toán nội suy rất thông minh (nếu tôi tự nói) để cho phép phóng to sâu tùy ý vào chi tiết của bản đồ. Tại thời điểm này, tôi muốn vẽ một số đường viền địa hình (sử dụng đường cong bezier bậc hai), nhưng tôi đã không thể tìm thấy bất kỳ tài liệu tốt nào mô tả các thuật toán hiệu quả để tìm ra những đường cong đó.

Để cung cấp cho bạn một ý tưởng cho những gì tôi đang suy nghĩ về, đây là thực hiện một kém của con người (trong đó các renderer chỉ sử dụng một giá trị RGB đen bất cứ khi nào nó gặp một điểm ảnh mà nó phân cắt một đường đồng mức):

Continuous Color with Ghetto Topo Lines

có một số vấn đề với cách tiếp cận này, mặc dù:

  • khu vực của đồ thị với một kết quả có độ dốc dốc trong dòng topo mỏng hơn (và thường bị hỏng). Lý tưởng nhất, tất cả các dòng topo nên liên tục.

  • Các khu vực của biểu đồ có độ dốc phẳng hơn dẫn đến các đường trên cùng rộng hơn (và thường là toàn bộ vùng màu đen, đặc biệt là ở chu vi ngoài của vùng hiển thị).

Vì vậy, tôi đang xem xét phương pháp vẽ vector để có được những đường cong đẹp, dày 1 pixel hoàn hảo này. Cấu trúc cơ bản của thuật toán sẽ phải bao gồm các bước sau:

  1. Ở mỗi độ cao rời rạc mà tôi muốn vẽ một đường topo, tìm một tập hợp các tọa độ nơi cao ở đó phối hợp rất chặt chẽ (đưa ra một giá trị epsilon tùy ý) đến độ cao mong muốn.

  2. Loại bỏ các điểm dư thừa. Ví dụ, nếu ba điểm nằm trong một đường thẳng hoàn hảo, thì điểm trung tâm là thừa, vì nó có thể được loại bỏ mà không thay đổi hình dạng của đường cong. Tương tự như vậy, với đường cong bezier, nó thường có thể loại bỏ các điểm neo cetain bằng cách điều chỉnh vị trí của các điểm kiểm soát liền kề.

  3. Tập hợp các điểm còn lại thành một chuỗi, sao cho mỗi đoạn giữa hai điểm xấp xỉ với quỹ đạo trung lập cao, và sao cho không có hai đoạn đường nào đi qua đường. Mỗi chuỗi điểm phải tạo một đa giác khép kín hoặc phải giao nhau với hộp giới hạn của vùng hiển thị.

  4. Đối với mỗi đỉnh, tìm một cặp điểm kiểm soát sao cho đường cong kết quả biểu thị lỗi tối thiểu, đối với các điểm dư thừa được loại bỏ trong bướC# 2.

  5. Đảm bảo rằng tất cả các đối tượng địa lý có thể nhìn thấy ở thang tỷ lệ hiển thị hiện tại được thể hiện bằng các dòng đầu thích hợp. Ví dụ, nếu dữ liệu chứa một cành với độ cao cao, nhưng với đường kính cực nhỏ, các đường topo vẫn nên được vẽ. Bạn chỉ nên bỏ qua các đối tượng địa lý dọc nếu đường kính của đối tượng địa lý nhỏ hơn độ chi tiết hiển thị tổng thể của hình ảnh.

Nhưng ngay cả dưới những khó khăn, tôi vẫn có thể nghĩ đến chẩn đoán khác nhau cho việc tìm kiếm các dòng:

  • Tìm các điểm cao trong rendering bounding-box. Từ điểm cao đó, du lịch xuống dốc dọc theo nhiều quỹ đạo khác nhau. Bất cứ lúc nào đường truyền đi qua một ngưỡng cao, thêm điểm đó vào một xô cao độ cụ thể. Khi đường đi ngang đạt đến mức tối thiểu cục bộ, hãy thay đổi khóa học và đi lên dốc.

  • Thực hiện truyền tải có độ phân giải cao dọc theo hộp giới hạn hình chữ nhật của vùng hiển thị. Tại mỗi ngưỡng độ cao (và tại các điểm uốn, bất cứ nơi nào độ dốc đảo chiều), hãy thêm các điểm đó vào một xô cao độ cụ thể. Sau khi hoàn thành việc truyền tải ranh giới, bắt đầu truy tìm vào trong từ các điểm ranh giới trong các nhóm đó.

  • Quét toàn bộ vùng hiển thị, thực hiện đo lường độ cao ở khoảng thời gian thường xuyên thưa thớt. Đối với mỗi phép đo, sử dụng nó gần với một ngưỡng cao như một cơ chế để quyết định có hay không để đo lường nội suy của các nước láng giềng. Sử dụng kỹ thuật này sẽ cung cấp bảo đảm tốt hơn về vùng phủ sóng trên toàn bộ vùng hiển thị, nhưng sẽ rất khó để tập hợp các điểm kết quả thành một thứ tự hợp lý để xây dựng đường dẫn.

Vì vậy, đó là một số suy nghĩ của tôi ...

Trước khi lặn sâu vào một thực hiện, tôi muốn xem liệu bất cứ ai khác trên StackOverflow có nhiều kinh nghiệm với loại này của vấn đề và có thể cung cấp gợi ý cho thực hiện chính xác và hiệu quả.

Edit:

Tôi đặc biệt quan tâm đến các "Gradient" gợi ý do ellisbben. Và cấu trúc dữ liệu cốt lõi của tôi (bỏ qua một số các phím tắt nội suy tối ưu hóa) có thể được biểu diễn dưới dạng tổng kết của một tập hợp các hàm gaussian 2D, có thể hoàn toàn khác biệt.

Tôi cho rằng tôi sẽ cần cấu trúc dữ liệu để biểu thị độ dốc ba chiều và hàm để tính vectơ độ dốc đó tại điểm tùy ý. Trên đỉnh đầu của tôi, tôi không biết làm thế nào để làm điều đó (mặc dù nó có vẻ như nó phải dễ dàng), nhưng nếu bạn có một liên kết giải thích toán học, tôi sẽ có nhiều nghĩa vụ!

UPDATE:

Nhờ sự đóng góp xuất sắc của ellisbben và Azim, bây giờ tôi có thể tính toán góc đường viền cho bất kỳ điểm tùy ý trong lĩnh vực này. Vẽ các đường topo thực sẽ sớm theo dõi!

Dưới đây là các kết xuất được cập nhật, có và không có trình kết xuất đồ họa dựa trên đường rạch mà tôi đã sử dụng. Mỗi hình ảnh bao gồm một nghìn điểm mẫu ngẫu nhiên, được biểu thị bằng các chấm đỏ. Góc đường viền tại điểm đó được biểu diễn bằng một vạch trắng. Trong một số trường hợp nhất định, không thể đo độ dốc tại điểm đã cho (dựa trên độ chi tiết của phép nội suy), do đó, chấm đỏ xảy ra mà không có đường góc-đường viền tương ứng.

Tận hưởng!

(LƯU Ý: Các kết xuất này sử dụng địa hình bề mặt khác với kết xuất trước đó - vì tôi tạo ngẫu nhiên các cấu trúc dữ liệu trên mỗi lần lặp lại, trong khi tôi đang tạo mẫu - nhưng phương pháp kết xuất lõi giống nhau chắc chắn bạn sẽ có được ý tưởng)

alt text

alt text

Dưới đây là một thực tế thú vị:. qua trên tay phía bên phải của các render, bạn sẽ thấy một loạt các đường viền lạ dòng ở ngang và dọc hoàn hảo góc ical. Đây là hiện vật của quá trình nội suy, sử dụng một mạng lưới các bộ nội suy để giảm số lượng tính toán (khoảng 500%) cần thiết để thực hiện các hoạt động dựng hình lõi. Tất cả những đường viền kỳ lạ này xuất hiện trên ranh giới giữa hai ô lưới nội suy.

May mắn thay, những hiện vật đó không thực sự quan trọng. Mặc dù các hiện vật có thể phát hiện được trong khi tính toán độ dốc, trình kết xuất cuối cùng sẽ không nhận thấy chúng, vì nó hoạt động ở độ sâu bit khác nhau.


CẬP NHẬT LẠI:

Aaaaaaaand, như một niềm đam mê cuối cùng trước khi tôi đi ngủ, đây là một cặp render, một trong những trường học cũ "màu liên tục" phong cách, và một với 20.000 mẫu dốc . Trong tập hợp các kết xuất này, tôi đã loại bỏ chấm đỏ cho các điểm mẫu, vì nó không cần thiết làm xáo trộn hình ảnh.

Ở đây, bạn thực sự có thể thấy các đồ tạo tác nội suy mà tôi đã đề cập trước đó, nhờ cấu trúc lưới của bộ sưu tập nội suy. Tôi nên nhấn mạnh rằng các đồ tạo tác đó sẽ hoàn toàn vô hình trên kết xuất đường viền cuối cùng (vì sự chênh lệch về độ lớn giữa bất kỳ ô nội suy liền kề nào nhỏ hơn độ sâu bit của ảnh được hiển thị).

Bon appetit !!

alt text

alt text

+0

Tại sao bạn không sử dụng thư viện, công cụ hiện có (chẳng hạn như gnuplot, tecplot)? – jfs

+0

Bạn nói dữ liệu liên tục - điều đó ngụ ý rằng bạn có thể tính toán các giá trị cho các tọa độ liên pixel? – Alnitak

+0

Vâng, tôi có thể tính toán giá trị tại bất kỳ tọa độ nào (với độ chính xác điểm nổi 64 bit). Cấu trúc dữ liệu thực sự là một tập hợp các hàm Gauss 2D, mỗi hàm có biên độ riêng và độ lệch chuẩn của nó, và nội suy sử dụng một Trình Ước lượng Mật độ Hạt nhân để tìm các giá trị trung gian đó. – benjismith

Trả lời

9

gradient là toán tử toán học có thể giúp bạn.

Nếu bạn có thể biến nội suy thành một hàm có thể phân biệt được, thì độ dốc của chiều cao sẽ luôn hướng theo hướng đi lên dốc nhất. Tất cả các đường cong có chiều cao bằng nhau đều vuông góc với độ cao của chiều cao được đánh giá tại điểm đó.

Ý tưởng của bạn về việc bắt đầu từ điểm cao nhất là hợp lý, nhưng có thể bỏ lỡ các tính năng nếu có nhiều hơn một địa phương tối đa.

tôi muốn đề nghị

  1. giá trị chiều cao pick mà tại đó bạn sẽ vẽ đường
  2. tạo ra một loạt các điểm trên, lưới đều đặn cách nhau tốt, sau đó đi bộ mỗi điểm theo từng bước nhỏ theo hướng dốc về phía độ cao gần nhất mà bạn muốn vẽ một đường thẳng
  3. tạo các đường cong bằng cách bước từng điểm vuông góc với gradient; loại bỏ các điểm thừa bằng cách giết chết một điểm khi đường cong khác đến quá gần - nhưng để tránh phá hủy tâm của đồng hồ cát như hình, bạn có thể cần kiểm tra góc giữa vector hướng vuông góc với gradient cho cả hai điểm. (Khi tôi nói định hướng, ý tôi là đảm bảo rằng góc giữa gradient và giá trị vuông góc với bạn tính luôn 90 độ là theo cùng một hướng.)
+0

Rất đẹp. Xem chỉnh sửa gần đây nhất của tôi cho các câu hỏi làm rõ thêm. – benjismith

0

tôi luôn luôn kiểm tra những nơi như http://mathworld.wolfram.com trước khi đi sâu vào của riêng tôi :)

Có lẽ phần curves của họ sẽ giúp đỡ? Hoặc có thể là mục nhập trên maps.

0

so sánh những gì bạn đã hiển thị với bản đồ hàng đầu thế giới thực - chúng trông giống hệt với tôi! tôi sẽ không thay đổi một điều ...

+0

Vâng, * vị trí * của các dòng là khá tốt ngay bây giờ. Nhưng các dòng chính họ là tất cả bị phá vỡ và lầy lội và cẩu thả tìm kiếm. Vẽ các đường topo như (... cont'd ...) – benjismith

+0

... đường cong bezier sẽ (tôi nghĩ) cung cấp một dọn dẹp rất đẹp. Nhưng nó cũng sẽ mang lại một số lợi ích bổ sung, chẳng hạn như làm cho các vùng cao có thể lựa chọn bằng một cú click chuột (điều này sẽ rất tuyệt vời!) – benjismith

3

Cách khác, có thuật toán marching squares mà dường như phù hợp với bạn vấn đề, mặc dù bạn có thể muốn làm mịn các kết quả nếu bạn sử dụng một lưới thô.

Đường cong trên cùng bạn muốn vẽ là isosurfaces của trường vô hướng trên 2 thứ nguyên. Đối với các mặt phẳng trong 3 chiều, có thuật toán marching cubes.

2

Tôi đã muốn một cái gì đó như thế này bản thân mình, nhưng đã không tìm thấy một giải pháp dựa trên vector.

Một giải pháp dựa trên raster không phải là xấu, mặc dù, đặc biệt là nếu dữ liệu của bạn dựa trên raster. Nếu dữ liệu của bạn cũng dựa trên vectơ (nói cách khác, bạn có mô hình 3D bề mặt của bạn), bạn sẽ có thể thực hiện một số phép toán thực để tìm các đường giao nhau với các mặt phẳng nằm ngang ở các độ cao khác nhau.

Để biết cách tiếp cận dựa trên raster, tôi nhìn vào từng cặp pixel lân cận. Nếu một ở trên một mức đường bao, và một là dưới đây, rõ ràng là một đường đồng mức chạy giữa chúng. Bí quyết tôi sử dụng để chống bí danh đường viền là để trộn màu đường viền thành cả hai pixel, tỷ lệ thuận với độ gần của chúng với đường đồng mức lý tưởng.

Có thể một số ví dụ sẽ hữu ích. Giả sử rằng điểm ảnh hiện tại là "độ cao" 12 ft, một người hàng xóm ở độ cao 8 ft và đường bao là 10 ft. Sau đó, có một đường viền nằm giữa đường; tô điểm ảnh hiện tại bằng màu đường viền với độ mờ là 50%. Một điểm ảnh khác là 11 feet và có một người hàng xóm ở độ cao 6 feet. Tô màu pixel hiện tại với độ mờ là 80%.

alpha = (contour - neighbor)/(current - neighbor) 

Thật không may, tôi không có mã tiện dụng, và có thể đã được hơn một chút để nó (Tôi mơ hồ nhớ lại nhìn vào các nước láng giềng chéo quá, và điều chỉnh bởi sqrt(2)/2). Tôi hy vọng điều này đủ để cung cấp cho bạn ý chính.

+0

Tôi không có mô hình 3D, nhưng bất kỳ bề mặt nào trong hệ thống của tôi đều có thể biểu diễn như một phương trình, vì vậy nó chắc chắn đủ điều kiện như là một biểu diễn vector chính xác tùy ý. Nhưng phương trình là biiiiiiig và khó chịu. Ví dụ: hình ảnh trên trang này sử dụng phương trình có hơn 300 cụm từ. Đó là waaaaay xấu xí. – benjismith

+0

Có, tôi còn nhớ câu hỏi khác của bạn về việc đặt sẵn tập dữ liệu cho nội suy. Bạn có thể sử dụng điều đó để làm điều gì đó chính xác hơn so với nội suy tuyến tính, nhưng vì đầu ra mục tiêu của bạn vẫn là một pixel, sự khác biệt có thể không hiển thị. – erickson

+0

Tôi thích cách tiếp cận của bạn để xác định xem đường đồng mức có chạy * giữa * hai pixel hay không. Cách tiếp cận mà tôi đã thực hiện trong kết xuất của tôi (ở trên) là để xem liệu giá trị pixel là * đóng * với đường bao thực, được cho một số epsilon tùy ý hay không. (... tiếp tục ...) – benjismith

3

Để trả lời nhận xét của bạn về @erickson và để trả lời điểm về việc tính toán độ dốc của hàm của bạn. Thay vì tính toán các dẫn xuất của hàm số hạng 300 của bạn, bạn có thể làm một sự phân biệt số như sau.

Cho một điểm [x, y] trong hình ảnh của bạn, bạn có thể tính toán gradient (hướng dốc phong nha)

g={ (f(x+dx,y)-f(x-dx,y))/(2*dx), 
    { (f(x,y+dy)-f(x,y-dy))/(2*dy) 

nơi dx và dy có thể là khoảng cách trong mạng lưới của bạn. Đường đồng mức sẽ chạy vuông góc với gradient. Vì vậy, để có được hướng đường bao, c, chúng ta có thể nhân g = [v, w] bởi ma trận, A = [0 -1, 1 0] cho

c = [-w,v] 
+0

Vâng, đây là suy nghĩ đầu tiên của tôi, để có được một phép đo thực nghiệm về độ dốc x và độ dốc y. Nhưng tôi không biết cách biến nó thành gradient. Vì vậy, tôi bắt đầu làm việc trên tính toán các dẫn xuất từng phần cho toàn bộ hàm lớn. Cảm ơn bạn đã lừa ma trận nhân! – benjismith

+0

chào mừng bạn. vui vì nó đã giúp. – Azim

1

Nó xảy ra với tôi rằng những gì bạn đang cố gắng làm sẽ khá dễ làm trong MATLAB, sử dụng hàm đường bao. Làm những việc như tạo ra các xấp xỉ mật độ thấp cho các đường nét của bạn có thể được thực hiện với một số xử lý hậu kỳ khá đơn giản của các đường bao.

May mắn thay, GNU Octave, một bản sao MATLAB, đã triển khai các chức năng vẽ đường bao khác nhau. Bạn có thể xem mã đó cho một thuật toán và thực hiện gần như chắc chắn là âm thanh toán học. Hoặc, bạn có thể chỉ có thể giảm tải việc xử lý sang Octave. Kiểm tra trang trên interfacing with other languages để xem điều đó có dễ dàng hơn không.

Tiết lộ: Tôi chưa sử dụng Octave rất nhiều và tôi chưa thực sự thử nghiệm âm mưu đường viền của nó. Tuy nhiên, từ kinh nghiệm của tôi với MATLAB, tôi có thể nói rằng nó sẽ cung cấp cho bạn gần như tất cả mọi thứ bạn đang yêu cầu chỉ trong một vài dòng mã, miễn là bạn lấy dữ liệu của bạn vào MATLAB.

Ngoài ra, xin chúc mừng bạn đã tạo ra một âm mưu slopefield rất hiệu quả.

0

Viết dữ liệu dưới dạng HGT file (định dạng dữ liệu độ cao kỹ thuật số rất đơn giản được USGS sử dụng) và sử dụng công cụ miễn phí và mã nguồn mở gdal_contour để tạo đường nét. Điều đó hoạt động rất tốt cho các bản đồ trên mặt đất, ràng buộc là các điểm dữ liệu được ký số 16 bit, phù hợp với chiều cao của đất theo mét rất tốt, nhưng có thể không đủ cho dữ liệu của bạn, mà tôi cho rằng không phải là bản đồ địa hình thực tế - mặc dù bạn đề cập đến bản đồ địa hình.

0

Tôi khuyên bạn nên cách tiếp cận CONREC:

  • Tạo một danh sách phân khúc dòng trống
  • Chia dữ liệu của bạn vào ô vuông lưới thường xuyên
  • Đối với mỗi ô vuông, chia hình vuông thành 4 hình tam giác thành phần:
    • Đối với mỗi hình tam giác, hãy xử lý các trường hợp (từ a đến j):
      • Nếu đoạn đường đi qua một trong t ông trường hợp:
        • Tính điểm cuối của nó
        • Store đoạn thẳng trong danh sách
  • Vẽ từng phân khúc dòng trong danh sách phân khúc dòng

Nếu dòng quá lởm chởm, sử dụng lưới nhỏ hơn. Nếu các dòng này đủ mượt và thuật toán mất quá nhiều thời gian, hãy sử dụng lưới lớn hơn.

Các vấn đề liên quan