2010-06-07 34 views
8

Tôi cần tính chiều dài của đối tượng trong một hình ảnh nhị phân (khoảng cách tối đa giữa các pixel bên trong đối tượng). Vì nó là một hình ảnh nhị phân, nên chúng ta có thể xem nó là một mảng 2D với các giá trị 0 (màu trắng) và 1 (màu đen). Điều tôi cần là một thuật toán thông minh (và tốt hơn là đơn giản) để thực hiện thao tác này. Hãy ghi nhớ có nhiều đối tượng trong hình ảnh.Tính chiều dài của các đối tượng theo hình ảnh nhị phân - thuật toán

Những hình ảnh để làm rõ: hình ảnh đầu vào

alt text http://cl.ly/489019a048c1bf20c6bb/content

mẫu:

alt text http://cl.ly/f5c379e59deef435f365/content

+0

Vấn đề nhỏ gọn - trông giống như gạo? Hạt giống? –

+0

Dung dịch cần phải nhanh như thế nào? Bạn cũng cần một giải pháp chính xác? – shuttle87

+0

@Mark B. - gạo thực sự, @ shuttle87 - không phải chính xác 100%. – Jacek

Trả lời

3

Tôi nghĩ vấn đề rất đơn giản nếu các ranh giới của một đối tượng là lồi và không có ba đỉnh là trên một dòng (tức là không có đỉnh có thể được gỡ bỏ mà không cần thay đổi đa giác): Sau đó, bạn chỉ có thể chọn hai điểm một cách ngẫu nhiên và sử dụng một loại tìm kiếm gradient descent đơn giản để tìm thấy những dòng dài nhất:

Start with random vertices A, B 
See if the line A' - B is longer than A - B where A' is the point left of A; if so, replace A with A' 
See if the line A' - B is longer than A - B where A' is the point right of A; if so, replace A with A' 
Do the same for B 
repeat until convergence 

vì vậy, tôi muốn đề nghị tìm kiếm thân lồi cho mỗi blob giống, loại bỏ tất cả các "superfluos" đỉnh (để đảm bảo hội tụ) và runn ing các thuật toán ở trên.

Xây dựng thân lồi là một hoạt động O (n log n) IIRC, trong đó n là số lượng điểm ảnh ranh giới. Nên được khá hiệu quả cho các đối tượng nhỏ như thế này. EDIT: Tôi chỉ nhớ rằng O (n log n) cho thuật toán lồi lồi là cần thiết để sắp xếp các điểm. Nếu các điểm ranh giới là kết quả của một phân tích thành phần được kết nối, chúng đã được sắp xếp. Vì vậy, toàn bộ thuật toán sẽ chạy trong thời gian O (n), trong đó n là số điểm ranh giới. (Đó là rất nhiều công việc, tuy nhiên, vì bạn có thể phải viết thuật toán lồi-thân của riêng bạn hoặc chỉnh sửa một để bỏ qua các loại.)

Add: Trả lời bình luận

Nếu bạn không cần độ chính xác 100%, bạn có thể đơn giản phù hợp với hình elip với từng đốm màu và tính chiều dài của trục chính: Điều này có thể được tính từ central moments (IIRC đơn giản là căn bậc hai nếu giá trị riêng lớn nhất của ma trận hiệp phương sai), vì vậy nó là O (n) hoạt động và hiệu quả có thể được tính toán trong một lần quét qua hình ảnh. Nó có lợi thế bổ sung là nó lấy tất cả các điểm ảnh của một đốm màu vào tài khoản, không chỉ là hai điểm cực trị, tức là nó ít bị ảnh hưởng bởi tiếng ồn.

+0

ahh có tính toán các thành phần kết nối và vỏ lồi của mỗi thành phần kết nối sẽ cung cấp cho bạn một xấp xỉ tốt cung cấp các hình dạng có phần phức tạp. – ldog

+0

@gmatt: Đây không phải là xấp xỉ. Tôi khá chắc chắn rằng các điểm cực đoan mà anh ta tìm kiếm luôn ở trên thân lồi. Sử dụng vỏ lồi không thêm bất kỳ điểm mới nào, nó chỉ loại bỏ các điểm không thể là giải pháp được. – Niki

+0

thực sự, tôi nghĩ rằng một phát hiện cạnh đơn giản có thể làm việc tốt hơn để có được phác thảo hơn là đầy đủ ra lồi lồi trên mỗi blob riêng biệt/hình dạng. Ngoài ra tôi không nghĩ rằng nguồn gốc gradient là cách tốt nhất để làm điều này, quá tiêu thụ tài nguyên. – ldog

1

Một cách tiếp cận rất thô, brute-force sẽ được đầu tiên xác định tất cả các điểm ảnh cạnh (bất kỳ pixel đen trong đối tượng liền kề với một pixel không phải màu đen) và tính toán khoảng cách giữa tất cả các cặp pixel cạnh có thể. Khoảng cách dài nhất của những khoảng cách này sẽ cho bạn độ dài của vật thể.

Nếu các đối tượng luôn có hình dạng giống như trong mẫu của bạn, bạn có thể tăng tốc độ này bằng cách chỉ đánh giá các pixel có giá trị x và y cao nhất và thấp nhất trong đối tượng.

