Estoy intentando encontrar las esquinas de una imagen, no necesito los contornos, sólo las 4 esquinas. Voy a cambiar la perspectiva con 4 esquinas.

Estoy usando Opencv, pero necesito saber los pasos para encontrar las esquinas y cuál es la función que voy a utilizar.

Mis imágenes como este:(sin puntos rojos, voy a pintar los puntos después)
Cómo encontrar las esquinas de una Imagen usando OpenCv

EDITADO:

Después de los pasos sugeridos, he escrito el código: (Nota: no estoy usando puro OpenCv, estoy usando javaCV, pero la lógica es la misma).

//Load two images and allocate other structures (I´m using other image)
    IplImage colored = cvLoadImage(
            "res/scanteste.jpg",
            CV_LOAD_IMAGE_UNCHANGED);

Cómo encontrar las esquinas de una Imagen usando OpenCv

    IplImage gray = cvCreateImage(cvGetSize(colored), IPL_DEPTH_8U, 1);
    IplImage smooth = cvCreateImage(cvGetSize(colored), IPL_DEPTH_8U, 1);

    //Step 1 - Convert from RGB to grayscale (cvCvtColor)
    cvCvtColor(colored, gray, CV_RGB2GRAY);

Cómo encontrar las esquinas de una Imagen usando OpenCv

    //2 Smooth (cvSmooth)
    cvSmooth( gray, smooth, CV_BLUR, 9, 9, 2, 2); 

Cómo encontrar las esquinas de una Imagen usando OpenCv

    //3 - cvThreshold  - What values?
    cvThreshold(gray,gray, 155, 255, CV_THRESH_BINARY);

Cómo encontrar las esquinas de una Imagen usando OpenCv

    //4 - Detect edges (cvCanny) -What values?
    int N = 7;
    int aperature_size = N;
    double lowThresh = 20;
    double highThresh = 40;     
    cvCanny( gray, gray, lowThresh*N*N, highThresh*N*N, aperature_size );   

