it-swarm.com.ru

Обнаружение линии OpenCV для линий 45 градусов

У меня есть изображение:

original image where opencv houghP transform can't find the -45 degree line

На этом изображении преобразование OpenCV Hough не может обнаружить большую линию -45 градусов, используя

minLineLength = 150 
maxLineGap = 5 
line_thr = 150 
linesP = cv.HoughLinesP(dst, 1, np.pi / 180, line_thr, None, minLineLength, maxLineGap) 

Единственные найденные строки:

lines found

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

Если я вручную обрежу изображение следующим образом:

cropped version where line is found

тогда я ясно вижу преобразование Хафа OpenCV, находящее правильную линию:

line found

Я хочу найти эту же строку в не обрезанной версии. Любые предложения по не обрезанной версии, чтобы найти его?

Также могут быть случаи, когда линии вообще нет или линия не проходит весь путь по длине оси X. Примеры

enter image description here enter image description here

4
pilogo

Я сделал это в командной строке в терминале с помощью ImageMagick, но вы можете применить точно такой же метод с OpenCV.

Шаг 1

Возьмите изображение и поверните его на 45 градусов, добавив черные пиксели в качестве фона, где это необходимо:

convert 45.jpg -background black -rotate 45 result.png

 enter image description here

Шаг 2

Теперь, опираясь на предыдущую команду, установите для каждого пикселя медиану поля шириной 1 пиксель и высотой 250 пикселей по центру:

convert 45.jpg -background black -rotate 45 -statistic median 1x250 result.png

 enter image description here

Шаг 3

Теперь, снова опираясь на предыдущую команду, поверните ее на 45 градусов назад:

convert 45.jpg -background black -rotate 45 -statistic median 1x250 -rotate -45 result.png

 enter image description here


Итак, в итоге, вся обработка:

convert input.jpg -background black -rotate 45 -statistic median 1x250 -rotate -45 result.png

Очевидно, затем обрежьте его обратно до исходного размера и добавьте бок о бок с оригиналом для проверки:

convert 45.jpg -background black -rotate 45 -statistic median 5x250 -rotate -45 +repage -gravity center -crop 184x866+0+0 result.png
convert 45.jpg result.png +append result.png 

 enter image description here


Вы также можете использовать статистику mean плюс пороговое значение вместо median, так как это быстрее, чем сортировка, чтобы найти медиану, однако это приводит к размытию:

convert 45.jpg -background black -rotate 45 -statistic mean 1x250 result.png

 enter image description here

Ваше вновь добавленное изображение обрабатывается с таким результатом:

 enter image description here

1
Mark Setchell

Проблема, очевидно, в том, что искомая строка не является строкой. На самом деле это похоже на поезд из связанных кругов и коробок. Поэтому я рекомендую вам сделать следующее:

Найти все контуры на изображении, используя поиск контуров

img = cv.imread('image.jpg')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(img_gray, 127, 255, 0)
img2, contours, hierarchy = cv.findContours(thresh, CHAIN_APPROX_SIMPLE ,cv.RETR_EXTERNAL)

Это вернет много контуров, поэтому используйте цикл, чтобы сохранить только достаточно длинные контуры. Поскольку размер изображения составляет 814x1041 пикселей, я предполагаю, что контур длинный, если он составляет не менее 10% ширины изображения, что составляет почти 100 (вы, очевидно, должны оптимизировать это значение)

long_contours = []
for contour in contours[i]:
    perimeter = cv2.arcLength(contour,True)
    if (perimeter > 0.1 * 1018)  # 10% of the image width
        long_contours.append(contour)

Теперь нарисуйте повернутый ограничивающий прямоугольник вокруг тех длинных контуров, которые также могут быть линиями. Длинный контур считается линией, если его ширина намного длиннее его высоты или большое соотношение сторон (например, 8, и вам также необходимо оптимизировать это значение)

for long_contour in long_contours:
    rect = cv2.minAreaRect(long_contour)
    aspec_ratio =  rect.width / rect.height

    if aspec_ratio > 8 : 
       box = cv2.boxPoints(rect)
       box = np.int0(box)
       cv2.drawContours(img,[box],0,(255,255,255),cv.FILLED)

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

 Rotated rectangle over a suspected line

1
Sameh Yassin

Я реализовал немного более простой алгоритм, чем мой другой ответ, но на этот раз в Python с OpenCV.

По сути, вместо того, чтобы брать среднее значение вертикальных столбцов пикселей, он суммирует пиксели в столбцах и выбирает наиболее яркий столбец. Если я покажу дополненное, повернутое изображение с другим изображением ниже, представляющим суммы столбцов, вы должны увидеть, как это работает:

 enter image description here

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image as greyscale
im = cv2.imread('45.jpg',cv2.IMREAD_GRAYSCALE)

# Pad with border so it isn't cropped when rotated
bw=300
bordered = cv2.copyMakeBorder(im, top=bw, bottom=bw, left=bw, right=bw, borderType= cv2.BORDER_CONSTANT)

# Rotate -45 degrees
w, h = bordered.shape
M = cv2.getRotationMatrix2D((h/2,w/2),-45,1)
paddedrotated = cv2.warpAffine(bordered,M,(h,w))
# DEBUG cv2.imwrite('1.tif',paddedrotated)

# Sum the elements of each column and find column with most white pixels
colsum = np.sum(paddedrotated,axis=0,dtype=np.float)
col = np.argmax(colsum)
# DEBUG cv2.imwrite('2.tif',colsum)

# Fill with black except for the line we have located which we make white
paddedrotated[:,:] = 0
paddedrotated[:,col] = 255

# Rotate back to straight
w, h = paddedrotated.shape
M = cv2.getRotationMatrix2D((h/2,w/2),45,1)
straight = cv2.warpAffine(paddedrotated,M,(h,w))

# Remove padding and save to disk
straight = straight[bw:-bw,bw:-bw]
cv2.imwrite('result.png',straight)

Обратите внимание, что вам на самом деле не нужно поворачивать изображение обратно к прямой и обрезать его до исходного размера. Вы могли бы на самом деле остановиться после первой строки, которая говорит:

col = np.argmax(colsum)

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

Вот вывод:

 enter image description here


Keywords: обнаружение линии, обнаружение линии, поворот, подушка, граница, проекция, проект, изображение, обработка изображения, Python, OpenCV, аффинный, Hough

1
Mark Setchell

Ваш оригинальный код хорош как свисток. Единственная проблема состоит в том, что ваше изображение содержит слишком много информации, которая портит оценки аккумулятора. Все получится, если вы увеличите порог линии до 255.

minLineLength = 150 
maxLineGap = 5
line_thr = 255
linesP = cv2.HoughLinesP(dst, 1, np.pi / 180.0, line_thr, None, minLineLength, maxLineGap) 

Вот результаты, использующие это значение . Здесь обнаружены 3 строки из-за большого размера белого пикселя.

[  1  41 286 326]
[  0  42 208 250]
[  1  42 286 327]

 enter image description here

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

[110 392 121 598]
[112 393 119 544]
[141 567 147 416]
[ 29 263  29 112]
[  0  93 179 272]

 enter image description here

Здесь не найдено ни одной строки .  enter image description here

1
yapws87