如何确定线条的宽度?

aze*_*r89 6 opencv image-processing computer-vision

我需要检测这些线的宽度:

在此输入图像描述

这些线是平行的并且有一些噪音.

目前,我所做的是:

1.使用减薄找到中心(张颂)

ZhanSuenThinning(binImage, thin);
Run Code Online (Sandbox Code Playgroud)

2.计算距离变换

cv::distanceTransform(binImage, distImg, CV_DIST_L2, CV_DIST_MASK_5);
Run Code Online (Sandbox Code Playgroud)

3.累积中心周围的一半距离

double halfWidth = 0.0;
int count = 0;
for(int a = 0; a < thinImg.cols; a++)
    for(int b = 0; b < thinImg.rows; b++)
        if(thinImg.ptr<uchar>(b, a)[0] > 0)
        {
            halfWidth += distImg.ptr<float>(b, a)[0];
            count ++;
        }
Run Code Online (Sandbox Code Playgroud)

4.最后,获得实际宽度

width = halfWidth / count * 2;
Run Code Online (Sandbox Code Playgroud)

结果,不太好,在1-2像素左右是错误的.在更大的图像上,结果更糟,有什么建议吗?

小智 10

您可以调整条形码阅读器算法,这是更快的方法.

图片

扫描水平和垂直线条.让X表示与黑线的水平交点的长度,Y表示垂直交点的长度(如果有一些噪音,可以计算几个X和Y的中值).

X * Y / 2 = area
X²+Y² = hypotenuse²
hypotenuse * width / 2 = area
Run Code Online (Sandbox Code Playgroud)

所以:width = 2*area/hypotenuse

编辑:您也可以使用PCA轻松找到角度.


Har*_*ris 5

您需要为图像中的每个轮廓找到RotatedRect,这是OpenCV教程的操作方法。然后,只需从旋转的矩形中获取“大小”的值,即可获得轮廓的高度和宽度,高度和宽度可能会因轮廓的不同对齐方式而互换。在上图中,高度变为宽度,宽度变为高度。

Contour-->RotatedRect 
              | 
              '-->  Size2f size
                            |
                            |-->width
                            '-->height
Run Code Online (Sandbox Code Playgroud)

找到轮廓后就做

RotatedRect minRect = minAreaRect( Mat(contours[i]) );
Size2f contourSize=minRect.size  //  width and height of the rectangle
Run Code Online (Sandbox Code Playgroud)

每个轮廓的旋转矩形

在此处输入图片说明

这是C ++代码

Mat src=imread("line.png",1);
Mat thr,gray;
blur(src,src,Size(3,3));
cvtColor(src,gray,CV_BGR2GRAY);
Canny(gray,thr,50, 190, 3, false );
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( thr.clone(),contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point(0,0));
vector<RotatedRect> minRect( contours.size() );

for( int i = 0; i < contours.size(); i++ )
  minRect[i] = minAreaRect( Mat(contours[i]) );

for( int i = 0; i< contours.size(); i++ )
 {
    cout<<"  Size ="<<minRect[i].size<<endl; //The width may interchange according to contour alignment
    Size2f s=minRect[i].size;
    // rotated rectangle
    Point2f rect_points[4]; minRect[i].points( rect_points );
    for( int j = 0; j < 4; j++ )
      line( src, rect_points[j], rect_points[(j+1)%4], Scalar(0,0,255), 1, 8 );
}

imshow("src",src);
imshow("Canny",thr);
Run Code Online (Sandbox Code Playgroud)


Hug*_*une 3

一个快速而简单的建议:

  • 计算黑色像素的总数。

  • 检测每条线的长度。(也许使用 CVHoughLinesP,或者只是每条细线周围的边界框的对角线)

  • 将黑色像素的数量除以所有线条长度的总和,即可得出平均线条宽度。

我不确定这是否比您现有的方法更准确。每条线的不规则末端部分可能会使其脱落。

您可以尝试一件事来提高这种情况的准确性:

  • 测量线的平均角度
  • 旋转图像,使线条水平对齐
  • 裁剪形状的矩形子部分,因此所有线条都具有相同的长度
    (您可以通过形态学闭运算获得形状的轮廓,然后找到完全包含在形状内的矩形。确保矩形的水平边缘是行与行之间)
  • 然后再次计算黑色像素的数量(将图像旋转产生的灰色像素计算为整个像素的x%)
  • 除以(矩形宽度 * 矩形中的行数)