【问题标题】:Remove Boxes/rectangles from image从图像中删除框/矩形
【发布时间】:2017-07-02 00:17:10
【问题描述】:

我有以下图片。 this image

我想删除数字周围的橙色框/矩形,并保持原始图像干净,没有任何橙色网格/矩形。

以下是我当前的代码,但它不会删除它。

Mat mask = new Mat();
Mat src = new Mat();
src = Imgcodecs.imread("enveloppe.jpg",Imgcodecs.CV_LOAD_IMAGE_COLOR);
Imgproc.cvtColor(src, hsvMat, Imgproc.COLOR_BGR2HSV);

Scalar lowerThreshold = new Scalar(0, 50, 50);
Scalar upperThreshold = new Scalar(25, 255, 255);
Mat mask = new Mat();
Core.inRange(hsvMat, lowerThreshold, upperThreshold, mask);
//src.setTo(new scalar(255,255,255),mask);

what to do next ?

如何从原始图像中删除橙色框/矩形?

更新: 有关信息,掩码包含我要删除的所有框/矩形。我不知道如何使用此蒙版从源(src)图像中删除框/矩形,就好像它们不存在一样。

【问题讨论】:

  • 1) 在你的面具上使用findContours 来获得橙色物体的轮廓。 2)找到每个轮廓的boundingRect。 3) 最终根据面积/纵横比/大小丢弃轮廓 4) 对于每个矩形,在新的黑色初始化蒙版上绘制一个填充的白色矩形 5) 使用 setTo 和新蒙版,将蒙版下的所有像素设置为一种颜色您的选择
  • 我已经尝试过这种方法。用另一种颜色绘制检测到的轮廓并不能解决问题,它只是一种更改框/矩形颜色的方法。就我而言,我想从原始图像中删除框/矩形,就好像它们不存在一样。
  • 如果将它们的颜色更改为背景颜色会怎样?另见“inpaint”;)
  • 我以这种方式使用了 inpaint Photo.inpaint(src, mask, src, 3,Photo.INPAINT_TELEA); // 它不会删除框/矩形
  • 请贴出你使用的代码、掩码、得到的结果和想要的结果。否则很难遵循,并帮助你

标签: opencv image-processing computer-vision


【解决方案1】:

这就是我为解决问题所做的。我用 C++ 解决了这个问题,我使用了 OpenCV。

第 1 部分:查找候选框

首先,我想隔离特定于红色通道的信号。我将图像分成三个通道。然后我从蓝色通道中减去红色通道,从绿色通道中减去红色通道。之后,我将之前的两个减法结果相减。最终的减法结果如下图所示。

using namespace cv;
using namespace std;

Mat src_rgb = imread("image.jpg");

std::vector<Mat> channels;
split(src_rgb, channels);

Mat diff_rb, diff_rg;
subtract(channels[2], channels[0], diff_rb);
subtract(channels[2], channels[1], diff_rg);

Mat diff;
subtract(diff_rb, diff_rg, diff);

我的下一个目标是将获得的图像的各个部分分成单独的“组”。为此,我使用高斯滤波器稍微平滑了图像。然后我应用一个阈值来获得二值图像;最后我在该图像中寻找外部轮廓。

GaussianBlur(diff, diff, cv::Size(11, 11), 2.0, 2.0);
threshold(diff, diff, 5, 255, THRESH_BINARY);