1

Tôi khuyên bạn nên thử chuyển đổi khoảng cách "đảo ngược". Trong thế giới phép thuật của hình thái toán học (xin lỗi không thể chống lại sự lặp lại), phép biến đổi khoảng cách cung cấp cho bạn khoảng cách gần nhất của mỗi pixel tới điểm ảnh ranh giới gần nhất. Trong trường hợp của bạn, bạn quan tâm đến khoảng cách xa nhất đến một điểm ảnh ranh giới, do đó tôi đã khéo léo áp dụng một tiền tố "đảo ngược".

Bạn có thể tìm thông tin về biến đổi khoảng cách herehere. Tôi tin rằng MATLAB thực hiện phép biến đổi khoảng cách theo here. Điều đó sẽ khiến tôi tin rằng bạn có thể tìm thấy việc thực hiện mã nguồn mở của biến đổi khoảng cách trong octave. Hơn nữa, nó sẽ không làm tôi ngạc nhiên ít nhất nếu opencv triển khai nó.

Tôi đã không suy nghĩ nhiều nhưng trực quan với tôi rằng bạn sẽ có thể đảo ngược biến đổi khoảng cách và tính toán nó trong khoảng thời gian tương tự như biến đổi khoảng cách ban đầu.

1

Tôi nghĩ bạn có thể xem xét sử dụng thuật toán breadth first search.

Ý tưởng cơ bản là bạn lặp qua từng hàng và cột trong hình ảnh và nếu bạn chưa truy cập nút (nút là hàng và cột có pixel màu), thì bạn sẽ chạy chiều rộng tìm kiếm đầu tiên. Bạn sẽ ghé thăm mỗi nút bạn có thể có thể, và theo dõi các điểm tối đa và min cho đối tượng.

Dưới đây là một số mã C++ mẫu (chưa được kiểm tra):

#include <vector> 
#include <queue> 
#include <cmath> 
using namespace std; 

// used to transition from given row, col to each of the 
// 8 different directions 
int dr[] = { -1, 0, 1, -1, 1, -1, 0, 1 }; 
int dc[] = { -1, -1, -1, 0, 0, 1, 1, 1 }; 

// WHITE or COLORED cells 
const int WHITE = 0; 
const int COLORED = 1; 

// number of rows and columns 
int nrows = 2000; 
int ncols = 2000; 

// assume G is the image 
int G[2000][2000]; 

// the "visited array" 
bool vis[2000][2000]; 

// get distance between 2 points 
inline double getdist(double x1, double y1, double x2, double y2) { 
    double d1 = x1 - x2; 
    double d2 = y1 - y2; 
    return sqrt(d1*d1+d2*d2); 
} 

// this function performs the breadth first search 
double bfs(int startRow, int startCol) { 
    queue<int> q; 

    q.push(startRow); 
    q.push(startCol); 

    vector< pair< int, int > > points; 

    while(!q.empty()) { 
    int r = q.front(); 
    q.pop(); 
    int c = q.front(); 
    q.pop(); 

    // already visited? 
    if (vis[r][c]) 
     continue; 


    points.push_back(make_pair(r,c));  

    vis[r][c] = true; 

    // try all eight directions 
    for(int i = 0; i < 8; ++i) { 
     int nr = r + dr[i]; 
     int nc = c + dc[i]; 

     if (nr < 0 || nr >= nrows || nc < 0 || nc >= ncols) 
     continue; // out of bounds 

     // push next node on queue 
     q.push(nr); 
     q.push(nc); 

    }  
    } 

    // the distance is maximum difference between any 2 points encountered in the BFS 
    double diff = 0; 
    for(int i = 0; i < (int)points.size(); ++i) { 
    for(int j = i+1; j < (int)points.size(); ++j) { 
     diff = max(diff,getdist(points[i].first,points[i].second,points[j].first,points[j].second)); 
    } 
    } 
    return diff; 
} 

int main() { 

    vector<double> lengths; 

    memset(vis,false,sizeof vis); 
    for(int r = 0; r < nrows; ++r) { 
    for(int c = 0; c < ncols; ++c) { 
     if (G[r][c] == WHITE) 
     continue; // we don't care about cells without objects 
     if (vis[r][c]) 
     continue; // we've already processed this object 

     // find the length of this object 
     double len = bfs(r,c); 
     lengths.push_back(len); 
    } 
    } 

    return 0; 
} 
+0

Chạm vào từng điểm ảnh của hạt * âm thanh * không hiệu quả nếu bạn chỉ muốn tìm hai điểm trên ranh giới. – Niki

+0

danh sách bao gồm dài hơn mã nguồn! bạn sử dụng số phức ở đâu? – ldog

+0

@gmatt - Xin lỗi, đây là từ mẫu cuộc thi lập trình của tôi, tôi luôn có thói quen để chúng ở đó nhưng tôi đồng ý với diễn đàn này có lẽ không phải là ý hay. Cảm ơn đã chỉ ra điều đó. – dcp

2

Tìm chiều dài trục chính của hình elip có cùng giây phút trung tâm được chuẩn hóa như khu vực. Trong MATLAB, bạn có thể sử dụng regionprops.

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