Как найти углы на изображении с помощью OpenCv
Я пытаюсь найти углы на изображении, мне не нужны контуры, только 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]()
Итак, я хочу найти cornes, но я не знаю, как использовать функции углов, такие как cvCornerHarris и другие.
Ответы
Ответ 1
Сначала проверьте /samples/c/squares.c в своем дистрибутиве OpenCV. В этом примере представлен квадратный детектор, и это должно быть довольно неплохим началом для определения угловых функций. Затем взгляните на функциональные функции OpenCV, такие как cvCornerHarris() и cvGoodFeaturesToTrack().
Вышеупомянутые методы могут возвращать многие угловые функции - большинство из них не будут "истинными углами", которые вы ищете. В моем приложении мне приходилось обнаруживать квадраты, которые были повернуты или перекошены (из-за перспективы). Мой конвейер обнаружения состоял из:
- Конвертировать из RGB в оттенки серого (cvCvtColor)
- Гладкий (cvSmooth)
- Порог (cvThreshold)
- Обнаружение ребер (cvCanny)
- Найти контуры (cvFindContours)
- Приблизительные контуры с линейными функциями (cvApproxPoly)
- Найдите "прямоугольники", которые были структурами, которые имели полигонализированные контуры, имеющие 4 точки, имели достаточную площадь, причем смежные края составляли ~ 90 градусов, расстояние между "противоположными" вершинами имело достаточный размер и т.д.
Шаг 7 был необходим, потому что слегка шумное изображение может дать много структур, которые кажутся прямоугольными после полигонализации. В моем приложении мне также приходилось иметь дело с квадратными структурами, которые появились внутри, или перекрывали желаемый квадрат. Я нашел свойство области контура и центр тяжести полезным для распознавания правильного прямоугольника.
Ответ 2
На первый взгляд, для человеческого глаза есть 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)
ОБНОВИТЬ
Переменная 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]()
Ответ 3
Попробуйте прочитать это: http://sudokugrab.blogspot.com/2009/07/how-does-it-all-work.html
Ответ 4
- найти контуры с помощью опции RETR_EXTERNAL (серый → фильтр Гаусса → крайний край → найти контур)
- найти контур наибольшего размера → это будет край прямоугольника
-
найти углы с небольшим расчетом
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] будет четырьмя углами. Я смог извлечь четыре угла таким образом.
Ответ 5
Применить houghlines к каноническому изображению - вы получите список очков
применим выпуклую оболочку к этому множеству точек