2012-06-03 12 views
16

Tôi đang phát triển ứng dụng để theo dõi động vật nhỏ trong đĩa Petri (hoặc các hộp chứa hình tròn khác). Trước khi thực hiện theo dõi, một vài khung hình đầu tiên được sử dụng để xác định các khu vực. Mỗi món ăn sẽ khớp với khu vực tĩnh độc lập tròn (tức là sẽ không được cập nhật trong khi theo dõi). Người dùng có thể yêu cầu chương trình tìm cách tìm các món ăn từ hình ảnh gốc và sử dụng chúng làm khu vực.Mạnh mẽ tìm thấy N vòng tròn có cùng đường kính: thay thế cho bruteforcing Hough transform threshold

Dưới đây là ví dụ: enter image description here enter image description here

Để thực hiện nhiệm vụ này, tôi đang sử dụng Hough Vòng Chuyển. Nhưng trên thực tế, những người dùng khác nhau sẽ có cài đặt và hình ảnh rất khác nhau và tôi không muốn yêu cầu người dùng xác định các tham số theo cách thủ công. Tôi không thể đoán được tất cả các tham số.

Tuy nhiên, tôi có thêm thông tin mà tôi muốn sử dụng:

Tôi biết chính xác số vòng kết nối được phát hiện.

  • Tất cả các vòng kết nối có cùng kích thước.
  • Vòng kết nối không thể trùng lặp.
  • Tôi có ý tưởng sơ bộ về kích thước tối thiểu và tối đa của vòng kết nối.
  • Các vòng tròn phải hoàn toàn trong ảnh.

Do đó, tôi có thể thu hẹp số tham số để xác định thành một: ngưỡng. Sử dụng những thông tin này và xem xét rằng tôi có N vòng kết nối để tìm, giải pháp hiện tại của tôi là kiểm tra nhiều giá trị ngưỡng và giữ vòng tròn giữa độ lệch chuẩn là nhỏ nhất (vì tất cả các vòng tròn phải có kích thước tương tự):

//at this point, minRad and maxRad were calculated from the size of the image and the number of circles to find. 
//assuming circles should altogether fill more than 1/3 of the images but cannot be altogether larger than the image. 
//N is the integer number of circles to find. 
//img is the picture of the scene (filtered). 

//the vectors containing the detected circles and the --so far-- best circles found. 
std::vector<cv::Vec3f> circles, bestCircles; 

//the score of the --so far-- best set of circles 
double bestSsem = 0; 

for(int t=5; t<400 ; t=t+2){ 
//Apply Hough Circles with the threshold t 
    cv::HoughCircles(img, circles, CV_HOUGH_GRADIENT, 3, minRad*2, t,3, minRad, maxRad); 

    if(circles.size() >= N){ 
//call a routine to give a score to this set of circles according to the similarity of their radii 
     double ssem = scoreSetOfCircles(circles,N); 
//if no circles are recorded yet, or if the score of this set of circles is higher than the former best 
     if(bestCircles.size() < N || ssem > bestSsem){ 
//this set become the temporary best set of circles 
       bestCircles=circles; 
       bestSsem=ssem; 
     } 
    } 
} 

Với:

//the methods to assess how good is a set of circle (the more similar the circles are, the higher is ssem) 
    double scoreSetOfCircles(std::vector<cv::Vec3f> circles, int N){ 
    double ssem=0, sum = 0; 
     double mean; 
     for(unsigned int j=0;j<N;j++){ 
      sum = sum + circles[j][2]; 
     } 
     mean = sum/N; 
     for(unsigned int j=0;j<N;j++){ 
      double em = mean - circles[j][2]; 
      ssem = 1/(ssem + em*em); 
     } 
    return ssem; 

}

tôi đã đạt đến một độ chính xác cao hơn bằng cách thực hiện một pas thứ hai s trong đó tôi lặp lại thuật toán này thu hẹp khoảng [minRad: maxRad] sử dụng kết quả của pass đầu tiên.

Ví dụ minRad2 = 0,95 * bán kính trung bình của các vòng kết nối tốt nhất và maxRad2 = 1,05 * bán kính trung bình của các vòng kết nối tốt nhất.

Tôi đã có kết quả khá tốt bằng cách sử dụng phương pháp này cho đến nay. Tuy nhiên, nó là chậm và khá bẩn. Câu hỏi của tôi là:

  • Bạn có thể điều gì về giải thuật thay thế để giải quyết vấn đề này một cách sạch hơn/nhanh hơn không?
  • Hoặc bạn sẽ đề xuất gì để cải thiện thuật toán này?
  • Bạn có nghĩ rằng tôi nên điều tra biến đổi Hough tổng quát không?

Cảm ơn câu trả lời và đề xuất của bạn.

+0

những thứ đó trong món ăn là gì? –

+8

Chúng là những nhịp đập, nhưng chương trình sẽ hoạt động với nhiều lỗi khác nhau :) –

+2

Không có gì về thuật toán, nhưng bạn có thể tận dụng lợi thế của C++ 11 nếu bạn chưa sử dụng nó (container tiêu chuẩn nhanh hơn) và các chức năng như std :: fma để có độ chính xác cao hơn với một số nội dung. Và sử dụng "a + = b" thay vì "a = a + b". Tất cả điều đó chỉ là về cú pháp C++ vì vậy nó sẽ không cải thiện thuật toán mà chỉ là hàm C++ của nó. – Morwenn

