【问题标题】:Opencv: find box within a boxOpencv:在一个盒子里找到盒子
【发布时间】:2014-12-22 21:34:52
【问题描述】:

物流

opencv 2.4 和 Python 2.7

我正在使用的图像:

问题

我感兴趣的是隔离形成围绕 9 条垂直和水平线的框的轮廓。我只是不确定该怎么做。我看过各种教程,例如关于数独谜题的教程,那些只是假设最大的盒子就是你要找的那个(因为数独谜题没有盒子里的盒子,减去实际的网格) .我尝试使用 findContour 函数并按大小过滤轮廓,但没有成功。我最终得到不一致的结果,有时会找到正确的轮廓,但有时会找到完全错误的轮廓。谁能指出我正确的方向?谢谢。

原图:

【问题讨论】:

  • 你还能上传原图吗?仅通过边缘图像可能很难得到盒子。
  • 是的。没问题!谢谢!

标签: python opencv


【解决方案1】:

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

  1. 使用 cv::HoughLines() 获取轴方向。
  2. 估计透视变换矩阵 (M) 以对齐图像 w.r.t.轴方向。
  3. 使用 cv::warpPerspective() 扭曲图像。
  4. 使用@dervish 的答案获取网格线候选。
  5. 按颜色信息(蓝白棋盘)和行距过滤行候选。
  6. 使用M 对最终网格进行反向变换,以获得原始图像空间中的网格。

或者直接在第2步找到最终的网格位置,得到第N长的线。并按步骤 4 过滤结果。

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()

【讨论】:

  • 是的。我已经实现了霍夫线算法。不过,我会调查一下,看看是否可行。谢谢。顺便问一下,你用什么版本的 opencv 做霍夫线?
  • 霍夫线是正确的方向。我使用 Arch Linux 官方存储库中的 OpenCV 2.4。
【解决方案2】:

最好放原图,但我试着从你的轮廓图像中解读

我做了以下步骤

  1. 您可能需要去除一些噪音(侵蚀)
  2. 根据这些轮廓计算水平和垂直投影
  3. 在图像上绘制投影,以便能够分析与检查表相关的投影边界。
  4. 请注意,垂直投影(绿色)如何为您提供左右边界的指示,水平投影(蓝色)也用于指示工作表的底部和顶部。

您只需要平滑投影并优化您对精确轮廓的搜索。

如果你觉得有用我可以分享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;

 }

【讨论】:

  • 是的。如果你不介意分享那就太好了。另外,您是否有一个我可以阅读的链接,或者您介意进一步解释这些预测?单线代表边界吗?
  • 还是我感兴趣的点的相对极值?我也发布了原始图像。
  • 是的,我会尽快分享
  • 顺便说一句,你的投影可能是一个简单的reduce
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 2017-02-04
  • 1970-01-01
  • 2021-12-09
  • 2014-02-02
  • 2020-10-19
  • 2018-04-20
相关资源
最近更新 更多