3

我正在尝试检测简单的黑白绘图图像文件(jpg 或 bmp 格式)中的线、圆和弧

我之前发布了一个类似的问题,其中建议使用 OpenCV 库。这是一个很好的图书馆,但是,它对我的​​目的来说不够准确。更具体地说,Canny 检测算法不知何故不适用于我的图像。

因此,我正在尝试使用 QImage 自己实现该算法。我已经成功地实现了直线。Qt C++ 中的代码如下。这是一个非常混乱的代码,但我只是提供它供参考。

该算法非常简单:
1. 我从左上角逐行扫描图像。
2. 每当遇到黑色像素时,我会向其右下角扫描,检查它是否是线段的角点。

for ( int i = 0; i < myImage.height(); i++ ) {

        for ( int j = 0; j < myImage.width(); j++ ) {
            if ( qGray( myImage.pixel( j, i ) ) == 0 ) {

                myImage.setPixel( j, i, value );
                bool horiLineDrawn = false;
                int xRight = j+1, xLeft = j-1;
                int y = i+1;
                while ( xRight < myImage.width() && qGray( myImage.pixel( xRight, i ) ) == 0 ) {
                    myImage.setPixel( xRight, i, value );
                    xRight++;
                }
                while ( y < myImage.height() && xLeft >= 0 &&
                        qGray( myImage.pixel( xLeft, y ) ) == 0 ) {
                    if ( xLeft - 1 >= 0 &&
                         qGray( myImage.pixel( xLeft - 1, y ) ) == 0 ) {
                        while ( xLeft >= 0 &&
                                qGray( myImage.pixel( xLeft, y ) ) == 0 ) {
                            myImage.setPixel( xLeft, y, value );
                            xLeft--;
                        }
                        y++;
                    } else if ( y+1 < myImage.height() &&
                                qGray( myImage.pixel( xLeft, y + 1 ) ) == 0 ) {
                        while ( y < myImage.height() &&
                                qGray( myImage.pixel( xLeft, y ) ) == 0 ) {
                            myImage.setPixel( xLeft, y, value );
                            y++;
                        }
                        xLeft--;
                    } else {
                        xLeft--;
                        y++;
                    }
                }
                y--;
                xLeft++;
                if ( y > i && ( y - i > MIN_PIXELS_LINE ||
                                xRight-1 - xLeft > MIN_PIXELS_LINE )
                     ) {
                    drawFile.Line( fileName2, xRight-1, myImage.height() - i, xLeft,
                                   myImage.height() - y, 0 );
                    horiLineDrawn = true;
                }

                y = i + 1;
                while ( y < myImage.height() && xRight < myImage.width() &&
                        qGray( myImage.pixel( xRight, y ) ) == 0 ) {


                    if ( xRight + 1 < myImage.width() &&
                         qGray( myImage.pixel( xRight + 1, y ) ) == 0 ) {
                        while ( xRight < myImage.width() &&
                                qGray( myImage.pixel( xRight, y ) ) == 0 ) {
                            myImage.setPixel( xRight, y, value );
                            xRight++;
                        }
                        y++;
                    } else if ( y+1 < myImage.height() &&
                                qGray( myImage.pixel( xRight, y + 1 ) ) == 0 ) {
                        while ( y < myImage.height() &&
                                qGray( myImage.pixel( xRight, y ) ) == 0 ) {
                            myImage.setPixel( xRight, y, value );
                            y++;
                        }
                        xRight++;
                    } else {
                        xRight++;
                        y++;
                    }
                }
                y--;
                xRight--;
                if ( y - i > MIN_PIXELS_LINE || xRight - j > MIN_PIXELS_LINE
                     && !horiLineDrawn) {
                    drawFile.Line( fileName2, j, myImage.height() - i, xRight,
                                   myImage.height() - y, 0 );
                    horiLineDrawn = true;
                }

                y = i + 1;
                while ( y < myImage.height() && qGray( myImage.pixel( j, y ) ) == 0 ) {
                    myImage.setPixel( j, y, value );
                    y++;
                }
                xLeft = j - 1;
                xRight = j + 1;
                if ( xLeft >= 0 && y < myImage.height() &&
                     qGray( myImage.pixel( xLeft, y ) ) == 0 ) {
                    while ( xLeft >= 0 && y < myImage.height() &&
                            qGray( myImage.pixel( xLeft, y ) ) == 0 ) {
                        while ( y < myImage.height() &&
                                qGray( myImage.pixel( xLeft, y ) ) == 0 ) {
                            myImage.setPixel( xLeft, y, value );
                            y++;
                        }
                        xLeft--;
                    }
                    xLeft++;
                    y--;
                    if ( y - i > MIN_PIXELS_LINE || j - xLeft > MIN_PIXELS_LINE )
                        drawFile.Line( fileName2, j, myImage.height() - i, xLeft,
                                       myImage.height() - y, 0 );
                } else if ( xRight < myImage.width() && y < myImage.height() &&
                            qGray( myImage.pixel( xRight, y ) ) == 0 ) {
                       while ( xRight < myImage.width() && y < myImage.height() &&
                               qGray( myImage.pixel( xRight, y ) ) == 0 ) {
                           while ( y < myImage.height() &&
                                   qGray( myImage.pixel( xRight, y ) ) == 0 ) {
                               myImage.setPixel( xRight, y, value );
                               y++;
                           }
                           xRight++;
                       }
                       xRight--;
                       y--;
                       if ( y - i > MIN_PIXELS_LINE || xRight - j > MIN_PIXELS_LINE )
                           drawFile.Line( fileName2, j, myImage.height() - i, xRight,
                                          myImage.height() - y, 0 );
                } else {
                    y--;
                    if ( y - i > MIN_PIXELS_LINE )
                        drawFile.Line( fileName2, j, myImage.height() - i, j,
                                       myImage.height() - y, 0 );
                }


            }
        }
    }

这工作正常。例如:

输入图像:
在此处输入图像描述

输出图像:
在此处输入图像描述

谁能建议我如何为圆和弧实现类似或更好的算法?效率不是问题,因为我的图像尺寸最大为 1000 x 1000 像素。但是,准确性至关重要。

编辑:在我目前的直线实现中可能存在很多错误,比如我没有测试过相交线等。但我认为我将能够管理这些并发症。

4

1 回答 1

3

出于好奇,您所有的图像都是带有细线的二进制文件吗?这些是扫描的手绘图还是像素艺术?我问是因为你会遇到使用 JPEG 压缩的麻烦,它在线条艺术上是出了名的糟糕。您应该确保始终对线条图使用无损压缩。

如果图像中存在噪声和其他伪影,则任何边缘检测器都不太可能完美。如果我正在解决这个问题,我将专注于预处理数据以使其具有更强的线条,从而使线条检测过程更容易。这可以通过预先对图像进行阈值处理,可能进行一些形态学清理,甚至锐化图像来完成。

此外,如果您的图像已经是二进制的(或者可以使用简单的阈值进行二进制),那么 Canny 边缘检测(或实际上任何灰度边缘检测器)可能不是最好的工具。您最好将图像二进制化并使用findContours之类的东西来识别边缘。

如果您正在寻找与识别形状的霍夫变换略有不同的东西,您可以尝试使用模型拟合算法,例如 RANSAC。

于 2013-11-12T03:48:16.170 回答