Trả lời

10

Phương pháp sau đây nên làm việc khá tốt cho trường hợp của bạn:

  1. Binarize hình ảnh của bạn (bạn có thể cần phải làm điều này trên nhiều cấp độ của ngưỡng để thực hiện thuật toán phụ thuộc vào điều kiện ánh sáng)
  2. Tìm đường nét
  3. Đối với mỗi đường viền tính toán những khoảnh khắc
  4. Lọc họ theo khu vực để loại bỏ đường viền quá nhỏ
  5. Lọc đường viền bằng giấy cáo bạch:

    double area = moms.m00; 
    double perimeter = arcLength(Mat(contours[contourIdx]), true); 
    double ratio = 4 * CV_PI * area/(perimeter * perimeter); 
    

    ratio gần 1 sẽ cung cấp cho bạn vòng kết nối.

  6. Tính bán kính và tâm của mỗi vòng tròn

    center = Point2d(moms.m10/moms.m00, moms.m01/moms.m00); 
    

Và bạn có thể bổ sung thêm các bộ lọc để cải thiện sự vững mạnh.

Thực ra bạn có thể tìm thấy việc triển khai toàn bộ quy trình trong OpenCV. Hãy xem cách lớp SimpleBlobDetector và chức năng findCirclesGrid được triển khai.

+0

Cảm ơn bạn, tôi thích đề xuất của bạn. Vấn đề duy nhất của tôi, là một thực tế rằng, theo như tôi hiểu nó, nó đòi hỏi một sự tương phản tốt và có thể dự đoán được giữa bên trong và bên ngoài của các vòng tròn (hoặc các cạnh liên tục). Tôi đã không chụp ảnh các trường hợp mà độ tương phản sẽ thấp nhưng, ví dụ, người thử nghiệm có thể làm việc với các tấm như thế này: http://www.pioneerscientific.com/Merchant5/graphics/00000002/12%20well % 20plates% 20full-1.jpg và đặt một con vật ở mỗi giếng ... Ngoài ra, người thử nghiệm có thể làm việc với động vật rõ ràng trong nền tối. –

5

Trong thuật toán hiện tại, điều quan trọng nhất là loại vòng lặp for(int t=5; t<400; t=t+2). Đang thử ghi lại giá trị điểm số cho một số hình ảnh thử nghiệm. Biểu đồ score(t) so với t. Với bất kỳ may mắn nào, nó sẽ gợi ý phạm vi nhỏ hơn cho t hoặc là một đường cong mượt mà với một cực đại duy nhất. Trong trường hợp thứ hai, bạn có thể thay đổi vòng lặp của mình trên tất cả các giá trị t thành tìm kiếm thông minh hơn bằng cách sử dụng phương thức Hill Climbing.

Thậm chí nếu nó khá ồn ào, bạn có thể lặp đầu tiên trên bội số của, nói, 30 tuổi, và cho là tốt nhất 1 hoặc 2 trong những vòng lặp qua bội số gần đó 2.

Ngoài ra, trong chức năng điểm số của bạn, bạn nên loại bỏ bất kỳ kết quả nào với các vòng tròn trùng lặp và có thể phạt các vòng tròn cách nhau quá mức.

+0

Cảm ơn bạn, tôi sẽ thấy hình dạng của Điểm (t) so với t và xem liệu tôi có thể sử dụng kỹ thuật tối ưu hóa như vậy trong hầu hết các trường hợp không. –

3

Bạn không giải thích tại sao bạn đang sử dụng nền đen. Trừ khi bạn đang sử dụng ống kính telecentric (có vẻ như không chắc chắn, với trường nhìn rõ ràng) và bỏ qua biến dạng xuyên tâm cho thời điểm này, hình ảnh của các món ăn sẽ là hình elip, vì vậy việc ước tính chúng dưới dạng vòng tròn có thể dẫn đến lỗi nghiêm trọng.

Tất cả và tất cả, dường như tôi không tuân thủ một cách tiếp cận tốt. Nếu mục tiêu chỉ đơn giản là xóa nền, vì vậy bạn có thể theo dõi các lỗi bên trong các món ăn, thì mục tiêu của bạn phải là như vậy: tìm các pixel nào là nền và đánh dấu chúng. Cách dễ nhất để làm điều đó là chụp ảnh nền mà không có đĩa, dưới cùng một ánh sáng và máy ảnh, và trực tiếp phát hiện sự khác biệt với hình ảnh với hình ảnh. Một nền màu sẽ thích hợp hơn để làm điều đó, với một màu không xuất hiện trong các món ăn (ví dụ: màu xanh lá cây hoặc màu xanh nhung). Vì vậy, bạn đã giảm vấn đề để bluescreening (hoặc key key chroma), một kỹ thuật cổ điển trong tầm nhìn máy như được áp dụng cho các hiệu ứng hình ảnh. Thực hiện tìm kiếm trên google cho "giả định mờ ảo vattos" để tìm các thuật toán cổ điển để giải quyết vấn đề này.