2012-06-07 11 views
6

Me estoy acercando a una tarea de Biografía, y necesito extraer algunas características de algunas imágenes de celda.Descartar valores atípicos Puntos clave SIFT en la imagen de celda con OpenCV

Utilicé el algoritmo SIFT para extraer los puntos clave dentro de la imagen, como se puede ver en la imagen.

enter image description here

Como también se puede ver en la imagen (círculo rojo), algunos puntos clave son valores atípicos y no quiero para calcular cualquier característica en ellos.

que obtuvo el vector cv::KeyPoint con el siguiente código:

const cv::Mat input = cv::imread("/tmp/image.jpg", 0); //Load as grayscale 

cv::SiftFeatureDetector detector; 
std::vector<cv::KeyPoint> keypoints; 
detector.detect(input, keypoints); 

pero me gustaría que descartar a partir de los vector todos esos puntos clave que, digamos por ejemplo, tienen menos de 3 puntos clave dentro de un cierto región de interés (ROI) centrada en ellos en la imagen.

por lo tanto necesito para implementar una función que devuelve el número de puntos clave dentro de un cierto retorno de la inversión dada como entrada:

int function_returning_number_of_key_points_in_ROI(cv::KeyPoint, ROI); 
    //I have not specified ROI on purpose...check question 3 

Tengo tres preguntas:

  1. ¿Hay alguna función existente haciendo ¿algo parecido?
  2. Si no, ¿me puede ayudar a entender cómo implementarlo?
  3. ¿Utilizaría un ROI circular o rectangular para esta tarea? ¿Y cómo lo especificaría en la entrada?

Nota:

me olvidó especificar que me gustaría una implementación eficiente de la función, es decir, la comprobación de cada punto clave de la posición relativa de todos los demás con respecto a que no sería una buena solución (si existe otra forma de hacerlo).

+1

¿Se puede publicar la imagen original? Me gustaría probar algo, y luego publicar los resultados si es exitoso :) – mevatron

+0

@mevatron - http://s18.postimage.org/jayhj4q3d/phase1_image1.jpg aquí va, he subido la versión RGB, simplemente conviértalo en escala de grises si así lo desea ... hágamelo saber lo que está haciendo;) – Matteo

+0

Puede usar RANSAC, si puede definir un modelo. RANSAC decidirá qué puntos son inliers (se ajustan al modelo) y atípicos (no se ajusta al modelo). Tal vez su modelo puede ser algo así como un 3 puntos que definen un área más pequeña que X (significa que están lo suficientemente cerca). Es una idea –

Respuesta

8

Decidí seguir la ruta estadística, pero puede que esto no funcione si tiene varias celdas a la vista.

Mi solución es bastante sencilla:

  1. Calcular las ubicaciones KeyPoint
  2. Encontrar el centroide de las localizaciones espaciales KeyPoint
  3. calcular la distancia euclídea de todos los puntos al centroide
  4. Filtrar puntos clave originales por distance < mu + 2*sigma

Aquí está la imagen que g et utilizando este algoritmo (puntos clave == verde, centroide == rojo):

enter image description here

Por último, aquí está el ejemplo de código de cómo lo hice:

#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
#include <opencv2/features2d/features2d.hpp> 

#include <iostream> 
#include <vector> 

using namespace cv; 
using namespace std; 

void distanceFromCentroid(const vector<Point2f>& points, Point2f centroid, vector<double>& distances) 
{ 
    vector<Point2f>::const_iterator point; 
    for(point = points.begin(); point != points.end(); ++point) 
    { 
     double distance = std::sqrt((point->x - centroid.x)*(point->x - centroid.x) + (point->y - centroid.y)*(point->y - centroid.y)); 
     distances.push_back(distance); 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    Mat input = imread("cell.jpg", 0); //Load as grayscale 

    SiftFeatureDetector detector; 
    vector<cv::KeyPoint> keypoints; 
    detector.detect(input, keypoints); 

    vector<Point2f> points; 
    vector<KeyPoint>::iterator keypoint; 
    for(keypoint = keypoints.begin(); keypoint != keypoints.end(); ++keypoint) 
    { 
     points.push_back(keypoint->pt); 
    } 

    Moments m = moments(points, true); 
    Point2f centroid(m.m10/m.m00, m.m01/m.m00); 

    vector<double> distances; 
    distanceFromCentroid(points, centroid, distances); 

    Scalar mu, sigma; 
    meanStdDev(distances, mu, sigma); 

    cout << mu.val[0] << ", " << sigma.val[0] << endl; 

    vector<KeyPoint> filtered; 
    vector<double>::iterator distance; 
    for(size_t i = 0; i < distances.size(); ++i) 
    { 
     if(distances[i] < (mu.val[0] + 2.0*sigma.val[0])) 
     { 
      filtered.push_back(keypoints[i]); 
     } 
    } 

    Mat out = input.clone(); 
    drawKeypoints(input, filtered, out, Scalar(0, 255, 0)); 

    circle(out, centroid, 7, Scalar(0, 0, 255), 1); 

    imshow("kpts", out); 
    waitKey(); 

    imwrite("statFilter.png", out); 

    return 0; 
} 

Espero que ayude!

+0

¡¡¡Realmente la solución que usted propuso es realmente clara y directa !! Sin embargo, como habrás notado, esto puede tener problemas cuando hay más de una celda contenida en la imagen. En mi conjunto de datos hay algunas imágenes malas, pero estoy tratando de limpiar descartando esas muestras. Me atendré a esta solución por ahora, y en caso de pedir ayuda adicional. ;) THKS TANTO ... – Matteo

+2

¡Impresionante! Me alegra que lo haya encontrado útil; Por cierto, el problema es genial :) Estaba pensando que si tiene varias celdas, es posible que pueda realizar algún tipo de operación de agrupamiento (Vecinos más cercanos o algo similar) como un paso de procesamiento previo, y procesarlos por separado de esa manera. – mevatron

+1

Es un proyecto en Bioinformática, ¡necesito clasificar la evolución de las células mediante el análisis de su morfología! Y esto es solo el comienzo;) también la idea de k-means parece realmente inteligente, lo intentaré y, si está interesado, encuentre la forma de que sepa la evolución del proyecto. – Matteo

Cuestiones relacionadas