Python “如何检测角点”;“关节”;连接图像上的元素?

Python “如何检测角点”;“关节”;连接图像上的元素?,python,python-3.x,image,opencv,image-processing,Python,Python 3.x,Image,Opencv,Image Processing,我通过Python 3.7使用OpenCV。我有一组单色图像,看起来像这样: 我想找到这些图像上的所有“关节点”,其中“关节点”是两块木板的每个交点的中心(1像素)。这些“关节”大致由下图中的红色圆环表示: 第一个想法是对图像进行骨架化,然后通过算法找到所有连接的边缘,但所有骨架化技术都给了我扭曲或圆角以及额外的“萌芽” 结果: 第二个想法是找到内部轮廓,将它们近似到边界点,找到最近的邻居,然后以某种方式计算中心,但是,同样,精明的边缘检测方法给了我扭曲的角落和额外的点 import cv

我通过Python 3.7使用OpenCV。我有一组单色图像,看起来像这样:

我想找到这些图像上的所有“关节点”,其中“关节点”是两块木板的每个交点的中心(1像素)。这些“关节”大致由下图中的红色圆环表示:

第一个想法是对图像进行骨架化,然后通过算法找到所有连接的边缘,但所有骨架化技术都给了我扭曲或圆角以及额外的“萌芽”

结果:

第二个想法是找到内部轮廓,将它们近似到边界点,找到最近的邻居,然后以某种方式计算中心,但是,同样,精明的边缘检测方法给了我扭曲的角落和额外的点

import cv2

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


这个问题有可靠的解决方法吗?

这是我解决这个问题的方法:

  • 确定垂直线
  • 确定水平线
  • 找出它们的交点,这些交点是关节
  • 第一步,检查每一列,确定细线并使其变为黑色(0)。结果只会是垂直线。对于第二步,请执行相反的操作。 最后,将垂直线图像水平线图像进行比较。两者中的白色(255)像素是交点

    <强>注:请不要因为C++中的编码而责备我。我不熟悉python,我只是想展示我的方法和结果

    以下是代码和结果:

    资料来源:

    垂直线:

    水平线:

    结果:

    守则:

    #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;
    }
    
    #包括
    #包括
    #包括
    使用名称空间std;
    使用名称空间cv;
    int main()
    {
    Mat img=imread(“/ur/image/directory/joints.jpg”,1);
    imshow(“来源”,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();
    CVT颜色(垂直、垂直、灰色);
    CVT颜色(水平、水平、灰色);
    int finish\u checker=0,finish\u checker=0;
    
    对于(int i=0;i)这里使用Python而不是C++的方法的一个稍微修改的版本。
  • 获取二值图像。加载图像,转换为灰度,然后

  • 获取水平和垂直线条遮罩。使用创建水平和垂直结构元素,然后执行以隔离线条

  • 找到关节。我们将两个面具放在一起以获得关节

  • 在关节遮罩上找到质心。然后我们计算


  • 水平/垂直线遮罩

    检测到绿色接头

    结果


    你看过卷积吗?你是说卷积网络吗?它们不太可能对我有帮助,因为类是高度不平衡的。我的意思是卷积是图像处理操作。调整内核可以突出显示你正在寻找的信息(关节):很好的方法,在获得红色方框后,您可以更进一步,找到质心以获得准确的点。是的,在红色方框后,也可以很容易地找到一步质心。我将尝试将其添加到后面。确实很好的方法!但是对角线呢?我假设不可能正确提取它们,因为角度可能不同呃。@SagRU垂直和水平都不包括的区域是对角线或其他。你可以从这一点继续使用对角线。@Nathance在这种情况下使用高斯模糊和大津阈值的原因是什么?没有噪声,图像总是黑白的,所以我假设基本阈值就足够了。高斯模糊是为了确保没有小颗粒的噪声,大津的阈值是为了确保它是一个二值图像(1通道0或255)。如果你只是灰度化,它不是一个二进制图像。基本阈值就足够了,但我想自动计算阈值,这样它就不会是硬编码的value@nathancy虽然我最终采用了一种不同的、更复杂的方法,但我同意您的解决方案是所有答案中最好的(衷心感谢Yunus Temulenk的贡献)。
    #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;
    }
    
    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()