Как найти углы на изображении с помощью OpenCv - PullRequest
39 голосов
/ 01 сентября 2011

Я пытаюсь найти углы на изображении, мне не нужны контуры, только 4 угла.Я буду менять перспективу, используя 4 угла.

Я использую Opencv, но мне нужно знать шаги, чтобы найти углы и какую функцию я буду использовать.

Мои изображения будут похожиэто: (без красных точек, я буду рисовать точки после) enter image description here

РЕДАКТИРОВАНИЕ:

После предложенных шагов я написал код: (Примечание: я не использую чистый OpenCvЯ использую javaCV, но логика та же).

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

enter image description here

    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);

enter image description here

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

enter image description here

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

enter image description here

    //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 );   

enter image description here

    //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();
          }

    } 

enter image description here

Итак, я хочунайти углы, но я не знаю, как использовать функцию углов, как cvCornerHarris и другие.

Ответы [ 4 ]

34 голосов
/ 01 сентября 2011

Во-первых, проверьте /samples/c/squares.c в вашем дистрибутиве OpenCV.В этом примере представлен квадратный детектор, и он должен стать хорошим началом для определения угловых объектов.Затем взгляните на функционально-ориентированные функции OpenCV, такие как cvCornerHarris () и cvGoodFeaturesToTrack ().

Вышеуказанные методы могут возвращать много угловых функций - большинство из них не будут "истинными углами", которые вы ищете.В моем приложении я должен был обнаружить квадраты, которые были повернуты или перекошены (из-за перспективы).Мой конвейер обнаружения состоял из:

  1. Преобразование из RGB в оттенки серого (cvCvtColor)
  2. Плавный (cvSmooth)
  3. Порог (cvThreshold)
  4. Обнаружениеребра (cvCanny)
  5. Поиск контуров (cvFindContours)
  6. Приближенные контуры с линейными элементами (cvApproxPoly)
  7. Поиск «прямоугольников», представляющих собой структуры, которые: имели полигональные контуры, имеющие 4 точки, имели достаточную площадь, имели смежные края ~ 90 градусов, имели расстояние между «противоположными» вершинами достаточного размера и т. д.

Шаг 7 был необходим, потому что слегка зашумленное изображение может дать много структуркоторые появляются прямоугольные после многоугольности.В моем приложении мне также приходилось иметь дело с квадратными структурами, которые появлялись внутри или перекрывали нужный квадрат.Я обнаружил, что свойство площади контура и центр тяжести помогают определить правильный прямоугольник.

12 голосов
/ 28 мая 2018

На первый взгляд, для человеческого глаза есть 4 угла. Но в компьютерном зрении угол считается точкой, в которой интенсивность градиента изменяется по всей его окрестности. Окрестность может быть 4-пиксельной или 8-пиксельной.

enter image description here

В уравнении, указанном для нахождения градиента интенсивности, он был рассмотрен для 4-пиксельной окрестности СМ. ДОКУМЕНТАЦИЯ .

Вот мой подход к рассматриваемому изображению. У меня также есть код на Python:

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 

Это хороший выбор, чтобы всегда размыть изображение, чтобы удалить менее возможные изменения градиента и сохранить более интенсивные. Я решил выбрать двусторонний фильтр , который в отличие от фильтра Гаусса не размывает все пиксели в окрестности. Это скорее размывает пиксели, которые имеют интенсивность пикселей, аналогичную интенсивности центрального пикселя. Короче говоря, он сохраняет края / углы с высоким изменением градиента, но размывает области с минимальными изменениями градиента.

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

enter image description here

Для человека это не такая большая разница по сравнению с исходным изображением. Но это имеет значение. Теперь находим возможные углы:

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

dst возвращает массив (той же 2D-формы изображения) с собственными значениями, полученными из упомянутого окончательного уравнения ЗДЕСЬ .

Теперь необходимо применить порог, чтобы выбрать те углы, которые выходят за пределы определенного значения. Я буду использовать один в документации:

#--- 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)

enter image description here

Белые пиксели - это области возможных углов. Вы можете найти много углов, соседствующих друг с другом.

Чтобы нарисовать выбранные углы на изображении:

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

enter image description here

(пиксели красного цвета - углы, не очень заметные)

Чтобы получить массив всех пикселей с углами:

coordinates = np.argwhere(mask)

UPDATE

Переменная coor - это массив массивов. Преобразование его в список списков

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

Преобразование вышеупомянутого в список кортежей

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

У меня есть простой и довольно наивный способ найти 4 угла. Я просто рассчитал расстояние каждого угла до каждого другого угла. Я сохранил те углы, расстояние которых превышало определенный порог.

Вот код:

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

До запуска фрагмента выше coor_tuples имел все угловые точки: [(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)]

После запуска фрагмента у меня осталось 4 угла:

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

ОБНОВЛЕНИЕ 2

Теперь все, что вам нужно сделать, это просто отметить эти 4 точки на копии исходного изображения.

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) 

enter image description here

0 голосов
/ 21 июня 2019
  1. поиск контуров с опцией RETR_EXTERNAL. (Серый -> фильтр Гаусса -> резкий край -> найти контур)
  2. поиск контура наибольшего размера -> это будет край прямоугольника
  3. найти углы с небольшим расчетом

    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] будет четырьмя углами.Я смог извлечь четыре угла таким образом.

0 голосов
/ 22 октября 2014

Примените жесткие линии к хитрому изображению - вы получите список точек, примените выпуклую оболочку к этому набору точек

...