vector<vector<Point>> contours;
findContours(diff, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

Click to see subtraction result, Gaussian blurred image, thresholded image and detected contours.

第 2 部分:检查候选框

之后,我必须估计每个轮廓的内部是否包含数字或其他内容。我做了一个假设,数字总是用黑色墨水打印,并且它们会有锋利的边缘。因此,我拍摄了一张蓝色通道图像,并应用了一点高斯平滑,并将其与拉普拉斯算子进行卷积。

Mat blurred_ch2;
GaussianBlur(channels[2], blurred_ch2, cv::Size(7, 7), 1, 1);

Mat laplace_result;
Laplacian(blurred_ch2, laplace_result, -1, 1);

然后我拍摄了生成的图像,并分别对每个轮廓应用了以下程序。我计算了轮廓内部像素值的标准偏差。在数字周围的轮廓内标准偏差很高;它在围绕狗头的两个轮廓和印章顶部的字母内很低。

这就是我可以应用标准偏差阈值的原因。标准偏差约为。包含数字的轮廓要大两倍,所以这是一种只选择包含数字的轮廓的简单方法。然后我画了轮廓内部蒙版。我使用侵蚀和减法来获得“盒子边缘蒙版”。

最后一步相当简单。我计算了图像每个通道上框附近的平均像素值的估计值。然后我将“box edge mask”下的所有像素值更改为每个通道上的那些值。在对每个框轮廓重复该过程后,我将所有三个通道合并为一个。

Mat mask(src_rgb.size(), CV_8UC1);
for (int i = 0; i < contours.size(); ++i)
{
    mask.setTo(0);
    drawContours(mask, contours, i, cv::Scalar(200), -1);

    Scalar mean, stdev;
    meanStdDev(laplace_result, mean, stdev, mask);

    if (stdev.val[0] < 10.0) continue;

    Mat eroded;
    erode(mask, eroded, cv::Mat(), cv::Point(-1, -1), 6);
    subtract(mask, eroded, mask);

    for (int c = 0; c < src_rgb.channels(); ++c)
    {
        erode(mask, eroded, cv::Mat());
        subtract(mask, eroded, eroded);

        Scalar mean, stdev;
        meanStdDev(channels[c], mean, stdev, eroded);
        channels[c].setTo(mean, mask);
    }
}

Mat final_result;
merge(channels, final_result);
imshow("Final Result", final_result);

Click to see red channel of the image, the result of convolution with Laplacian operator, drawn mask of the box edges and the final result.

请注意

这段代码远非最佳,尤其是最后一个循环做了很多不必要的工作。但我认为在这种情况下,可读性更重要(而且问题的作者并没有要求优化解决方案)。

寻求更通用的解决方案

在我发布最初的回复后,问题的作者指出,数字可以是任何颜色,并且它们的边缘不一定是锐利的。这意味着上述过程可能由于各种原因而失败。 I altered the input image so that it contains different kinds of numbers (click to see the image),你可以在这个输入上运行我的算法并分析出了什么问题。

在我看来,需要其中一种方法(或者可能两者兼而有之)以获得更“通用”的解决方案:

  • 只关注矩形的形状和颜色(确认候选框确实是橙色框,无论里面是什么,都将其移除)
  • 只关注数字(在每个候选框内部运行适当的数字检测算法;如果它包含单个数字,则移除该框)

我将给出第一种方法的一个简单示例。如果您可以假设橙色框大小始终相同,只需在算法的最后一个循环中检查框大小而不是信号的标准差即可:

Rect rect = boundingRect(contours[i]);
float area = rect.area();
if (area < 1000 || area > 1200) continue;

警告:矩形的实际面积约为 600Px^2,但我考虑到了高斯模糊,这会导致轮廓扩大。另请注意,如果您使用这种方法,则不再需要对蓝色通道图像执行模糊或拉普拉斯操作。

您还可以为该条件添加其他简单的约束;宽度和高度之间的比例是我想到的第一个。几何属性也是一个不错的选择(直角、直边、凸度......)。

【讨论】:

  • Nejc 感谢您的出色工作。这正是我想做的。你能分享你的代码吗?
  • Nejc :您说“我假设数字将始终用黑色墨水打印并且它们将具有锋利的边缘”:在我的情况下,数字可能是手写数字并且可以是任何颜色。如果需要此信息,仅供参考
  • @ctbcorp 我现在编辑了帖子并添加了代码。整个算法都包含在内,但我将其分为几个部分,以便文本很好地遵循代码。晚上晚些时候我也会回复你的第二条评论(我可能只是编辑原始帖子并添加其他内容)。
  • @ctbcorp 现在我还在我的答案中添加了一个新部分,作为对您第二条评论的回复。
  • @ctbcorp 就我个人而言,我很欣赏“谢谢”的评论,我很高兴能提供帮助,但我想提醒您有关此类 cmets 的社区规则:stackoverflow.com/help/someone-answers跨度>
猜你喜欢
  • 2019-08-11
  • 2015-12-16
  • 2014-04-22
  • 2023-02-24
  • 1970-01-01
  • 2018-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多