opencv 和 python - 激光曲线检测

Posted

技术标签:

【中文标题】opencv 和 python - 激光曲线检测【英文标题】:opencv and python - Laser curved line detection 【发布时间】:2015-05-27 09:14:06 【问题描述】:

我正在尝试获取位于该曲线中间的一组点。 我找到了这个脚本,但我的激光图像不起作用......

im_gray = cv2.imread(img, cv2.CV_LOAD_IMAGE_GRAYSCALE)

        im_gray = cv2.Canny(im_gray,50,150,apertureSize = 3)

        ret, im_bw = cv2.threshold(im_gray, 0, 255, cv2.THRESH_BINARY)

        #(thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

        #thresh = 127
        #im_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1]

        #ret, bw = cv2.threshold(im_bw, 0, 255, cv2.THRESH_BINARY)

        cv2.imwrite('resultpoint_bw.png',im_bw)

        # find contours of the binarized image
        contours, heirarchy = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        # curves
        curves = np.zeros((im_bw.shape[0], im_bw.shape[1], 3), np.uint8)

        cv2.imwrite('resultpoint_bw_2.png',im_bw)


        for i in range(len(contours)):

            # for each contour, draw the filled contour
            draw = np.zeros((im_bw.shape[0], im_bw.shape[1]), np.uint8)
            cv2.drawContours(draw, contours, i, (255,255,255), -1)
            # for each column, calculate the centroid
            for col in range(draw.shape[0]):
                M = cv2.moments(draw[:, col])
                if M['m00'] != 0:
                    x = col
                    y = int(M['m01']/M['m00'])
                    curves[y, x, :] = (0, 0, 255)


        cv2.imwrite('resultpoint_0.png',curves)

在结果图像中,点是错误的,因为是轮廓,不需要轮廓,而是中间的单点...

有没有可能做这个?

【问题讨论】:

为什么这个标签是javac++ 因为我错了 :) 我只需要 pyton、c++ 和 opencv 标签 你能添加你的图片样本吗? 在这里你可以找到img s2.postimg.org/z3dg3qz95/test.jpg 您的问题解决了吗?如果对您有帮助,请标记为答案! 【参考方案1】:

您可以应用这些简单的步骤来获得这条中心线。

    阈值二进制反转 应用Thinning algorithm 减少厚度。 在二值图像中查找非零像素。

   void thinningIteration(Mat& im, int iter)
    
        Mat marker = Mat::zeros(im.size(), CV_8UC1);
        for (int i = 1; i < im.rows-1; i++)
        
            for (int j = 1; j < im.cols-1; j++)
            
                uchar p2 = im.at<uchar>(i-1, j);
                uchar p3 = im.at<uchar>(i-1, j+1);
                uchar p4 = im.at<uchar>(i, j+1);
                uchar p5 = im.at<uchar>(i+1, j+1);
                uchar p6 = im.at<uchar>(i+1, j);
                uchar p7 = im.at<uchar>(i+1, j-1);
                uchar p8 = im.at<uchar>(i, j-1);
                uchar p9 = im.at<uchar>(i-1, j-1);

                int A  = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) + 
                         (p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) + 
                         (p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
                         (p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);
                int B  = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
                int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
                int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);

                if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
                    marker.at<uchar>(i,j) = 1;
            
        
        im &= ~marker;
    

    void thinning(Mat& im)
    
        im /= 255;
        Mat prev = Mat::zeros(im.size(), CV_8UC1);
        Mat diff;
        do 
        
            thinningIteration(im, 0);
            thinningIteration(im, 1);
            absdiff(im, prev, diff);
            im.copyTo(prev);
         
        while (countNonZero(diff) > 0);

        im *= 255;
    

    void main()
    
        Mat mSource_Bgr,mSource_Gray,mThreshold,mThinning;
        mSource_Bgr= imread(FileName_S.c_str(),IMREAD_COLOR);
        mSource_Gray= imread(FileName_S.c_str(),0);

        threshold(mSource_Gray,mThreshold,50,255,THRESH_BINARY);

        mThinning= mThreshold.clone();

        thinning(mThinning);

        imshow("mThinning",mThinning);

        vector<Point2i> locations;   // output, locations of non-zero pixels 
        findNonZero(mThinning, locations);

        for (int i = 0; i < locations.size(); i++)
        
            circle(mSource_Bgr,locations[i],2,Scalar(0,255,0),1);
        

        imshow("mResult",mSource_Bgr);

    

【讨论】:

非常感谢!现在我需要在 python 中转换你的脚本。可以提取坐标吗? 我投了赞成票,但请注意,激光散斑通常意味着最亮的像素不会位于中心。您需要先进行大量模糊/平滑处理,或者使用加权平均值来获得准确的激光线中心。【参考方案2】:

我在 python 中找到了解决方案:

    import cv2
    import numpy as np
    import glob
    import json, io
    from matplotlib import pyplot as plt
    from PIL import Image

    img = cv2.imread(fname, 0);

    i = Image.fromarray(self.__imgremapped_bw)

    pixels = i.load() # this is not a list

    self.__pointsData = [];

    find = 0

    for y in range(self.__top,self.__bottom):
        row_averages = []
        for x in range(self.__top,self.__bottom):
            cur_pixel = pixels[x, y]
            if cur_pixel >= self.__thresholdColor:
                row_averages.append(x)
                find = 1
            elif find == 1:
                pointSum = 0
                for idx, val in enumerate(row_averages):
                    pointSum += row_averages[idx];

                xf = pointSum/len(row_averages)
                # 0.5 correzione pixel al centro
                self.__pointsData.append([[y+0.5,xf+0.5]])
                row_averages = []
                find = 0

    #self.__drawPoint(self.__imgremapped_bw)

    return self.__pointsData

self.__top,self.__bottom 和 self.__top,self.__bottom 是一个裁剪区域,用于优化提取点。

self.__pointsData.append([[y+0.5,xf+0.5]])

+0.5 是为了获得中心像素。

在这种情况下,可能会有更多的行,因为这些行:

            if cur_pixel >= self.__thresholdColor:
                row_averages.append(x)
                find = 1
            elif find == 1:
                pointSum = 0
                for idx, val in enumerate(row_averages):
                    pointSum += row_averages[idx];

                xf = pointSum/len(row_averages)
                # 0.5 correzione pixel al centro
                self.__pointsData.append([[y+0.5,xf+0.5]])
                row_averages = []
                find = 0

有一个带有颜色范围的媒体点计算。

希望对你有帮助。

谢谢

【讨论】:

以上是关于opencv 和 python - 激光曲线检测的主要内容,如果未能解决你的问题,请参考以下文章

opencv---曲线断点检测(八邻域断点检测)

opencv---曲线断点检测(八邻域断点检测)

使用 OpenCV 进行垂直曲线检测

OpenCV+python轮廓

python opencv3 检测人

运动对象检测和描述