Cómo encontrar las esquinas de una Imagen usando OpenCv

    //5 - Find contours (cvFindContours)
    int total = 0;
    CvSeq contour2 = new CvSeq(null);
    CvMemStorage storage2 = cvCreateMemStorage(0);
    CvMemStorage storageHull = cvCreateMemStorage(0);
    total = cvFindContours(gray, storage2, contour2, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
    if(total > 1){
          while (contour2 != null && !contour2.isNull()) {
              if (contour2.elem_size() > 0) {
                //6 - Approximate contours with linear features (cvApproxPoly)
                  CvSeq points = cvApproxPoly(contour2,Loader.sizeof(CvContour.class), storage2, CV_POLY_APPROX_DP,cvContourPerimeter(contour2)*0.005, 0);
                  cvDrawContours(gray, points,CvScalar.BLUE, CvScalar.BLUE, -1, 1, CV_AA);

              }
              contour2 = contour2.h_next();
          }

    } 

Cómo encontrar las esquinas de una Imagen usando OpenCv

Así, quiero encontrar la cornes, pero no sé cómo usar las esquinas de la función como cvCornerHarris y otros.

  • OpenCV de la «esquina» de las funciones no se encuentran en las esquinas de manera que usted está pensando — a grandes rasgos, se encuentran áreas con importantes horizontal y vertical de la variación. El objetivo de la esquina de las funciones de OpenCV es encontrar piezas distintivas de la imagen que será útil para el seguimiento visual, que no es necesariamente lo que comúnmente se piensa como las esquinas.
  • El código exacto en stackoverflow.com/a/14368605/1832154 (excepto el cambio de tamaño de la parte, ya que su imagen es lo suficientemente pequeño ya) da i.imgur.com/hMdAlHX.png
  • Encontrar un umbral global y el uso de «contorno» (blob) de detección para este tipo de aplicación no es un enfoque sólido. La digitalización de los bordes horizontal y vertical de los bordes de la imagen hacia el interior sería razonable empezar si su solicitud es para encontrar un (distorsionada) rectángulo de papel.
InformationsquelleAutor Ricardo | 2011-08-31

5 Comentarios

  1. 35

    Primero, echa un vistazo /muestras/c/plazas.c en su OpenCV distribución. Este ejemplo proporciona una plaza de detector, y debe ser un muy buen inicio cómo detectar la esquina-como características. A continuación, echar un vistazo a la función de OpenCV orientado a funciones como cvCornerHarris() y cvGoodFeaturesToTrack().

    Los métodos anteriores pueden volver muchos esquina características similares a la de – más no será el verdadero «esquinas» que usted está buscando. En mi aplicación, he tenido a detectar las plazas que había sido girada o inclinada (debido a la perspectiva). Mi detección de tubería consistió en:

    1. Convertir de RGB a escala de grises (cvCvtColor)
    2. Suave (cvSmooth)
    3. Umbral (cvThreshold)
    4. La detección de bordes (cvCanny)
    5. Encontrar contornos (cvFindContours)
    6. Aproximado de contornos con características lineales (cvApproxPoly)
    7. Encontrar «rectángulos», que fueron las estructuras que: había polygonalized contornos de la posesión de 4 puntos, fueron de suficiente área, tenía bordes adyacentes fueron ~90 grados, había distancia entre «lo contrario» vértices era de suficiente tamaño, etc.

    Paso 7 era necesario porque una un poco de ruido de la imagen puede producir muchas de las estructuras que aparecen rectangular después de polygonalization. En mi solicitud, yo también tenía que lidiar con la plaza-como las estructuras que apareció dentro de, o se superponen la deseada plaza. He encontrado el contorno del área de la propiedad y centro de gravedad para ser útil a la hora de discernir el rectángulo adecuado.

    • Necesito un poco de ayuda con el paso 7, cómo utilizar cvCornerHarris, con mi ejemplo, véase la edición del post, me puedes ayudar?
    • Es cvSmooth algo así como un desenfoque Gaussiano? ¿Dilatar el resultado de cvCanny? ¿Cómo aproximado de contornos, digamos 5 esquinas (deformated plaza porque de sombras, etc.) o suqares con un poco de cresta. Su enfoque es más o menos lo que quiero hacer, pero estoy struggeling muy duro. ¿Puede dar algunos ejemplos de código? Sería muy útil.
  2. 13

    A primera vista, para un ojo humano hay 4 esquinas. Pero en la visión por ordenador, en una esquina se considera un punto que se ha gradiente importante cambio en la intensidad a través de su vecindario. El barrio puede ser un 4 píxeles de barrio o una de 8 píxeles de barrio.

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    En la ecuación proporcionada para encontrar el gradiente de intensidad, se ha considerado por 4 píxeles barrio CONSULTE LA DOCUMENTACIÓN DE.

    Aquí está mi enfoque de la imagen en cuestión. Tengo el código en python así:

    path = r'C:\Users\selwyn77\Desktop\Stack\corner'
    filename = 'env.jpg'
    
    img = cv2.imread(os.path.join(path, filename))
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)    #--- convert to grayscale 
    

    Es una buena opción para siempre el desenfoque de la imagen para eliminar los menos posibles gradiente de cambios y preservar los más intensos. He optado por elegir el filtro bilateral que a diferencia de la Gaussiana del filtro no se aplica a todos los píxeles en el barrio. Más bien, se desenfoca los píxeles que tiene la misma intensidad de píxeles a la de la central de píxeles. En resumen conserva los bordes y las esquinas de alto gradiente de cambio, pero se desdibuja las regiones que tienen un mínimo de un cambio de rasante.

    bi = cv2.bilateralFilter(gray, 5, 75, 75)
    cv2.imshow('bi',bi)
    

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    A un ser humano, no es una diferencia tan grande en comparación con la imagen original. Pero no importa. Ahora encontrar posibles esquinas:

    dst = cv2.cornerHarris(bi, 2, 3, 0.04)
    

    dst devuelve una matriz (de la misma forma 2D de la imagen) con los eigen valores obtenidos a partir de la última ecuación se mencionó AQUÍ.

    Ahora un umbral tiene que ser aplicado para seleccionar las esquinas más allá de un cierto valor. Voy a usar el que en la documentación:

    #--- create a black image to see where those corners occur ---
    mask = np.zeros_like(gray)
    
    #--- applying a threshold and turning those pixels above the threshold to white ---           
    mask[dst>0.01*dst.max()] = 255
    cv2.imshow('mask', mask)
    

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    Los píxeles blancos son regiones de posibles esquinas. Usted puede encontrar muchos rincones de vecinos el uno al otro.

    Para dibujar el seleccionado las esquinas de la imagen:

    img[dst > 0.01 * dst.max()] = [0, 0, 255]   #--- [0, 0, 255] --> Red ---
    cv2.imshow('dst', img)
    

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    (De color rojo píxeles son las esquinas, no tan visible)

    Con el fin de obtener una matriz de todos los píxeles con esquinas:

    coordinates = np.argwhere(mask)
    

    ACTUALIZACIÓN

    Variable coor es un array de arrays. La conversión a la lista de listas de

    coor_list = [l.tolist() for l in list(coor)]

    La conversión de los anteriores a la lista de tuplas

    coor_tuples = [tuple(l) for l in coor_list]

    Tengo una vida fácil y bastante ingenuo manera de encontrar a las 4 esquinas. Yo simplemente calcula la distancia de cada esquina, a cada esquina. He conservado las esquinas, cuya distancia superado un determinado umbral.

    Aquí está el código:

    thresh = 50
    
    def distance(pt1, pt2):
        (x1, y1), (x2, y2) = pt1, pt2
        dist = math.sqrt( (x2 - x1)**2 + (y2 - y1)**2 )
        return dist
    
    coor_tuples_copy = coor_tuples
    
    i = 1    
    for pt1 in coor_tuples:
    
        print(' I :', i)
        for pt2 in coor_tuples[i::1]:
            print(pt1, pt2)
            print('Distance :', distance(pt1, pt2))
            if(distance(pt1, pt2) < thresh):
                coor_tuples_copy.remove(pt2)      
        i+=1
    

    Antes de ejecutar el código anterior coor_tuples tenía todos los puntos de esquina:
    [(4, 42),
    (4, 43),
    (5, 43),
    (5, 44),
    (6, 44),
    (7, 219),
    (133, 36),
    (133, 37),
    (133, 38),
    (134, 37),
    (135, 224),
    (135, 225),
    (136, 225),
    (136, 226),
    (137, 225),
    (137, 226),
    (137, 227),
    (138, 226)]

    Después de ejecutar el fragmento de código que me quedé con 4 esquinas:

    [(4, 42), (7, 219), (133, 36), (135, 224)]

    ACTUALIZACIÓN 2

    Ahora todo lo que tienes que hacer es marcar estos 4 puntos en una copia de la imagen original.

    img2 = img.copy()
    for pt in coor_tuples:
        cv2.circle(img2, tuple(reversed(pt)), 3, (0, 0, 255), -1)
    cv2.imshow('Image with 4 corners', img2) 
    

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    • Gracias! Último paso: ¿cómo extraer sólo 4 puntos de las esquinas (útil para seguir la eliminación / corrección de perspectiva)? Qué es necesario para utilizar un algoritmo para encontrar grupos en los muchos puntos? («El que los píxeles blancos de las regiones de posibles esquinas. Usted puede encontrar muchos rincones de vecinos el uno al otro.») Puede agregar un ejemplo?
    • Verificación de la actualización. Esto es lo que yo tenía en mente.
    • Muchas gracias @JeruLuke!
  3. 1

    Aquí está una implementación usando cv2.goodFeaturesToTrack() para detectar esquinas. El enfoque es

    • Convertir la imagen a escala de grises
    • Realizar detección de bordes canny
    • Detectar esquinas
    • Opcionalmente realizar 4-punto de perspectiva de transformación para obtener la vista cenital de la imagen

    El uso de esta imagen inicial,

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    Después de la conversión a escala de grises, realizamos la detección de bordes canny

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    Ahora que tenemos un decente imagen binaria, podemos utilizar cv2.goodFeaturesToTrack()

    corners = cv2.goodFeaturesToTrack(canny, 4, 0.5, 50)
    

    Para los parámetros, le damos el astuto imagen, establecer el número máximo de las esquinas a 4 (maxCorners), la utilización de un mínimo de calidad aceptados de 0.5 (qualityLevel), y establecer el mínimo posible de la distancia Euclídea entre la devolución de las esquinas a 50 (minDistance). Aquí está el resultado

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    Ahora que hemos identificado las esquinas, se puede realizar una 4-punto de perspectiva de transformación para obtener una vista cenital del objeto. Hemos de primer orden de los puntos de las agujas del reloj, a continuación, dibuje el resultado en una máscara.

    Nota: podríamos haber encontrado contornos en el Canny imagen en lugar de hacer este paso para crear la máscara, pero pretender que sólo teníamos los 4 puntos de esquina para trabajar con

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    A continuación nos encontramos con los contornos de esta máscara y filtro usando cv2.arcLength() y cv2.approxPolyDP(). La idea es que si el contorno tiene 4 puntos, entonces debe ser nuestro objeto. Una vez que tenemos este contorno, realizamos una perspectiva de transformación

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    Finalmente podemos rotar la imagen dependiendo de la orientación deseada. Aquí está el resultado

    Cómo encontrar las esquinas de una Imagen usando OpenCv

    Código sólo para la detección de esquinas

    import cv2
    
    image = cv2.imread('1.png')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    canny = cv2.Canny(gray, 120, 255, 1)
    
    corners = cv2.goodFeaturesToTrack(canny,4,0.5,50)
    
    for corner in corners:
        x,y = corner.ravel()
        cv2.circle(image,(x,y),5,(36,255,12),-1)
    
    cv2.imshow('canny', canny)
    cv2.imshow('image', image)
    cv2.waitKey()
    

    Código para la detección de esquinas y la realización de la perspectiva de transformar

    import cv2
    import numpy as np
    
    def rotate_image(image, angle):
        # Grab the dimensions of the image and then determine the center
        (h, w) = image.shape[:2]
        (cX, cY) = (w /2, h /2)
    
        # grab the rotation matrix (applying the negative of the
        # angle to rotate clockwise), then grab the sine and cosine
        # (i.e., the rotation components of the matrix)
        M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
        cos = np.abs(M[0, 0])
        sin = np.abs(M[0, 1])
    
        # Compute the new bounding dimensions of the image
        nW = int((h * sin) + (w * cos))
        nH = int((h * cos) + (w * sin))
    
        # Adjust the rotation matrix to take into account translation
        M[0, 2] += (nW /2) - cX
        M[1, 2] += (nH /2) - cY
    
        # Perform the actual rotation and return the image
        return cv2.warpAffine(image, M, (nW, nH))
    
    def order_points_clockwise(pts):
        # sort the points based on their x-coordinates
        xSorted = pts[np.argsort(pts[:, 0]), :]
    
        # grab the left-most and right-most points from the sorted
        # x-roodinate points
        leftMost = xSorted[:2, :]
        rightMost = xSorted[2:, :]
    
        # now, sort the left-most coordinates according to their
        # y-coordinates so we can grab the top-left and bottom-left
        # points, respectively
        leftMost = leftMost[np.argsort(leftMost[:, 1]), :]
        (tl, bl) = leftMost
    
        # now, sort the right-most coordinates according to their
        # y-coordinates so we can grab the top-right and bottom-right
        # points, respectively
        rightMost = rightMost[np.argsort(rightMost[:, 1]), :]
        (tr, br) = rightMost
    
        # return the coordinates in top-left, top-right,
        # bottom-right, and bottom-left order
        return np.array([tl, tr, br, bl], dtype="int32")
    
    def perspective_transform(image, corners):
        def order_corner_points(corners):
            # Separate corners into individual points
            # Index 0 - top-right
            #       1 - top-left
            #       2 - bottom-left
            #       3 - bottom-right
            corners = [(corner[0][0], corner[0][1]) for corner in corners]
            top_r, top_l, bottom_l, bottom_r = corners[0], corners[1], corners[2], corners[3]
            return (top_l, top_r, bottom_r, bottom_l)
    
        # Order points in clockwise order
        ordered_corners = order_corner_points(corners)
        top_l, top_r, bottom_r, bottom_l = ordered_corners
    
        # Determine width of new image which is the max distance between 
        # (bottom right and bottom left) or (top right and top left) x-coordinates
        width_A = np.sqrt(((bottom_r[0] - bottom_l[0]) ** 2) + ((bottom_r[1] - bottom_l[1]) ** 2))
        width_B = np.sqrt(((top_r[0] - top_l[0]) ** 2) + ((top_r[1] - top_l[1]) ** 2))
        width = max(int(width_A), int(width_B))
    
        # Determine height of new image which is the max distance between 
        # (top right and bottom right) or (top left and bottom left) y-coordinates
        height_A = np.sqrt(((top_r[0] - bottom_r[0]) ** 2) + ((top_r[1] - bottom_r[1]) ** 2))
        height_B = np.sqrt(((top_l[0] - bottom_l[0]) ** 2) + ((top_l[1] - bottom_l[1]) ** 2))
        height = max(int(height_A), int(height_B))
    
        # Construct new points to obtain top-down view of image in 
        # top_r, top_l, bottom_l, bottom_r order
        dimensions = np.array([[0, 0], [width - 1, 0], [width - 1, height - 1], 
                        [0, height - 1]], dtype = "float32")
    
        # Convert to Numpy format
        ordered_corners = np.array(ordered_corners, dtype="float32")
    
        # Find perspective transform matrix
        matrix = cv2.getPerspectiveTransform(ordered_corners, dimensions)
    
        # Return the transformed image
        return cv2.warpPerspective(image, matrix, (width, height))
    
    image = cv2.imread('1.png')
    original = image.copy()
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    canny = cv2.Canny(gray, 120, 255, 1)
    
    corners = cv2.goodFeaturesToTrack(canny,4,0.5,50)
    
    c_list = []
    for corner in corners:
        x,y = corner.ravel()
        c_list.append([int(x), int(y)])
        cv2.circle(image,(x,y),5,(36,255,12),-1)
    
    corner_points = np.array([c_list[0], c_list[1], c_list[2], c_list[3]])
    ordered_corner_points = order_points_clockwise(corner_points)
    mask = np.zeros(image.shape, dtype=np.uint8)
    cv2.fillPoly(mask, [ordered_corner_points], (255,255,255))
    
    mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
    cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    
    for c in cnts:
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.015 * peri, True)
        if len(approx) == 4:
            transformed = perspective_transform(original, approx)
    
    result = rotate_image(transformed, -90)
    
    cv2.imshow('canny', canny)
    cv2.imshow('image', image)
    cv2.imshow('mask', mask)
    cv2.imshow('transformed', transformed)
    cv2.imshow('result', result)
    cv2.waitKey()
    
  4. 0
    1. encontrar contornos con RETR_EXTERNAL opción.(gris -> gaussiano-filtro> astuto borde -> encontrar el contorno)
    2. encontrar el mayor tamaño de contorno -> este será el borde del rectángulo
    3. encontrar rincones con poca cálculo

      Mat m;//image file
      findContours(m, contours_, hierachy_, RETR_EXTERNAL);
      auto it = max_element(contours_.begin(), contours_.end(),
          [](const vector<Point> &a, const vector<Point> &b) {
              return a.size() < b.size(); });
      Point2f xy[4] = {{9000,9000}, {0, 1000}, {1000, 0}, {0,0}};
      for(auto &[x, y] : *it) {
          if(x + y < xy[0].x + xy[0].y) xy[0] = {x, y};
          if(x - y > xy[1].x - xy[1].y) xy[1] = {x, y};
          if(y - x > xy[2].y - xy[2].x) xy[2] = {x, y};
          if(x + y > xy[3].x + xy[3].y) xy[3] = {x, y};
       }
      

    xy[4] será una de las cuatro esquinas.
    Yo era capaz de extraer las cuatro esquinas de esta manera.

Dejar respuesta

Please enter your comment!
Please enter your name here