Обнаружение вертикальных прямоугольников почти постоянного цвета на шумном изображении - PullRequest
1 голос
/ 06 января 2020

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

Исходное изображение:

Original Image

Изображение с ожидаемыми прямоугольниками / квадратами (могут быть тонкие вертикальные линии, независимо от того, обнаружены они как прямоугольники или нет):

Image with expected rectangles

Исходя из того, что я понял, это довольно ручная работа, требующая

  1. преобразования изображения в оттенки серого 8 бит (мое изображение уже в серой шкале)
  2. добавить гауссовский шум для сглаживания изображения
  3. преобразовать результат в черно-белый, например, с помощью adaptiveThreshold
  4. расширить результат, чтобы попытаться объединить детали, которые больше не соприкасаются
  5. стирают результат для удаления небольшого нежелательного шума
  6. запускают некоторый алгоритм для обнаружения форм

Я сейчас вычисляю следующее изображение:

Black and white threshold image

Примечания к sult:

  • шума нет (хотя на некоторых других изображениях я все еще получаю небольшие пятна шума здесь и там)
  • прямоугольники не все закрыты
  • один маленький прямоугольник / квадрат слева теперь может быть трудно определить рядом с вертикальной линией

Мои вопросы

  • Есть ли лучший способ сделать это?
  • Как мне go при обнаружении прямоугольников, которые в настоящее время не все закрыты? Знание того, что они всегда горизонтальные или вертикальные и имеют почти постоянный цвет, должно помочь.

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

Я использую OpenCV 4.1.2 с Python 3.7.2. Вот мой текущий код:

import cv2
import numpy
import platform
import sys

print("Python version: {}\nOpenCV version: {}".format(platform.python_version(), cv2.__version__))

# Used variables:
# For gaussian blur
gaussianBlur = 11
# For threshold
meanType = cv2.ADAPTIVE_THRESH_MEAN_C
meanTypeName = "Mean"
blockSize = 17
c = 3
# For close/open
growSize = 6
shrinkSize = 3

# Import image.
imageName = sys.argv[1]
image = cv2.imread(imageName)

# Convert to gray scale 8 bit, blur then take threshold.
grayscaled = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(grayscaled, (gaussianBlur, gaussianBlur), 0)
thresholded = cv2.adaptiveThreshold(blurred, 255, meanType, cv2.THRESH_BINARY_INV, blockSize, c)

# Close then Open to try to "close" the rectangles and remove noise.
rectClose = cv2.getStructuringElement(cv2.MORPH_RECT, (growSize,growSize))
rectOpen = cv2.getStructuringElement(cv2.MORPH_RECT, (shrinkSize,shrinkSize))
mask = cv2.morphologyEx(thresholded, cv2.MORPH_CLOSE, rectClose)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, rectOpen)

result = mask

# Compute contours and display them on the gray scale image
contours, hierarchy = cv2.findContours(result, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
resultWithContours = grayscaled
cv2.drawContours(resultWithContours, contours, -1, (0,0,255), cv2.FILLED)

# Display threshold image and original with detected contours.
both = numpy.concatenate([result, resultWithContours], axis=0)
cv2.imshow("{} Block Size={} C={}".format(meanTypeName, blockSize, c), both)

# Save both threshold and original with detected contours.
cv2.imwrite("{}_result_{}_blockSize{}_c{}.jpg".format(imageName, meanTypeName, blockSize, c), result)
cv2.imwrite("{}_contours_{}_blockSize{}_c{}.jpg".format(imageName, meanTypeName, blockSize, c), resultWithContours)

cv2.waitKey(0)
cv2.destroyAllWindows()

Ответы [ 2 ]

1 голос
/ 06 января 2020

Я сделал это:

1 - отфильтрованное изображение с двусторонним фильтром

2 - примененный порог Оцу (и перевернул двоичное изображение)

3 - открыл изображение ( морфологический)

4- Маскированное отфильтрованное изображение с раскрытым изображением

5- Примененный детектор острых краев

enter image description here

enter image description here

enter image description here

Теперь с findContour и drawContour вы можете делать все что угодно с прямоугольниками. Вот мой код (C ++):

Mat img__1, img__2,img__ = imread("E:/s.jpg", 0);
Mat filtered;

bilateralFilter(img__, filtered, 9, 5, 5);

imshow("filtered", filtered);

threshold(filtered, img__1, 0, 255, THRESH_OTSU);
img__1 = 255 - img__1;

imshow("Binarized by Otsu", img__1);

int k = 3;
erode(img__1, img__1, Mat::ones(k, k, CV_8U), Point(-1, -1), 1);
dilate(img__1, img__1, Mat::ones(k, k, CV_8U), Point(-1, -1), 1);

imshow("Dots removed", img__1);

img__1.convertTo(img__1, CV_32F);
filtered.convertTo(filtered, CV_32F);
img__1 = img__1 / 255.0;
multiply(filtered, img__1, img__1,1, CV_32F);
img__1.convertTo(img__1, CV_8U);

imshow("masked denoised image", img__1);

Mat canny_1;
Canny(img__1, canny_1, 30, 100);

imshow("final image", canny_1);
waitKey(0);
1 голос
/ 06 января 2020

Если цвет / интенсивность постоянны, вы можете использовать метод цветовой сегментации (более точный, чем адаптивный порог). Я обычно использую адаптивный порог в тех случаях, когда есть пара объектов с резкими контрастами / цветовыми различиями, как правило, со случайной цветовой палитрой.

Но в вашем случае, поскольку цвет соответствует, мы можем жестко кодировать цветовую гамму. Используйте любой инструмент выбора цвета, чтобы выбрать цвет прямоугольников, которые вы хотите определить, скажем, цвет 155 (значение серой шкалы). Тогда мы можем использовать cv2.inRange() с нижним порогом, скажем 150 и верхним порогом 160. Вы получите двоичное изображение из метода cv2.inRange(), который можно использовать для определения контуров.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...