Как обнаружить угловые «стыки», которые соединяют элементы на изображениях? - PullRequest
3 голосов
/ 11 марта 2020

Я использую OpenCV через Python 3.7. У меня есть набор моно chrome изображений, которые выглядят так:

enter image description here

Я хотел бы найти все "точки соединения" на этих изображениях где «точка соединения» - это центр (1 пиксель) каждого пересечения двух планок. Эти "суставы" примерно представлены красными цифрами на изображении ниже:

enter image description here

Первая идея состояла в том, чтобы скелетизировать изображение и затем найти все соединенные края Алгоритмически, но все методы скелетонизации дали мне волнистые или круглые углы и дополнительные «ростки».

import cv2
import numpy as np
from skimage.morphology import skeletonize

image = cv2.imread("SOURCE_IMAGE.jpg", cv2.IMREAD_GRAYSCALE)
binary_image = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 91, 12)
skeleton = (skeletonize(binary_image//255) * 255).astype(np.uint8)

Результат:

enter image description here

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

import cv2

image = cv2.imread("SOURCE_IMAGE.jpg", cv2.IMREAD_GRAYSCALE)
edged = cv2.Canny(image, 100, 200)

Результат:

enter image description here

Есть ли надежные подходы к этой проблеме?

Ответы [ 2 ]

3 голосов
/ 12 марта 2020

Вот слегка измененная версия @ подхода Юнуса Темурленка с использованием Python вместо C ++. Идея такова:

  1. Получить двоичное изображение. Загрузить изображение, преобразовать в оттенки серого, Размытие по Гауссу , затем Порог Оцу .

  2. Получение горизонтальных и вертикальных линейных масок. Создание горизонтальных и вертикальных структурирующих элементов с помощью cv2.getStructuringElement, затем выполнение cv2.morphologyEx, чтобы изолировать линии.

  3. Найти соединения. Мы cv2.bitwise_and две маски вместе, чтобы получить соединения.

  4. Находим центроид на маске сустава. Мы находим контуры , затем вычисляем центроид .


Маски горизонтальной / вертикальной линии

image image

Обнаружены стыки зеленого цвета

enter image description here

Результаты

enter image description here

import cv2
import numpy as np

# Load image, grayscale, Gaussian blur, Otsus threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3,3), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Find horizonal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10,1))
horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)

# Find vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,10))
vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)

# Find joints
joints = cv2.bitwise_and(horizontal, vertical)

# Find centroid of the joints
cnts = cv2.findContours(joints, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    # Find centroid and draw center point
    M = cv2.moments(c)
    cx = int(M['m10']/M['m00'])
    cy = int(M['m01']/M['m00'])
    cv2.circle(image, (cx, cy), 3, (36,255,12), -1)

cv2.imshow('thresh', thresh)
cv2.imshow('horizontal', horizontal)
cv2.imshow('vertical', vertical)
cv2.imshow('joints', joints)
cv2.imshow('image', image)
cv2.waitKey()     
3 голосов
/ 11 марта 2020

Это мой подход к решению этой проблемы:

  1. Определить вертикальные линии
  2. Определить горизонтальные линии
  3. Найти их пересечения, являющиеся соединениями

Для первого шага проверьте каждый столбец, определите тонкие линии и сделайте их черными (0). Результатом будут только вертикальные линии. Для второго шага сделайте обратное. В конце сравните изображение вертикальной линии с изображением горизонтальной линии . Пиксели белого цвета (255) в обеих точках пересечения.

Примечание: Пожалуйста, не вините меня из-за кодирования в C ++. Я не знаком с python Я просто хотел показать свой подход и результаты.

Вот код и результаты:

Источник:

enter image description here

Вертикальные линии:

enter image description here

Горизонтальные линии:

enter image description here

Результат:

enter image description here

Код:

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("/ur/image/directory/joints.jpg",1);

    imshow("Source",img);

    int checker = 1,checker2 = 1;
    int begin_y,finish_y2,finish_y,begin_y2;
    Mat vertical_img = img.clone();
    Mat horizontal_img = img.clone();

    cvtColor(vertical_img,vertical_img,CV_BGR2GRAY);
    cvtColor(horizontal_img,horizontal_img,CV_BGR2GRAY);

    int finish_checker = 0,finish_checker2=0;
    for(int i=0;i<horizontal_img.rows;i++)
    {
        for(int j=0;j<horizontal_img.cols;j++)
        {
            if(horizontal_img.at<uchar>(Point(j,i))>100 && checker)
            {
                begin_y = j;
                checker = 0;
            }

            if(horizontal_img.at<uchar>(Point(j,i))<20 && checker==0)
            {
                finish_y = j;
                checker = 1;
                finish_checker = 1;

            }

            if(finish_checker)
            {
                if((finish_y-begin_y)<30)
                {
                    for(int h=begin_y-2;h<=finish_y;h++)
                    {
                        horizontal_img.at<uchar>(Point(h,i)) = 0;
                    }
                }

                finish_checker = 0;
            }
        }
    }

    imshow("Horizontal",horizontal_img);

    for(int i=0;i<vertical_img.cols;i++)
    {
        for(int j=0;j<vertical_img.rows;j++)
        {
            if(vertical_img.at<uchar>(Point(i,j))>100 && checker2)
            {
                begin_y2 = j;
                checker2 = 0;
            }
            if(vertical_img.at<uchar>(Point(i,j))<50 && checker2==0)
            {
                finish_y2 = j;
                checker2 = 1;
                finish_checker2 = 1;
            }
            if(finish_checker2)
            {
                if((finish_y2-begin_y2)<30)
                {
                    for(int h=begin_y2-2;h<=finish_y2;h++)
                    {
                        vertical_img.at<uchar>(Point(i,h)) = 0;
                    }
                }
                finish_checker2 = 0;
            }
        }
    }
    imshow("Vertical",vertical_img);

    for(int y=0;y<img.cols;y++)
    {
        for(int z=0;z<img.rows;z++)
        {
            if(vertical_img.at<uchar>(Point(y,z))>200 && horizontal_img.at<uchar>(Point(y,z))>200)
            {
                img.at<cv::Vec3b>(z,y)[0]=0;
                img.at<cv::Vec3b>(z,y)[1]=0;
                img.at<cv::Vec3b>(z,y)[2]=255;
            }
        }
    }

    imshow("Result",img);
    waitKey(0);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...