c++ - 使用 OpenCV 检测绘制在背景图像上的矩形

标签 c++ opencv image-processing

我正在尝试检测绘制在图像上的一些矩形(白色)。 (比如使用绘画或其他图像编辑工具)。 由于我是图像处理的初学者,我通过网络和 OpenCV 示例程序搜索来完成这项工作,但无法让它完美地工作。我正在使用 OpenCV C++ 库。

我试过的算法

cv::Mat src = cv::imread(argv[1]);
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
Rect boundRect = boundingRect( Mat(approx) );
rectangle( dst, boundRect.tl(), boundRect.br(), Scalar(255,255,255), 1, 8, 0 );}

只检测到一个矩形。你能指导我或一些相同的链接吗?

输入图片:

输出图像:

最佳答案

我无法编译你的代码示例,因为 boundRect 是在 if block 中声明的,但矩形绘图(试图访问 boundRect)在 if block 之外,所以我调整了你的代码:

int main(int argc, char* argv[])
{
    cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
    cv::Mat dst = src.clone();

    cv::Mat gray;
    cv::cvtColor(src, gray, CV_BGR2GRAY);

    // ADDED: missing declaration of mu and sigma
    cv::Scalar mu, sigma;
    meanStdDev(gray, mu, sigma);
    cv::Mat bw;
    cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);

    // ADDED: displaying the canny output
    cv::imshow("canny", bw);


    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    std::vector<cv::Point> approx;
    for (int i = 0; i < contours.size(); i++){
        cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
        if (approx.size() >= 4 && approx.size() <= 6)
        {
            // ADDED: brackets around both lines belonging to the if-block
            cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
            cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 3, 8, 0);
        }

    }

    // ADDED: displaying input and results
    cv::imshow("input", src);
    cv::imshow("dst", dst);
    cv::imwrite("C:/StackOverflow/Output/rectangles.png", dst);
    cv::waitKey(0);
    return 0;
}

使用你的输入图像我得到了这个输出:

enter image description here

这可能不是您所期望的。查看精明的输出图像(查看中间结果以进行可视化调试总是好的!),图像中的结构太多,轮廓将覆盖所有这些,因此有些结构将近似为多项式有 4 到 6 个元素。

相反,您必须变得更聪明一些。您可以尝试使用 cv::HoughLinesP 提取直线并连接这些线。或者您可以尝试先通过查找白色区域来分割图像(如果您的矩形始终为白色)。

int main(int argc, char* argv[])
{
    cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
    cv::Mat dst = src.clone();

    cv::Mat gray;
    cv::cvtColor(src, gray, CV_BGR2GRAY);

    cv::Mat mask;
    // find "white" pixel
    cv::inRange(src, cv::Scalar(230, 230, 230), cv::Scalar(255, 255, 255), mask);
    cv::imshow("mask", mask);

    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    std::vector<cv::Point> approx;
    for (int i = 0; i < contours.size(); i++){
        cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
        if (approx.size() >= 4 && approx.size() <= 6)
        {
            cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
            cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 1, 8, 0);
        }
    }


    cv::imshow("input", src);
    cv::imshow("dst", dst);
    cv::imwrite("C:/StackOverflow/Output/rectangles2.png", dst);
    cv::waitKey(0);
    return 0;
}

给出这个结果:

enter image description here

如您所见,白色附近还有其他明亮区域。多项式近似也没有多大帮助。

关于c++ - 使用 OpenCV 检测绘制在背景图像上的矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35334088/

相关文章:

c# - 改进算法使其更快 - 从文件中扫描图像

c++ - 如何使用可变数量的参数为函数起别名?

c++ - 检查是否设置了 k 中 1 到 n 之间的所有位

opencv - 人脸检测:一次只显示一张脸

opencv - 无法安装虚拟python环境

python - 如何使用 Python OpenCV 确定内部轮廓和外部轮廓?

c++ - 将 cv::Mat 传递给 labview

c++ - 计算刚体惯性张量世界坐标

C++ OpenCV SVM 预测不起作用

c - 我如何在互联网上找到 pbmpak.c 文件?