gpt4 book ai didi

opencv - 从图像中删除框/矩形

转载 作者:行者123 更新时间:2023-12-02 16:49:28 29 4
gpt4 key购买 nike

我有以下图像。
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)图像中删除框/矩形,就像它们不存在一样。

最佳答案

这就是我解决问题的方法。我用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部分:检查框候选

之后,我必须估算每个轮廓的内部是否包含数字或其他内容。我假设数字将始终用黑色墨水打印,并且边缘会很锋利。因此,我拍摄了一个蓝色通道图像,并仅应用了一点高斯平滑并将其与Laplacian算子进行卷积。
Mat blurred_ch2;
GaussianBlur(channels[2], blurred_ch2, cv::Size(7, 7), 1, 1);

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

然后,我拍摄了生成的图像,并对每个轮廓分别应用了以下步骤。我计算了轮廓内部的像素值的标准偏差。包围数字的轮廓内部的标准偏差很高;围绕着狗的头部和邮票顶部的字母的两个轮廓线较低。

这就是为什么我可以应用标准偏差阈值的原因。标准偏差约为包含数字的轮廓要大两倍,因此这是仅选择包含数字的轮廓的简便方法。然后我画了轮廓的内部面具。我使用腐 eclipse 和减法来获得“盒子边缘蒙版”。

最后一步相当容易。我计算了图像每个通道上框附近的平均像素值的估计值。然后,将“框边缘遮罩”下的所有像素值更改为每个通道上的那些值。在对每个框轮廓重复该过程之后,我将所有三个通道合并为一个。
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;

    Look, it works!

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

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

    关于opencv - 从图像中删除框/矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42213769/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com