Opencv:在框中找到框

时间:2014-12-19 00:35:05

标签: python opencv

物流

opencv 2.4和Python 2.7

我正在使用的图片: enter image description here

问题

我感兴趣的是隔离形成围绕9条垂直和水平线的框的轮廓。我只是不确定如何解决这个问题。我看过各种教程,比如在Sudoku谜题上完成的那些教程,那些只是假设最大的盒子是你正在寻找的那个(因为数独谜题盒子里没有盒子,减去实际的网格) 。我已经尝试使用findContour函数并按大小过滤轮廓但没有运气。我最终会得到不一致的结果,有时会找到正确的轮廓,但有时会发现完全错误的轮廓。谁能指出我正确的方向?谢谢。

原始图片: enter image description here

2 个答案:

答案 0 :(得分:3)

受@ dervish的回答启发,我有一些想法。

  1. 使用cv :: HoughLines()获取轴方向。
  2. 估算透视变换矩阵(M)以对齐图像w.r.t.轴方向。
  3. 使用cv :: warpPerspective()来扭曲图像。
  4. 使用@ dervish的答案来获得网格线条。
  5. 根据颜色信息(蓝色和白色棋盘)和线距来过滤线条。
  6. 使用M对最终网格进行反向变换,以获取原始图像空间中的网格。
  7. 或直接在步骤2中找到最终网格位置以获得第N个最长行。并按步骤4过滤结果。

    HoughLine results

    python代码:

    import cv2
    import numpy as np
    
    
    def main():
        im = cv2.imread('image.png')
        #edge = cv2.imread('edge.png', 0)
        edge = cv2.Canny(im, 100, 200, apertureSize=3)
        lines = cv2.HoughLines(edge, 1, np.pi/180, 140)
        for rho, theta in lines[0]:
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a*rho
            y0 = b*rho
            x1 = int(x0 + 1000*(-b))
            y1 = int(y0 + 1000*(a))
            x2 = int(x0 - 1000*(-b))
            y2 = int(y0 - 1000*(a))
            cv2.line(im, (x1, y1), (x2, y2), (0, 0, 255), 2)
            # TODO: filter the lines by color and line distance
    
        cv2.imshow('image', im)
        cv2.imshow('edge', edge)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    
    if __name__ == '__main__':
        main()
    

答案 1 :(得分:2)

放置原始图像效果更好,但我试图从您的轮廓图像中进行解释

我做了以下步骤

  1. 你可能需要一些去除噪音(侵蚀)
  2. 根据这些轮廓计算水平和垂直投影
  3. 绘制图像上的投影,以便能够分析关于检查表的投影边界。
  4. 请注意垂直投影(绿色)如何显示左右边界,水平底部和顶部的水平(蓝色)也是如此。
  5. 您只需要平滑投影并优化搜索的确切轮廓。 enter image description here

    enter image description here

    如果您认为它有用,我可以共享opencv c ++(而不是python)实现的代码

    修改

    这是我用于制作水平和垂直投影的代码,您可能需要优化它。

     void HVprojection(Mat image)
    {
        // find the vertical projection
        Mat smothedRes = image.clone();
        vector<double> v_vl_proj; // holds the column sum values
        double max_vl_proj_h = 0,max_vl_proj_v=0; // holds the maximum value
        double average_v=0;
        for( int i=0;i<image.cols;++i )
        {
            Mat col;
            Scalar col_sum;
            // get individual columns
            col= image.col(i);
            col_sum = sum( col ); // find the sum of ith column
            v_vl_proj.push_back( col_sum.val[0] ); // push back to vector
            if( col_sum.val[0]>max_vl_proj_v )    max_vl_proj_v = col_sum.val[0];
            average_v+= col_sum.val[0];
        }
        average_v = average_v/image.cols;
    
        // find the horizontal projection
        vector<double> h_vl_proj; // holds the row sum values
    
        double average_h=0;
        for( int i=0;i<image.rows;++i )
        {
            Mat row;
            Scalar row_sum;
            // get individual columns
            row= image.row(i);
            row_sum = sum(row); // find the sum of ith row
            h_vl_proj.push_back(row_sum.val[0]); // push back to vector
            if( row_sum.val[0]>max_vl_proj_h )    max_vl_proj_h = row_sum.val[0];
            average_h+= row_sum.val[0];
        }
        average_h = average_h/image.rows;
    
    
        //******************Plotting vertical projection*******************
        for(int j =1;j<image.cols;j++)
        {
            int y1 = int(image.rows*v_vl_proj[j-1]/max_vl_proj_v);
            int y2 = int(image.rows*v_vl_proj[j]/max_vl_proj_v);
              line(image,Point(j-1,y1),Point(j,y2),Scalar(255,255,255),1,8);
            }
        int average_y = int(image.rows*average_v/max_vl_proj_v);  // zero level
        line(image,Point(0,average_y),Point(image.cols,average_y),Scalar(255,255,255),1,8);
    
    
    
    
        //***************Plotting horizontal projection**************
        for(int j =1;j<image.rows;j++)
        {
            int x1 = int(0.25*image.cols*h_vl_proj[j-1]/max_vl_proj_h);
            int x2 = int(0.25*image.cols*h_vl_proj[j]/max_vl_proj_h);
              line(image,Point(x1,j-1),Point(x2,j),Scalar(255,0,0),1,8);
            }
        int average_x = int(0.25*image.cols*average_h/max_vl_proj_h);
        line(image,Point(average_x,0),Point(average_x,image.rows),Scalar(255,0,0),1,8);
    
        imshow("horizontal_projection",image);
        imwrite("h_p.jpg",image);
    
    
    
    // if you want to smooth the signal of projection in case of noisu signal
        v_vl_proj = smoothing(v_vl_proj);
    
        for(int j =1;j<image.cols;j++)
            {
                int y1 = int(image.rows*v_vl_proj[j-1]/max_vl_proj_v);
                int y2 = int(image.rows*v_vl_proj[j]/max_vl_proj_v);
                  line(smothedRes,Point(j-1,y1),Point(j,y2),Scalar(0,255,0),1,8);
                }
            int average_y1 = int(smothedRes.rows*average_v/max_vl_proj_v);  // zero level
            line(smothedRes,Point(0,average_y1),Point(smothedRes.cols,average_y1),Scalar(0,255,0),1,8);
    
            imshow("SMoothed",smothedRes);
            imwrite("Vertical_projection.jpg",smothedRes);
            waitKey(0);
    }
    

    平滑投影信号:

    vector<double> smoothing(vector<double> a)
     {
         //How many neighbors to smooth
         int NO_OF_NEIGHBOURS=5;
         vector<double> tmp=a;
         vector<double> res=a;
    
         for(int i=0;i<a.size();i++)
         {
    
             if(i+NO_OF_NEIGHBOURS+1<a.size())
             {
                 for(int j=1;j<NO_OF_NEIGHBOURS;j++)
                 {
                     res.at(i)+=res.at(i+j+1);
                 }
                 res.at(i)/=NO_OF_NEIGHBOURS;
             }
             else
             {
                 for(int j=1;j<NO_OF_NEIGHBOURS;j++)
                 {
                     res.at(i)+=tmp.at(i-j);
                 }
                 res.at(i)/=NO_OF_NEIGHBOURS;
    
             }
    
    
         }
         return res;
    
     }